void ActOnPopScope(SourceLocation Loc, Scope *S);
void ActOnTranslationUnitScope(Scope *S);
- Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS);
- Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS,
+ Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
+ RecordDecl *&AnonRecord);
+ Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
MultiTemplateParamsArg TemplateParams,
- bool IsExplicitInstantiation = false);
+ bool IsExplicitInstantiation,
+ RecordDecl *&AnonRecord);
Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
AccessSpecifier AS,
ProhibitAttributes(Attrs);
DeclEnd = Tok.getLocation();
if (RequireSemi) ConsumeToken();
+ RecordDecl *AnonRecord = nullptr;
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
- DS);
+ DS, AnonRecord);
DS.complete(TheDecl);
+ if (AnonRecord) {
+ Decl* decls[] = {AnonRecord, TheDecl};
+ return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
+ }
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
// If there are no declarators, this is a free-standing declaration
// specifier. Let the actions module cope with it.
if (Tok.is(tok::semi)) {
+ RecordDecl *AnonRecord = nullptr;
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
- DS);
+ DS, AnonRecord);
+ assert(!AnonRecord && "Did not expect anonymous struct or union here");
DS.complete(TheDecl);
return;
}
if (DS.isFriendSpecified())
ProhibitAttributes(FnAttrs);
- Decl *TheDecl =
- Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
+ RecordDecl *AnonRecord = nullptr;
+ Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
+ getCurScope(), AS, DS, TemplateParams, false, AnonRecord);
DS.complete(TheDecl);
- return DeclGroupPtrTy::make(DeclGroupRef(TheDecl));
+ if (AnonRecord) {
+ Decl* decls[] = {AnonRecord, TheDecl};
+ return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
+ }
+ return Actions.ConvertDeclToDeclGroup(TheDecl);
}
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
if (Tok.is(tok::semi)) {
ProhibitAttributes(prefixAttrs);
DeclEnd = ConsumeToken();
+ RecordDecl *AnonRecord = nullptr;
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
getCurScope(), AS, DS,
TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
: MultiTemplateParamsArg(),
- TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation);
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation,
+ AnonRecord);
+ assert(!AnonRecord &&
+ "Anonymous unions/structs should not be valid with template");
DS.complete(Decl);
return Decl;
}
if (Tok.is(tok::semi)) {
ProhibitAttributes(attrs);
ConsumeToken();
- Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ RecordDecl *AnonRecord = nullptr;
+ Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
+ DS, AnonRecord);
DS.complete(TheDecl);
+ if (AnonRecord) {
+ Decl* decls[] = {AnonRecord, TheDecl};
+ return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
+ }
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
-Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS) {
- return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
+Decl *
+Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
+ RecordDecl *&AnonRecord) {
+ return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false,
+ AnonRecord);
}
// The MS ABI changed between VS2013 and VS2015 with regard to numbers used to
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
-Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams,
- bool IsExplicitInstantiation) {
+Decl *
+Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation,
+ RecordDecl *&AnonRecord) {
Decl *TagD = nullptr;
TagDecl *Tag = nullptr;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOpts().CPlusPlus ||
- Record->getDeclContext()->isRecord())
+ Record->getDeclContext()->isRecord()) {
+ // If CurContext is a DeclContext that can contain statements,
+ // RecursiveASTVisitor won't visit the decls that
+ // BuildAnonymousStructOrUnion() will put into CurContext.
+ // Also store them here so that they can be part of the
+ // DeclStmt that gets created in this case.
+ // FIXME: Also return the IndirectFieldDecls created by
+ // BuildAnonymousStructOr union, for the same reason?
+ if (CurContext->isFunctionOrMethod())
+ AnonRecord = Record;
return BuildAnonymousStructOrUnion(S, DS, AS, Record,
Context.getPrintingPolicy());
+ }
DeclaresAnything = false;
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
bool InstantiatingVarTemplate) {
- // If this is the variable for an anonymous struct or union,
- // instantiate the anonymous struct/union type first.
- if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
- if (RecordTy->getDecl()->isAnonymousStructOrUnion())
- if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return nullptr;
-
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
TemplateArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted) {
- // If this is the variable for an anonymous struct or union,
- // instantiate the anonymous struct/union type first.
- if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
- if (RecordTy->getDecl()->isAnonymousStructOrUnion())
- if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return nullptr;
-
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
declRefExpr(to(decl(hasAncestor(decl()))))));
}
+TEST(HasAncestor, AnonymousUnionMemberExpr) {
+ EXPECT_TRUE(matches("int F() {\n"
+ " union { int i; };\n"
+ " return i;\n"
+ "}\n",
+ memberExpr(member(hasAncestor(decl())))));
+ EXPECT_TRUE(matches("void f() {\n"
+ " struct {\n"
+ " struct { int a; int b; };\n"
+ " } s;\n"
+ " s.a = 4;\n"
+ "}\n",
+ memberExpr(member(hasAncestor(decl())))));
+ EXPECT_TRUE(matches("void f() {\n"
+ " struct {\n"
+ " struct { int a; int b; };\n"
+ " } s;\n"
+ " s.a = 4;\n"
+ "}\n",
+ declRefExpr(to(decl(hasAncestor(decl()))))));
+}
+
TEST(HasParent, MatchesAllParents) {
EXPECT_TRUE(matches(
"template <typename T> struct C { static void f() { 42; } };"