Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 22ffb44

Browse files
committed
Include RecordDecls from anonymous unions in the AST.
For void f() { union { int i; }; } clang used to omit the RecordDecl from the anonymous union from the AST. That's because the code creating it only called PushOnScopeChains(), which adds it to the current DeclContext, which here is the function's DeclContext. But RecursiveASTVisitor doesn't descent into all decls in a FunctionDecl. Instead, for DeclContexts that contain statements, return the RecordDecl so that it can be included in the DeclStmt containing the VarDecl for the union. Interesting bits from the AST before this change: |-FunctionDecl | `-CompoundStmt | |-DeclStmt | | `-VarDecl 0x589cd60 <col:3> col:3 implicit used 'union (anonymous at test.cc:3:3)' callinit After this change: -FunctionDecl | `-CompoundStmt | |-DeclStmt | | |-CXXRecordDecl 0x4612e48 <col:3, col:18> col:3 union definition | | | |-FieldDecl 0x4612f70 <col:11, col:15> col:15 referenced i 'int' | | `-VarDecl 0x4613010 <col:3> col:3 implicit used 'union (anonymous at test.cc:3:3)' callinit This is now closer to how anonymous struct and unions are represented as members of structs. It also enabled deleting some one-off code in the template instantiation code. Finally, it fixes a crash with ASTMatchers, see the included test case (this fixes http://crbug.com/580749). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@259079 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent c9d11f9 commit 22ffb44

File tree

8 files changed

+77
-34
lines changed

8 files changed

+77
-34
lines changed

include/clang/Sema/Sema.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -1861,12 +1861,12 @@ class Sema {
18611861
void ActOnPopScope(SourceLocation Loc, Scope *S);
18621862
void ActOnTranslationUnitScope(Scope *S);
18631863

1864-
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
1865-
DeclSpec &DS);
1866-
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
1867-
DeclSpec &DS,
1864+
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
1865+
RecordDecl *&AnonRecord);
1866+
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
18681867
MultiTemplateParamsArg TemplateParams,
1869-
bool IsExplicitInstantiation = false);
1868+
bool IsExplicitInstantiation,
1869+
RecordDecl *&AnonRecord);
18701870

18711871
Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
18721872
AccessSpecifier AS,

lib/Parse/ParseDecl.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -1530,9 +1530,14 @@ Parser::ParseSimpleDeclaration(unsigned Context,
15301530
ProhibitAttributes(Attrs);
15311531
DeclEnd = Tok.getLocation();
15321532
if (RequireSemi) ConsumeToken();
1533+
RecordDecl *AnonRecord = nullptr;
15331534
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
1534-
DS);
1535+
DS, AnonRecord);
15351536
DS.complete(TheDecl);
1537+
if (AnonRecord) {
1538+
Decl* decls[] = {AnonRecord, TheDecl};
1539+
return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
1540+
}
15361541
return Actions.ConvertDeclToDeclGroup(TheDecl);
15371542
}
15381543

@@ -3520,8 +3525,10 @@ void Parser::ParseStructDeclaration(
35203525
// If there are no declarators, this is a free-standing declaration
35213526
// specifier. Let the actions module cope with it.
35223527
if (Tok.is(tok::semi)) {
3528+
RecordDecl *AnonRecord = nullptr;
35233529
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
3524-
DS);
3530+
DS, AnonRecord);
3531+
assert(!AnonRecord && "Did not expect anonymous struct or union here");
35253532
DS.complete(TheDecl);
35263533
return;
35273534
}

lib/Parse/ParseDeclCXX.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -2400,10 +2400,15 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
24002400
if (DS.isFriendSpecified())
24012401
ProhibitAttributes(FnAttrs);
24022402

2403-
Decl *TheDecl =
2404-
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
2403+
RecordDecl *AnonRecord = nullptr;
2404+
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(
2405+
getCurScope(), AS, DS, TemplateParams, false, AnonRecord);
24052406
DS.complete(TheDecl);
2406-
return DeclGroupPtrTy::make(DeclGroupRef(TheDecl));
2407+
if (AnonRecord) {
2408+
Decl* decls[] = {AnonRecord, TheDecl};
2409+
return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
2410+
}
2411+
return Actions.ConvertDeclToDeclGroup(TheDecl);
24072412
}
24082413

24092414
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);

lib/Parse/ParseTemplate.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,15 @@ Parser::ParseSingleDeclarationAfterTemplate(
209209
if (Tok.is(tok::semi)) {
210210
ProhibitAttributes(prefixAttrs);
211211
DeclEnd = ConsumeToken();
212+
RecordDecl *AnonRecord = nullptr;
212213
Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
213214
getCurScope(), AS, DS,
214215
TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
215216
: MultiTemplateParamsArg(),
216-
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation);
217+
TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation,
218+
AnonRecord);
219+
assert(!AnonRecord &&
220+
"Anonymous unions/structs should not be valid with template");
217221
DS.complete(Decl);
218222
return Decl;
219223
}

