On Tue, May 20, 2014 at 03:12:08PM -0700, Nico Weber wrote: > On Tue, May 20, 2014 at 2:53 PM, Peter Collingbourne <[email protected]>wrote: > > > On Tue, May 20, 2014 at 09:21:38PM +0000, Nico Weber wrote: > > > Is there a list of extensions you want to support? > > > > I want to implement the unnamed substructure extension (section 3.3 here: > > http://plan9.bell-labs.com/sys/doc/compiler.html). As far as I know, that > > is the only other extension required for the Go standard library. > > > > Hm, that doesn't sound so bad. > > Do you happen to have a complete diff for all the changes you want to make > that you could put somewhere? It sounds like it would be relatively small.
I have unnamed substructures implemented (attached). No docs or tests yet, though it does allow me to compile the Go standard library. (It is in fact a relatively large diff, but most of it is boilerplate changes.) > What are the odds of the go standard library depending on more plan9 stuff > over time? I don't know. But I hope it wouldn't go much beyond what GCC already implements (namely, unnamed substructures). > > > Could the go standard library not use plan9 extensions, if it's > > interested > > > in being compiled with more than 1 compiler? > > > > I don't know how receptive the Go folks would be to that. > > > Have you asked? I haven't. I should probably do that. Thanks, -- Peter
commit 206d6ba77c7a264337d493c828e685b439d3640a Author: Peter Collingbourne <[email protected]> Date: Tue May 20 13:34:14 2014 -0700 Implement a Plan 9 extension that permits unnamed substructures. This extension is similar to an already implemented Microsoft C extension, but it also allows implicit conversions from structures to unnamed substructutres, and references to unnamed substructures by typedef name. The extension is documented in section 3.3 of: http://plan9.bell-labs.com/sys/doc/compiler.html diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f654791..6c79d90 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2149,7 +2149,8 @@ public: class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { // FIXME: This can be packed into the bitfields in Decl. bool Mutable : 1; - mutable unsigned CachedFieldIndex : 31; + bool IsUnnamedSubstructure : 1; + mutable unsigned CachedFieldIndex : 30; /// \brief An InClassInitStyle value, and either a bit width expression (if /// the InClassInitStyle value is ICIS_NoInit), or a pointer to the in-class @@ -2164,12 +2165,12 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> { llvm::PointerIntPair<Expr *, 2, unsigned> InitializerOrBitWidth; protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, - InClassInitStyle InitStyle) - : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), - Mutable(Mutable), CachedFieldIndex(0), - InitializerOrBitWidth(BW, InitStyle) { + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool IsUnnamedSubstructure, InClassInitStyle InitStyle) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Mutable(Mutable), + IsUnnamedSubstructure(IsUnnamedSubstructure), CachedFieldIndex(0), + InitializerOrBitWidth(BW, InitStyle) { assert((!BW || InitStyle == ICIS_NoInit) && "got initializer for bitfield"); } @@ -2178,6 +2179,7 @@ public: SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool IsUnnamedSubstructure, InClassInitStyle InitStyle); static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2189,6 +2191,14 @@ public: /// isMutable - Determines whether this field is mutable (C++ only). bool isMutable() const { return Mutable; } + /// \brief Returns whether this field holds an unnamed substructure (Plan 9 + /// extension). + /// + /// This cannot be determined purely by checking whether the FieldDecl is + /// named because an unnamed substructure member declared with a typedef type + /// is represented using a named FieldDecl. + bool isUnnamedSubstructure() const { return IsUnnamedSubstructure; } + /// isBitfield - Determines whether this field is a bitfield. bool isBitField() const { return getInClassInitStyle() == ICIS_NoInit && diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 4ca02d2..6de6c9e 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -1399,7 +1399,8 @@ private: QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, - /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), + /*Mutable=*/false, /*IsUnnamedSubstructure=*/false, + /*HasInit=*/ICIS_NoInit), NextIvar(nullptr), DeclAccess(ac), Synthesized(synthesized) {} public: @@ -1455,7 +1456,8 @@ class ObjCAtDefsFieldDecl : public FieldDecl { QualType T, Expr *BW) : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, /*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ? - BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {} + BW, /*Mutable=*/false, /*IsUnnamedSubstructure=*/false, + /*HasInit=*/ICIS_NoInit) {} public: static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h index aba88d6..6a4b2d1 100644 --- a/include/clang/AST/OperationKinds.h +++ b/include/clang/AST/OperationKinds.h @@ -298,7 +298,15 @@ enum CastKind { CK_ZeroToOCLEvent, // Convert a pointer to a different address space. - CK_AddressSpaceConversion + CK_AddressSpaceConversion, + + /// \brief Plan 9 extension: implicit conversion of a structure to an unnamed + /// substructure. + CK_UnnamedSubstructure, + + /// \brief Plan 9 extension: implicit conversion of a pointer to a structure + /// to a pointer to an unnamed substructure. + CK_UnnamedSubstructurePointer, }; static const CastKind CK_Invalid = static_cast<CastKind>(-1); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f4a1a35..576308a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1741,8 +1741,7 @@ public: RecordDecl *Record, const PrintingPolicy &Policy); - Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, - RecordDecl *Record); + Decl *BuildAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, @@ -7563,6 +7562,9 @@ public: void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr); + bool PromoteToUnnamedSubstructure(QualType LHSType, QualType RHSType, + ExprResult &RHS, bool IsPointer); + /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fe735dc..b4d6ab7 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4581,6 +4581,7 @@ QualType ASTContext::getCFConstantStringType() const { FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); @@ -4630,7 +4631,8 @@ QualType ASTContext::getBlockDescriptorType() const { FieldDecl *Field = FieldDecl::Create( *this, RD, SourceLocation(), SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr, - /*BitWidth=*/nullptr, /*Mutable=*/false, ICIS_NoInit); + /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); RD->addDecl(Field); } @@ -4669,8 +4671,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { FieldDecl *Field = FieldDecl::Create( *this, RD, SourceLocation(), SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/nullptr, - /*BitWidth=*/nullptr, - /*Mutable=*/false, ICIS_NoInit); + /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); RD->addDecl(Field); } @@ -5831,6 +5833,7 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) { FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListTagDecl->addDecl(Field); @@ -5883,6 +5886,7 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) { FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListTagDecl->addDecl(Field); @@ -5943,6 +5947,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) { FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListTagDecl->addDecl(Field); @@ -6003,6 +6008,7 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListDecl->addDecl(Field); @@ -6052,6 +6058,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { FieldTypes[i], /*TInfo=*/nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); VaListTagDecl->addDecl(Field); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index b180326..8f954d8 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2893,6 +2893,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, BitWidth, D->isMutable(), + D->isUnnamedSubstructure(), D->getInClassInitStyle()); ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index fc15bde..8134737 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3146,15 +3146,16 @@ FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool IsUnnamedSubstructure, InClassInitStyle InitStyle) { return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, - BW, Mutable, InitStyle); + BW, Mutable, IsUnnamedSubstructure, InitStyle); } FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(), SourceLocation(), nullptr, QualType(), nullptr, - nullptr, false, ICIS_NoInit); + nullptr, false, false, ICIS_NoInit); } bool FieldDecl::isAnonymousStructOrUnion() const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index aea2f43..c600a7c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1496,6 +1496,8 @@ bool CastExpr::CastConsistency() const { case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_ZeroToOCLEvent: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; @@ -1632,6 +1634,10 @@ const char *CastExpr::getCastKindName() const { return "ZeroToOCLEvent"; case CK_AddressSpaceConversion: return "AddressSpaceConversion"; + case CK_UnnamedSubstructure: + return "UnnamedSubstructure"; + case CK_UnnamedSubstructurePointer: + return "UnnamedSubstructurePointer"; } llvm_unreachable("Unhandled cast kind!"); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c1468cb..40cb7cf 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -7134,6 +7134,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ZeroToOCLEvent: case CK_NonAtomicToAtomic: case CK_AddressSpaceConversion: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -7607,6 +7609,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ZeroToOCLEvent: case CK_NonAtomicToAtomic: case CK_AddressSpaceConversion: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index ebd160b..e5428f1 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -2801,6 +2801,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_ARCExtendBlockObject: case CK_CopyAndAutoreleaseBlockObject: case CK_AddressSpaceConversion: + case CK_UnnamedSubstructurePointer: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); case CK_Dependent: @@ -2827,6 +2828,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_BlockPointerToObjCPointerCast: case CK_NoOp: case CK_LValueToRValue: + case CK_UnnamedSubstructure: return EmitLValue(E->getSubExpr()); case CK_UncheckedDerivedToBase: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 6c50521..ab2f060 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -662,6 +662,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_NoOp: case CK_UserDefinedConversion: case CK_ConstructorConversion: + case CK_UnnamedSubstructure: assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(), E->getType()) && "Implicit cast types must be compatible"); @@ -714,6 +715,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: case CK_AddressSpaceConversion: + case CK_UnnamedSubstructurePointer: llvm_unreachable("cast kind invalid for aggregate types"); } } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 1f84c86..d797968 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -476,6 +476,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: case CK_AddressSpaceConversion: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 4e61592..1ef06e8 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -701,6 +701,8 @@ public: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_ZeroToOCLEvent: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: return 0; } llvm_unreachable("Invalid CastKind"); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 522a0e2..a64e181 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1313,6 +1313,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_NonAtomicToAtomic: case CK_NoOp: case CK_UserDefinedConversion: + case CK_UnnamedSubstructure: return Visit(const_cast<Expr*>(E)); case CK_BaseToDerived: { @@ -1371,6 +1372,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return CGF.Builder.CreatePointerCast(V, ConvertType(CE->getType())); } case CK_FunctionToPointerDecay: + case CK_UnnamedSubstructurePointer: return EmitLValue(E).getAddress(); case CK_NullToPointer: diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 575884b..a4e0b70 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -5057,9 +5057,10 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) SourceLocation(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCIdType(), 0, 0, false, ICIS_NoInit)); + Ctx.getObjCIdType(), 0, 0, false, false, + ICIS_NoInit)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCClassType(), 0, 0, false, + Ctx.getObjCClassType(), 0, 0, false, false, ICIS_NoInit)); RD->completeDefinition(); @@ -5438,9 +5439,10 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul SourceLocation(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.VoidPtrTy, 0, 0, false, ICIS_NoInit)); + Ctx.VoidPtrTy, 0, 0, false, false, + ICIS_NoInit)); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, - Ctx.getObjCSelType(), 0, 0, false, + Ctx.getObjCSelType(), 0, 0, false, false, ICIS_NoInit)); RD->completeDefinition(); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index af257c5..a3c4ad2 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2527,6 +2527,7 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); @@ -2602,6 +2603,7 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); Field->setAccess(AS_public); D->addDecl(Field); diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp index 666844c..bc4d5e7 100644 --- a/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1076,6 +1076,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: return false; } } diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp index 3cacbdd..7e3dbc6 100644 --- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -899,6 +899,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { &Context->Idents.get(D->getNameAsString()), IvarT, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -2776,7 +2777,9 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { &Context->Idents.get("arr"), Context->getPointerType(Context->VoidPtrTy), nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); + /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, + ICIS_NoInit); MemberExpr *ArrayLiteralME = new (Context) MemberExpr(NSArrayCallExpr, false, ARRFD, SourceLocation(), @@ -2913,7 +2916,9 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral &Context->Idents.get("arr"), Context->getPointerType(Context->VoidPtrTy), nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); + /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, + ICIS_NoInit); MemberExpr *DictLiteralValueME = new (Context) MemberExpr(NSValueCallExpr, false, ARRFD, SourceLocation(), @@ -3049,6 +3054,7 @@ QualType RewriteModernObjC::getSuperStructType() { FieldTypes[i], nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit)); } @@ -3082,6 +3088,7 @@ QualType RewriteModernObjC::getConstantStringStructType() { FieldTypes[i], nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit)); } @@ -3243,7 +3250,9 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla &Context->Idents.get("s"), returnType, nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); + /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(STCE, false, FieldD, SourceLocation(), FieldD->getType(), VK_LValue, OK_Ordinary); @@ -3897,7 +3906,7 @@ QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType( &Context->Idents.get(Ivar->getName()), Ivar->getType(), nullptr, /*Expr *BW */Ivar->getBitWidth(), - false, ICIS_NoInit)); + false, false, ICIS_NoInit)); } RD->completeDefinition(); return Context->getTagDeclType(RD); @@ -4751,6 +4760,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -4799,6 +4809,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get("__forwarding"), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), @@ -4810,6 +4821,7 @@ Stmt *RewriteModernObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get(Name), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); @@ -7709,7 +7721,9 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { &Context->Idents.get(D->getNameAsString()), IvarT, nullptr, /*BitWidth=*/nullptr, - /*Mutable=*/true, ICIS_NoInit); + /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); @@ -7738,7 +7752,9 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { &Context->Idents.get(D->getNameAsString()), D->getType(), nullptr, /*BitWidth=*/D->getBitWidth(), - /*Mutable=*/true, ICIS_NoInit); + /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, + ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(), FD->getType(), VK_LValue, OK_Ordinary); diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp index beadb93..2d9ced9 100644 --- a/lib/Rewrite/Frontend/RewriteObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -2550,6 +2550,7 @@ QualType RewriteObjC::getSuperStructType() { FieldTypes[i], nullptr, /*BitWidth=*/nullptr, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit)); } @@ -2583,6 +2584,7 @@ QualType RewriteObjC::getConstantStringStructType() { FieldTypes[i], nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit)); } @@ -3834,6 +3836,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -3882,6 +3885,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get("__forwarding"), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); MemberExpr *ME = new (Context) MemberExpr(DeclRefExp, isArrow, FD, SourceLocation(), @@ -3893,6 +3897,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(DeclRefExpr *DeclRefExp) { &Context->Idents.get(Name), Context->VoidPtrTy, nullptr, /*BitWidth=*/nullptr, /*Mutable=*/true, + /*IsUnnamedSubstructure=*/false, ICIS_NoInit); ME = new (Context) MemberExpr(ME, true, FD, SourceLocation(), DeclRefExp->getType(), VK_LValue, OK_Ordinary); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index b0d1023..c571ee0 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -316,6 +316,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, case CK_LValueToRValue: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: + case CK_UnnamedSubstructurePointer: case CK_ToVoid: break; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b65a04a..99e8f94 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3269,9 +3269,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, } } - // Check for Microsoft C extension: anonymous struct member. - if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus && - CurContext->isRecord() && + // Check for Microsoft C extension: anonymous struct member, and the similar + // Plan 9 C extension: unnamed substructures/subunions. + if ((getLangOpts().MicrosoftExt || getLangOpts().Plan9Ext) && + !getLangOpts().CPlusPlus && CurContext->isRecord() && DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) { // Handle 2 kinds of anonymous struct: // struct STRUCT; @@ -3281,9 +3282,11 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if ((Record && Record->getDeclName() && !Record->isCompleteDefinition()) || (DS.getTypeSpecType() == DeclSpec::TST_typename && DS.getRepAsType().get()->isStructureType())) { - Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct) - << DS.getSourceRange(); - return BuildMicrosoftCAnonymousStruct(S, DS, Record); + if (getLangOpts().MicrosoftExt) { + Diag(DS.getLocStart(), diag::ext_ms_anonymous_struct) + << DS.getSourceRange(); + } + return BuildAnonymousStruct(S, DS, Record); } } @@ -3742,6 +3745,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Context.getTypeDeclType(Record), TInfo, /*BitWidth=*/0, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); if (getLangOpts().CPlusPlus) @@ -3807,9 +3811,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, return Anon; } -/// BuildMicrosoftCAnonymousStruct - Handle the declaration of an -/// Microsoft C anonymous structure. -/// Ref: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx +/// BuildAnonymousStruct - Handle the declaration of a +/// Microsoft or Plan 9 C anonymous structure. +/// Ref: +/// http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx +/// http://plan9.bell-labs.com/sys/doc/compiler.html +/// /// Example: /// /// struct A { int a; }; @@ -3820,32 +3827,56 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /// var.a = 3; /// } /// -Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, - RecordDecl *Record) { +Decl *Sema::BuildAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record) { + TypedefNameDecl *Typedef = 0; // If there is no Record, get the record via the typedef. - if (!Record) + if (!Record) { Record = DS.getRepAsType().get()->getAsStructureType()->getDecl(); + Typedef = cast<TypedefType>(DS.getRepAsType().get())->getDecl(); + } // Mock up a declarator. Declarator Dc(DS, Declarator::TypeNameContext); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); + IdentifierInfo *Name = 0; + + if (getLangOpts().Plan9Ext && Typedef) { + // http://plan9.bell-labs.com/sys/doc/compiler.html + // 3.3: "[...] the type name (it must be a typedef) of the unnamed structure + // can be used as an identifier." + if (CheckAnonMemberRedeclaration( + *this, S, CurContext, Typedef->getDeclName(), + Typedef->getLocation(), diag::err_anonymous_struct_member_redecl)) { + // The Plan 9 compiler accepts such redeclarations, but reject member + // references as being ambiguous. + return 0; + } + + Name = Typedef->getDeclName().getAsIdentifierInfo(); + } + // Create a declaration for this anonymous struct. NamedDecl* Anon = FieldDecl::Create(Context, - cast<RecordDecl>(CurContext), - DS.getLocStart(), - DS.getLocStart(), - /*IdentifierInfo=*/0, - Context.getTypeDeclType(Record), - TInfo, - /*BitWidth=*/0, /*Mutable=*/false, - /*InitStyle=*/ICIS_NoInit); + cast<RecordDecl>(CurContext), + DS.getLocStart(), + DS.getLocStart(), + /*IdentifierInfo=*/Name, + Context.getTypeDeclType(Record), + TInfo, + /*BitWidth=*/0, /*Mutable=*/false, + /*IsUnnamedSubstructure=*/true, + /*InitStyle=*/ICIS_NoInit); Anon->setImplicit(); // Add the anonymous struct object to the current context. - CurContext->addDecl(Anon); + if (Name) { + PushOnScopeChains(Anon, S); + } else { + CurContext->addDecl(Anon); + } // Inject the members of the anonymous struct into the current // context and into the identifier resolver chain for name lookup @@ -11706,7 +11737,9 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, checkDuplicateDefaultInit(*this, cast<CXXRecordDecl>(Record), Loc); FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, - BitWidth, Mutable, InitStyle); + BitWidth, Mutable, + /*IsUnnamedSubstructure=*/false, + InitStyle); if (InvalidDecl) NewFD->setInvalidDecl(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 33eea16..131f0e4 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6227,6 +6227,56 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, return CheckAssignmentConstraints(LHSType, RHSPtr, K); } +static void FindSubstructurePaths(std::vector<std::vector<FieldDecl *>> &Paths, + std::vector<FieldDecl *> &CurPath, + RecordDecl *RD, RecordDecl *Target) { + for (FieldDecl *FD : RD->fields()) { + if (FD->isUnnamedSubstructure()) { + CurPath.push_back(FD); + auto FieldRD = FD->getType()->getAs<RecordType>()->getDecl(); + if (FieldRD == Target) { + Paths.push_back(CurPath); + } else { + FindSubstructurePaths(Paths, CurPath, FieldRD, Target); + } + CurPath.pop_back(); + } + } +} + +/// Promotes RHS of type RHSType or pointer to RHSType to type LHSType by +/// following a chain of unnamed substructure references. +bool Sema::PromoteToUnnamedSubstructure(QualType LHSType, QualType RHSType, + ExprResult &RHS, bool IsPointer) { + auto LHSRType = LHSType->getAs<RecordType>(); + if (!LHSRType) + return false; + + auto RHSRType = RHSType->getAs<RecordType>(); + if (!RHSRType) + return false; + + std::vector<std::vector<FieldDecl *>> Paths; + std::vector<FieldDecl *> CurPath; + FindSubstructurePaths(Paths, CurPath, RHSRType->getDecl(), + LHSRType->getDecl()); + + if (Paths.size() == 1) { + bool IsArrow = IsPointer; + ExprValueKind VK = IsPointer ? VK_LValue : RHS.get()->getValueKind(); + + for (FieldDecl *FD : Paths[0]) { + RHS = new (Context) MemberExpr(RHS.get(), IsArrow, FD, SourceLocation(), + FD->getType(), VK, OK_Ordinary); + IsArrow = false; + } + + return true; + } + + return false; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -6336,9 +6386,24 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Conversions to normal pointers. - if (const PointerType *LHSPointer = dyn_cast<PointerType>(LHSType)) { + if (auto LHSPointer = dyn_cast<PointerType>(LHSType)) { // U* -> T* - if (isa<PointerType>(RHSType)) { + if (auto RHSPointer = dyn_cast<PointerType>(RHSType)) { + if (getLangOpts().Plan9Ext) { + // Implicit conversion from structure pointer to unnamed substructure + // pointer. + // http://plan9.bell-labs.com/sys/doc/compiler.html + // 3.3: "When an outer structure is used in a context that is only legal + // for an unnamed substructure, the compiler promotes the reference to + // the unnamed substructure. This is true for [...] references to + // pointers to structures." + if (PromoteToUnnamedSubstructure(LHSPointer->getPointeeType(), + RHSPointer->getPointeeType(), RHS, + /*IsPointer=*/true)) { + Kind = CK_UnnamedSubstructurePointer; + return Compatible; + } + } Kind = CK_BitCast; return checkPointerTypesForAssignment(*this, LHSType, RHSType); } @@ -6497,6 +6562,13 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, // struct A -> struct B if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) { + if (getLangOpts().Plan9Ext) { + if (PromoteToUnnamedSubstructure(LHSType, RHSType, RHS, + /*IsPointer=*/false)) { + Kind = CK_UnnamedSubstructure; + return Compatible; + } + } if (Context.typesAreCompatible(LHSType, RHSType)) { Kind = CK_NoOp; return Compatible; @@ -11693,7 +11765,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, FieldDecl *Field = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, CaptureType, S.Context.getTrivialTypeSourceInfo(CaptureType, Loc), - 0, false, ICIS_NoInit); + 0, false, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); @@ -11727,7 +11799,7 @@ static ExprResult addAsFieldToClosureType(Sema &S, FieldDecl *Field = FieldDecl::Create(S.Context, Lambda, Loc, Loc, 0, FieldType, S.Context.getTrivialTypeSourceInfo(FieldType, Loc), - 0, false, ICIS_NoInit); + 0, false, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); Lambda->addDecl(Field); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index bfb209a..879e626 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -781,7 +781,7 @@ static Expr *captureThis(ASTContext &Context, RecordDecl *RD, FieldDecl *Field = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy, Context.getTrivialTypeSourceInfo(ThisTy, Loc), - 0, false, ICIS_NoInit); + 0, false, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index e6c714e..da5f754 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -819,7 +819,7 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, FieldDecl *Sema::buildInitCaptureField(LambdaScopeInfo *LSI, VarDecl *Var) { FieldDecl *Field = FieldDecl::Create( Context, LSI->Lambda, Var->getLocation(), Var->getLocation(), - 0, Var->getType(), Var->getTypeSourceInfo(), 0, false, ICIS_NoInit); + 0, Var->getType(), Var->getTypeSourceInfo(), 0, false, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); LSI->Lambda->addDecl(Field); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index bb87632..e29b6b9 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -952,6 +952,7 @@ void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { VisitDeclaratorDecl(FD); FD->Mutable = Record[Idx++]; + FD->IsUnnamedSubstructure = Record[Idx++]; if (int BitWidthOrInitializer = Record[Idx++]) { FD->InitializerOrBitWidth.setInt(BitWidthOrInitializer - 1); FD->InitializerOrBitWidth.setPointer(Reader.ReadExpr(F)); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 8a463b5..28a99b3 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -663,6 +663,7 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->isMutable()); + Record.push_back(D->isUnnamedSubstructure()); if (D->InitializerOrBitWidth.getInt() != ICIS_NoInit || D->InitializerOrBitWidth.getPointer()) { Record.push_back(D->InitializerOrBitWidth.getInt() + 1); @@ -1481,6 +1482,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUnnamedSubstructure Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth // Type Source Info Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); @@ -1513,6 +1515,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo // FieldDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isMutable + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isUnnamedSubstructure Abv->Add(BitCodeAbbrevOp(0)); //getBitWidth // ObjC Ivar Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getAccessControl diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index b754ecb..df6d340 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -318,7 +318,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_ZeroToOCLEvent: - case CK_LValueBitCast: { + case CK_LValueBitCast: + case CK_UnnamedSubstructure: + case CK_UnnamedSubstructurePointer: { // Delegate to SValBuilder to process. SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy);
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
