From: Francois Pichet <pichet2000@gmail.com> Date: Sun, 21 Nov 2010 06:08:52 +0000 (+0000) Subject: Major anonymous union/struct redesign. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=87c2e121cf0522fc266efe2922b58091cd2e0182;p=clang Major anonymous union/struct redesign. A new AST node is introduced: def IndirectField : DDecl<Value>; IndirectFields are injected into the anonymous's parent scope and chain back to the original field. Name lookup for anonymous entities now result in an IndirectFieldDecl instead of a FieldDecl. There is no functionality change, the code generated should be the same. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119919 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 1c6a97282b..a5e29c6146 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1794,6 +1794,45 @@ public: friend class StmtIteratorBase; }; +/// IndirectFieldDecl - An instance of this class is created to represent a +/// field injected from an anonymous union/struct into the parent scope. +/// IndirectFieldDecl are always implicit. +class IndirectFieldDecl : public ValueDecl { + NamedDecl **Chaining; + int ChainingSize; + + IndirectFieldDecl(DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + NamedDecl **CH, int CHS) + : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {} + +public: + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, NamedDecl **CH, int CHS); + + typedef NamedDecl * const *chain_iterator; + chain_iterator chain_begin() const { return Chaining; } + chain_iterator chain_end() const { return Chaining+ChainingSize; } + + int getChainingSize() const { return ChainingSize; } + + FieldDecl *getAnonField() const { + assert(ChainingSize >= 2); + return cast<FieldDecl>(Chaining[ChainingSize - 1]); + } + + VarDecl *getVarDecl() const { + assert(ChainingSize >= 2); + return dyn_cast<VarDecl>(*chain_begin()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const IndirectFieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K == IndirectField; } + friend class ASTDeclReader; +}; /// TypeDecl - Represents a declaration of a type. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index f343881685..f05ab931ec 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1381,6 +1381,8 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, { TRY_TO(TraverseNestedNameSpecifier(D->getTargetNestedNameSpecifier())); }) +DEF_TRAVERSE_DECL(IndirectFieldDecl, {}) + template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) { TRY_TO(TraverseNestedNameSpecifier(D->getQualifier())); diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index e2f93e02c5..3e60d864a9 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -29,6 +29,7 @@ def Named : Decl<1>; def Value : DDecl<Named, 1>; def EnumConstant : DDecl<Value>; def UnresolvedUsingValue : DDecl<Value>; + def IndirectField : DDecl<Value>; def Declarator : DDecl<Value, 1>; def Function : DDecl<Declarator>, DeclContext; def CXXMethod : DDecl<Function>; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 9c36ce0347..4769722159 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -139,7 +139,8 @@ namespace clang { class VarDecl; class VisibilityAttr; class VisibleDeclConsumer; - + class IndirectFieldDecl; + namespace sema { class AccessedEntity; class BlockScopeInfo; @@ -1739,11 +1740,9 @@ public: ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = 0); - VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, - llvm::SmallVectorImpl<FieldDecl *> &Path); ExprResult BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - FieldDecl *Field, + IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr = 0, SourceLocation OpLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index dd3f344cc2..38d4b9fd25 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -269,6 +269,7 @@ namespace clang { Decl *VisitVarDecl(VarDecl *D); Decl *VisitAccessSpecDecl(AccessSpecDecl *D); Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); Decl *VisitStaticAssertDecl(StaticAssertDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitEnumConstantDecl(EnumConstantDecl *D); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 646d09006a..eb6c973d5e 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -718,7 +718,9 @@ namespace clang { /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, /// \brief A record containing CXXBaseSpecifiers. - DECL_CXX_BASE_SPECIFIERS + DECL_CXX_BASE_SPECIFIERS, + /// \brief A IndirectFieldDecl record. + DECL_INDIRECTFIELD, }; /// \brief Record codes for each kind of statement or expression. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 7b16809a1f..980e93c04d 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -98,6 +98,7 @@ namespace { Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); Decl *VisitCXXConversionDecl(CXXConversionDecl *D); Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); Decl *VisitObjCIvarDecl(ObjCIvarDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); @@ -2020,6 +2021,42 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { return ToField; } +Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + NamedDecl **NamedChain = + new (Importer.getToContext())NamedDecl*[D->getChainingSize()]; + + unsigned i = 0; + for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), + PE = D->chain_end(); PI != PE; ++PI) { + Decl* D = Importer.Import(*PI); + if (!D) + return 0; + NamedChain[i++] = cast<NamedDecl>(D); + } + + IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create( + Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), T, + NamedChain, D->getChainingSize()); + ToIndirectField->setAccess(D->getAccess()); + ToIndirectField->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToIndirectField); + LexicalDC->addDecl(ToIndirectField); + return ToIndirectField; +} + Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Import the major distinguishing characteristics of an ivar. DeclContext *DC, *LexicalDC; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index c448116ed2..ef8f16861e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -768,7 +768,7 @@ bool NamedDecl::isCXXInstanceMember() const { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); - if (isa<FieldDecl>(D)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) return true; if (isa<CXXMethodDecl>(D)) return cast<CXXMethodDecl>(D)->isInstance(); @@ -2030,6 +2030,12 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, return new (C) EnumConstantDecl(CD, L, Id, T, E, V); } +IndirectFieldDecl *IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, NamedDecl **CH, int CHS) { + return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS); +} + SourceRange EnumConstantDecl::getSourceRange() const { SourceLocation End = getLocation(); if (Init) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 5ba6623b20..7d8a92530e 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -249,6 +249,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProperty: return IDNS_Ordinary; + case IndirectField: + return IDNS_Ordinary | IDNS_Member; + case ObjCCompatibleAlias: case ObjCInterface: return IDNS_Ordinary | IDNS_Type; @@ -524,8 +527,6 @@ bool DeclContext::isTransparentContext() const { return !cast<EnumDecl>(this)->isScoped(); else if (DeclKind == Decl::LinkageSpec) return true; - else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord) - return cast<RecordDecl>(this)->isAnonymousStructOrUnion(); return false; } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index ba5970038d..bf26bd1f93 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -333,6 +333,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { islvalue = NTTParm->getType()->isReferenceType(); else islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || (Ctx.getLangOptions().CPlusPlus && (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D))); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7c2a8fb105..2b970a34c4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1748,7 +1748,8 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, RecordDecl *AnonRecord, - AccessSpecifier AS) { + AccessSpecifier AS, + llvm::SmallVector<NamedDecl*, 2> &Chaining) { unsigned diagKind = AnonRecord->isUnion() ? diag::err_anonymous_union_member_redecl : diag::err_anonymous_struct_member_redecl; @@ -1771,20 +1772,37 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, // definition, the members of the anonymous union are // considered to have been defined in the scope in which the // anonymous union is declared. - Owner->makeDeclVisibleInContext(*F); - S->AddDecl(*F); - SemaRef.IdResolver.AddDecl(*F); + Chaining.push_back(*F); + assert(Chaining.size() >= 2); + NamedDecl **NamedChain = + new (SemaRef.Context)NamedDecl*[Chaining.size()]; + for (unsigned i = 0; i < Chaining.size(); i++) + NamedChain[i] = Chaining[i]; + + IndirectFieldDecl* IndirectField = + IndirectFieldDecl::Create(SemaRef.Context, Owner, F->getLocation(), + F->getIdentifier(), F->getType(), + NamedChain, Chaining.size()); + + IndirectField->setAccess(AS); + IndirectField->setImplicit(); + SemaRef.PushOnScopeChains(IndirectField, S); // That includes picking up the appropriate access specifier. if (AS != AS_none) (*F)->setAccess(AS); + + Chaining.pop_back(); } } else if (const RecordType *InnerRecordType = (*F)->getType()->getAs<RecordType>()) { RecordDecl *InnerRecord = InnerRecordType->getDecl(); + + Chaining.push_back(*F); if (InnerRecord->isAnonymousStructOrUnion()) Invalid = Invalid || InjectAnonymousStructOrUnionMembers(SemaRef, S, Owner, - InnerRecord, AS); + InnerRecord, AS, Chaining); + Chaining.pop_back(); } } @@ -1999,7 +2017,10 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. - if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS)) + llvm::SmallVector<NamedDecl*, 2> Chain; + Chain.push_back(Anon); + + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain)) Invalid = true; // Mark this as an anonymous struct/union type. Note that we do not diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2741c6de65..235b41e342 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1067,10 +1067,15 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, FieldDecl *Member = 0; DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (Result.first != Result.second) + if (Result.first != Result.second) { Member = dyn_cast<FieldDecl>(*Result.first); - - // FIXME: Handle members of an anonymous union. + + // Handle anonymous union case. + if (!Member) + if (IndirectFieldDecl* IndirectField + = dyn_cast<IndirectFieldDecl>(*Result.first)) + Member = IndirectField->getAnonField(); + } if (Member) return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc, @@ -2600,15 +2605,15 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // In addition, if class T has a user-declared constructor (12.1), every // non-static data member of class T shall have a name different from T. for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName()); - R.first != R.second; ++R.first) - if (FieldDecl *Field = dyn_cast<FieldDecl>(*R.first)) { - if (Record->hasUserDeclaredConstructor() || - !Field->getDeclContext()->Equals(Record)) { - Diag(Field->getLocation(), diag::err_member_name_of_class) - << Field->getDeclName(); + R.first != R.second; ++R.first) { + NamedDecl *D = *R.first; + if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) || + isa<IndirectFieldDecl>(D)) { + Diag(D->getLocation(), diag::err_member_name_of_class) + << D->getDeclName(); break; } - } + } } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index bc811d0e77..37561028c2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -795,59 +795,18 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, D, NameInfo, Ty, VK)); } -/// \brief Given a field that represents a member of an anonymous -/// struct/union, build the path from that field's context to the -/// actual member. -/// -/// Construct the sequence of field member references we'll have to -/// perform to get to the field in the anonymous union/struct. The -/// list of members is built from the field outward, so traverse it -/// backwards to go from an object in the current context to the field -/// we found. -/// -/// \returns The variable from which the field access should begin, -/// for an anonymous struct/union that is not a member of another -/// class. Otherwise, returns NULL. -VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, - llvm::SmallVectorImpl<FieldDecl *> &Path) { - assert(Field->getDeclContext()->isRecord() && - cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion() - && "Field must be stored inside an anonymous struct or union"); - - Path.push_back(Field); - VarDecl *BaseObject = 0; - DeclContext *Ctx = Field->getDeclContext(); - do { - RecordDecl *Record = cast<RecordDecl>(Ctx); - ValueDecl *AnonObject = Record->getAnonymousStructOrUnionObject(); - if (FieldDecl *AnonField = dyn_cast<FieldDecl>(AnonObject)) - Path.push_back(AnonField); - else { - BaseObject = cast<VarDecl>(AnonObject); - break; - } - Ctx = Ctx->getParent(); - } while (Ctx->isRecord() && - cast<RecordDecl>(Ctx)->isAnonymousStructOrUnion()); - - return BaseObject; -} - ExprResult Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - FieldDecl *Field, + IndirectFieldDecl *IndirectField, Expr *BaseObjectExpr, SourceLocation OpLoc) { - llvm::SmallVector<FieldDecl *, 4> AnonFields; - VarDecl *BaseObject = BuildAnonymousStructUnionMemberPath(Field, - AnonFields); - // Build the expression that refers to the base object, from // which we will build a sequence of member references to each // of the anonymous union objects and, eventually, the field we // found via name lookup. bool BaseObjectIsPointer = false; Qualifiers BaseQuals; + VarDecl *BaseObject = IndirectField->getVarDecl(); if (BaseObject) { // BaseObject is an anonymous struct/union variable (and is, // therefore, not part of another non-anonymous record). @@ -877,7 +836,8 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, if (!MD->isStatic()) { QualType AnonFieldType = Context.getTagDeclType( - cast<RecordDecl>(AnonFields.back()->getDeclContext())); + cast<RecordDecl>( + (*IndirectField->chain_begin())->getDeclContext())); QualType ThisType = Context.getTagDeclType(MD->getParent()); if ((Context.getCanonicalType(AnonFieldType) == Context.getCanonicalType(ThisType)) || @@ -890,24 +850,29 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, } } else { return ExprError(Diag(Loc,diag::err_invalid_member_use_in_static_method) - << Field->getDeclName()); + << IndirectField->getDeclName()); } BaseQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); } if (!BaseObjectExpr) return ExprError(Diag(Loc, diag::err_invalid_non_static_member_use) - << Field->getDeclName()); + << IndirectField->getDeclName()); } // Build the implicit member references to the field of the // anonymous struct/union. Expr *Result = BaseObjectExpr; Qualifiers ResultQuals = BaseQuals; - for (llvm::SmallVector<FieldDecl *, 4>::reverse_iterator - FI = AnonFields.rbegin(), FIEnd = AnonFields.rend(); - FI != FIEnd; ++FI) { - FieldDecl *Field = *FI; + + IndirectFieldDecl::chain_iterator FI = IndirectField->chain_begin(), + FEnd = IndirectField->chain_end(); + + // Skip the first VarDecl if present. + if (BaseObject) + FI++; + for (; FI != FEnd; FI++) { + FieldDecl *Field = cast<FieldDecl>(*FI); QualType MemberType = Field->getType(); Qualifiers MemberTypeQuals = Context.getCanonicalType(MemberType).getQualifiers(); @@ -930,8 +895,9 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MarkDeclarationReferenced(Loc, *FI); PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI); // FIXME: Might this end up being a qualified name? - Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, - OpLoc, MemberType, VK_LValue, + Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, + cast<FieldDecl>(*FI), OpLoc, + MemberType, VK_LValue, Field->isBitField() ? OK_BitField : OK_Ordinary); BaseObjectIsPointer = false; @@ -1048,10 +1014,6 @@ enum IMAKind { /// context is not an instance method. IMA_Unresolved_StaticContext, - /// The reference is to a member of an anonymous structure in a - /// non-class context. - IMA_AnonymousMember, - /// All possible referrents are instance members and the current /// context is not an instance method. IMA_Error_StaticContext, @@ -1084,16 +1046,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { NamedDecl *D = *I; + if (D->isCXXInstanceMember()) { CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); - - // If this is a member of an anonymous record, move out to the - // innermost non-anonymous struct or union. If there isn't one, - // that's a special case. - while (R->isAnonymousStructOrUnion()) { - R = dyn_cast<CXXRecordDecl>(R->getParent()); - if (!R) return IMA_AnonymousMember; - } Classes.insert(R->getCanonicalDecl()); } else @@ -1577,7 +1532,8 @@ ExprResult Sema::ActOnIdExpression(Scope *S, else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else - MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()); + MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl()) || + isa<IndirectFieldDecl>(R.getFoundDecl()); if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs); @@ -1598,11 +1554,6 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, case IMA_Instance: return BuildImplicitMemberExpr(SS, R, TemplateArgs, true); - case IMA_AnonymousMember: - assert(R.isSingleResult()); - return BuildAnonymousStructUnionMemberReference(R.getNameLoc(), - R.getAsSingle<FieldDecl>()); - case IMA_Mixed: case IMA_Mixed_Unrelated: case IMA_Unresolved: @@ -1959,9 +1910,9 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, // (C++ [class.union]). // FIXME: This needs to happen post-isImplicitMemberReference? // FIXME: template-ids inside anonymous structs? - if (FieldDecl *FD = R.getAsSingle<FieldDecl>()) - if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(Loc, FD); + if (IndirectFieldDecl *FD = R.getAsSingle<IndirectFieldDecl>()) + return BuildAnonymousStructUnionMemberReference(Loc, FD); + // If this is known to be an instance access, go ahead and build a // 'this' expression now. @@ -2153,6 +2104,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (VD->isInvalidDecl()) return ExprError(); + // Handle anonymous. + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(VD)) + return BuildAnonymousStructUnionMemberReference(Loc, FD); + ExprValueKind VK = getValueKindForDecl(Context, VD); // If the identifier reference is inside a block, and it refers to a value @@ -3308,12 +3263,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) { - // We may have found a field within an anonymous union or struct - // (C++ [class.union]). - if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion() && - !BaseType->getAs<RecordType>()->getDecl()->isAnonymousStructOrUnion()) - return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, - BaseExpr, OpLoc); // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note @@ -3356,6 +3305,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, MemberType, VK, OK)); } + if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) + // We may have found a field within an anonymous union or struct + // (C++ [class.union]). + return BuildAnonymousStructUnionMemberReference(MemberLoc, FD, + BaseExpr, OpLoc); + if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, @@ -7956,6 +7911,12 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); + IndirectFieldDecl *IndirectMemberDecl = 0; + if (!MemberDecl) { + if (IndirectMemberDecl = R.getAsSingle<IndirectFieldDecl>()) + MemberDecl = IndirectMemberDecl->getAnonField(); + } + if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, @@ -7974,12 +7935,8 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, } RecordDecl *Parent = MemberDecl->getParent(); - bool AnonStructUnion = Parent->isAnonymousStructOrUnion(); - if (AnonStructUnion) { - do { - Parent = cast<RecordDecl>(Parent->getParent()); - } while (Parent->isAnonymousStructOrUnion()); - } + if (IndirectMemberDecl) + Parent = cast<RecordDecl>(IndirectMemberDecl->getDeclContext()); // If the member was found in a base class, introduce OffsetOfNodes for // the base class indirections. @@ -7992,15 +7949,17 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, Comps.push_back(OffsetOfNode(B->Base)); } - if (AnonStructUnion) { - llvm::SmallVector<FieldDecl*, 4> Path; - BuildAnonymousStructUnionMemberPath(MemberDecl, Path); - unsigned n = Path.size(); - for (int j = n - 1; j > -1; --j) - Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd)); - } else { + if (IndirectMemberDecl) { + for (IndirectFieldDecl::chain_iterator FI = + IndirectMemberDecl->chain_begin(), + FEnd = IndirectMemberDecl->chain_end(); FI != FEnd; FI++) { + assert(isa<FieldDecl>(*FI)); + Comps.push_back(OffsetOfNode(OC.LocStart, + cast<FieldDecl>(*FI), OC.LocEnd)); + } + } else Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd)); - } + CurrentType = MemberDecl->getType().getNonReferenceType(); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 9458e3580c..1b47332c53 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1429,6 +1429,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, } else if (!KnownField) { // Determine whether we found a field at all. ReplacementField = dyn_cast<FieldDecl>(*Lookup.first); + + // Check if ReplacementField is an anonymous field. + if (!ReplacementField) + if (IndirectFieldDecl* IField = dyn_cast<IndirectFieldDecl>(*Lookup.first)) + ReplacementField = IField->getAnonField(); } if (!ReplacementField) { diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 436488ed26..fc298c10e4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -456,6 +456,29 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { return Field; } +Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + NamedDecl **NamedChain = + new (SemaRef.Context)NamedDecl*[D->getChainingSize()]; + + int i = 0; + for (IndirectFieldDecl::chain_iterator PI = + D->chain_begin(), PE = D->chain_end(); + PI != PE; ++PI) + NamedChain[i++] = (SemaRef.FindInstantiatedDecl(D->getLocation(), + *PI, TemplateArgs)); + + IndirectFieldDecl* IndirectField + = IndirectFieldDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), D->getType(), + NamedChain, D->getChainingSize()); + + + IndirectField->setImplicit(D->isImplicit()); + IndirectField->setAccess(D->getAccess()); + Owner->addDecl(IndirectField); + return IndirectField; +} + Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Handle friend type expressions by simply substituting template // parameters into the pattern type and checking the result. diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 9f5d0c11d1..b1e46a623e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -107,6 +107,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *FD); + void VisitIndirectFieldDecl(IndirectFieldDecl *FD); void VisitVarDecl(VarDecl *VD); void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); @@ -635,6 +636,17 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { } } +void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { + VisitValueDecl(FD); + + FD->ChainingSize = Record[Idx++]; + assert(FD->ChainingSize >= 2 && "Anonymous chaining must be >= 2"); + FD->Chaining = new (*Reader.getContext())NamedDecl*[FD->ChainingSize]; + + for (unsigned I = 0; I != FD->ChainingSize; ++I) + FD->Chaining[I] = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); +} + void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VisitDeclaratorDecl(VD); VisitRedeclarable(VD); @@ -1475,6 +1487,10 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0, false); break; + case DECL_INDIRECTFIELD: + D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), + 0, 0); + break; case DECL_VAR: D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, SC_None, SC_None); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index f7bb23764d..27adb26d71 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -72,6 +72,7 @@ namespace clang { void VisitCXXDestructorDecl(CXXDestructorDecl *D); void VisitCXXConversionDecl(CXXConversionDecl *D); void VisitFieldDecl(FieldDecl *D); + void VisitIndirectFieldDecl(IndirectFieldDecl *D); void VisitVarDecl(VarDecl *D); void VisitImplicitParamDecl(ImplicitParamDecl *D); void VisitParmVarDecl(ParmVarDecl *D); @@ -528,6 +529,17 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) { Code = serialization::DECL_FIELD; } +void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + VisitValueDecl(D); + Record.push_back(D->getChainingSize()); + + for (IndirectFieldDecl::chain_iterator + P = D->chain_begin(), + PEnd = D->chain_end(); P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + Code = serialization::DECL_INDIRECTFIELD; +} + void ASTDeclWriter::VisitVarDecl(VarDecl *D) { VisitDeclaratorDecl(D); VisitRedeclarable(D);