lib/Parse/Parser.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -883,8 +883,14 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
883883
if (Tok.is(tok::semi)) {
884884
ProhibitAttributes(attrs);
885885
ConsumeToken();
886-
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
886+
RecordDecl *AnonRecord = nullptr;
887+
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
888+
DS, AnonRecord);
887889
DS.complete(TheDecl);
890+
if (AnonRecord) {
891+
Decl* decls[] = {AnonRecord, TheDecl};
892+
return Actions.BuildDeclaratorGroup(decls, /*TypeMayContainAuto=*/false);
893+
}
888894
return Actions.ConvertDeclToDeclGroup(TheDecl);
889895
}
890896

lib/Sema/SemaDecl.cpp

+21-8
Original file line numberDiff line numberDiff line change
@@ -3601,9 +3601,11 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
36013601

36023602
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
36033603
/// no declarator (e.g. "struct foo;") is parsed.
3604-
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
3605-
DeclSpec &DS) {
3606-
return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
3604+
Decl *
3605+
Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
3606+
RecordDecl *&AnonRecord) {
3607+
return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false,
3608+
AnonRecord);
36073609
}
36083610

36093611
// The MS ABI changed between VS2013 and VS2015 with regard to numbers used to
@@ -3709,10 +3711,11 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) {
37093711
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
37103712
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
37113713
/// parameters to cope with template friend declarations.
3712-
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
3713-
DeclSpec &DS,
3714-
MultiTemplateParamsArg TemplateParams,
3715-
bool IsExplicitInstantiation) {
3714+
Decl *
3715+
Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
3716+
MultiTemplateParamsArg TemplateParams,
3717+
bool IsExplicitInstantiation,
3718+
RecordDecl *&AnonRecord) {
37163719
Decl *TagD = nullptr;
37173720
TagDecl *Tag = nullptr;
37183721
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -3807,9 +3810,19 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
38073810
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
38083811
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
38093812
if (getLangOpts().CPlusPlus ||
3810-
Record->getDeclContext()->isRecord())
3813+
Record->getDeclContext()->isRecord()) {
3814+
// If CurContext is a DeclContext that can contain statements,
3815+
// RecursiveASTVisitor won't visit the decls that
3816+
// BuildAnonymousStructOrUnion() will put into CurContext.
3817+
// Also store them here so that they can be part of the
3818+
// DeclStmt that gets created in this case.
3819+
// FIXME: Also return the IndirectFieldDecls created by
3820+
// BuildAnonymousStructOr union, for the same reason?
3821+
if (CurContext->isFunctionOrMethod())
3822+
AnonRecord = Record;
38113823
return BuildAnonymousStructOrUnion(S, DS, AS, Record,
38123824
Context.getPrintingPolicy());
3825+
}
38133826

38143827
DeclaresAnything = false;
38153828
}

lib/Sema/SemaTemplateInstantiateDecl.cpp

-14
Original file line numberDiff line numberDiff line change
@@ -491,13 +491,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
491491
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
492492
bool InstantiatingVarTemplate) {
493493

494-
// If this is the variable for an anonymous struct or union,
495-
// instantiate the anonymous struct/union type first.
496-
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
497-
if (RecordTy->getDecl()->isAnonymousStructOrUnion())
498-
if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
499-
return nullptr;
500-
501494
// Do substitution on the type of the declaration
502495
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
503496
TemplateArgs,
@@ -2673,13 +2666,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
26732666
const TemplateArgumentListInfo &TemplateArgsInfo,
26742667
ArrayRef<TemplateArgument> Converted) {
26752668

2676-
// If this is the variable for an anonymous struct or union,
2677-
// instantiate the anonymous struct/union type first.
2678-
if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
2679-
if (RecordTy->getDecl()->isAnonymousStructOrUnion())
2680-
if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
2681-
return nullptr;
2682-
26832669
// Do substitution on the type of the declaration
26842670
TypeSourceInfo *DI =
26852671
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,

unittests/ASTMatchers/ASTMatchersTest.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -4240,6 +4240,28 @@ TEST(HasAncestor, ImplicitArrayCopyCtorDeclRefExpr) {
42404240
declRefExpr(to(decl(hasAncestor(decl()))))));
42414241
}
42424242

4243+
TEST(HasAncestor, AnonymousUnionMemberExpr) {
4244+
EXPECT_TRUE(matches("int F() {\n"
4245+
" union { int i; };\n"
4246+
" return i;\n"
4247+
"}\n",
4248+
memberExpr(member(hasAncestor(decl())))));
4249+
EXPECT_TRUE(matches("void f() {\n"
4250+
" struct {\n"
4251+
" struct { int a; int b; };\n"
4252+
" } s;\n"
4253+
" s.a = 4;\n"
4254+
"}\n",
4255+
memberExpr(member(hasAncestor(decl())))));
4256+
EXPECT_TRUE(matches("void f() {\n"
4257+
" struct {\n"
4258+
" struct { int a; int b; };\n"
4259+
" } s;\n"
4260+
" s.a = 4;\n"
4261+
"}\n",
4262+
declRefExpr(to(decl(hasAncestor(decl()))))));
4263+
}
4264+
42434265
TEST(HasParent, MatchesAllParents) {
42444266
EXPECT_TRUE(matches(
42454267
"template <typename T> struct C { static void f() { 42; } };"

0 commit comments

Comments
 (0)