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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 7c2a8fb..2b970a3 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1748,7 +1748,8 @@
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 @@
// 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 @@
// 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 2741c6d..235b41e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1067,10 +1067,15 @@
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 @@
// 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 bc811d0..3756102 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -795,59 +795,18 @@
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 @@
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 @@
}
} 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 @@
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 @@
/// 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 @@
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 @@
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 @@
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 @@
// (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 @@
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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 9458e35..1b47332 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1429,6 +1429,11 @@
} 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 436488e..fc298c1 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -456,6 +456,29 @@
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.