diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c55c41f1ebe2..0b270fe28369 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1861,12 +1861,12 @@ public: 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, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7b7adac2b752..49b593155b19 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1530,9 +1530,14 @@ Parser::ParseSimpleDeclaration(unsigned Context, 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); } @@ -3520,8 +3525,10 @@ void Parser::ParseStructDeclaration( // 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; } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index bcef9595cf18..814234d96da8 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2400,10 +2400,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, 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); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 098ac6836fd7..fffc40ee4e1f 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -209,11 +209,15 @@ Parser::ParseSingleDeclarationAfterTemplate( 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; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 5eb83837bc35..e33586c57cc7 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -883,8 +883,14 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs, 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); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f64970473ff3..cb79948341f0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3601,9 +3601,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// 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 @@ -3709,10 +3711,11 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { /// 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 || @@ -3807,9 +3810,19 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, 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; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7a452af77839..9403dd9fbaa7 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -491,13 +491,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { 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()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -2673,13 +2666,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( const TemplateArgumentListInfo &TemplateArgsInfo, ArrayRef 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()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 67d3de9f819c..7fd933718faf 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -4240,6 +4240,28 @@ TEST(HasAncestor, ImplicitArrayCopyCtorDeclRefExpr) { 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 struct C { static void f() { 42; } };"