Skip to content

Commit d9ba224

Browse files
committed
[modules] Suport for merging a parsed enum definition into an existing imported but not visible definition.
llvm-svn: 236690
1 parent 69a4779 commit d9ba224

File tree

7 files changed

+93
-25
lines changed

7 files changed

+93
-25
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,10 @@ class Sema {
12791279
bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
12801280
TypeDiagnoser &Diagnoser);
12811281
public:
1282+
/// \brief Make a merged definition of an existing hidden definition \p ND
1283+
/// visible at the specified location.
1284+
void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc);
1285+
12821286
/// Determine if \p D has a visible definition. If not, suggest a declaration
12831287
/// that should be made visible to expose the definition.
12841288
bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested);
@@ -1724,6 +1728,12 @@ class Sema {
17241728
TUK_Friend // Friend declaration: 'friend struct foo;'
17251729
};
17261730

1731+
struct SkipBodyInfo {
1732+
SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
1733+
bool ShouldSkip;
1734+
NamedDecl *Previous;
1735+
};
1736+
17271737
Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
17281738
SourceLocation KWLoc, CXXScopeSpec &SS,
17291739
IdentifierInfo *Name, SourceLocation NameLoc,
@@ -1733,7 +1743,7 @@ class Sema {
17331743
bool &OwnedDecl, bool &IsDependent,
17341744
SourceLocation ScopedEnumKWLoc,
17351745
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
1736-
bool IsTypeSpecifier, bool *SkipBody = nullptr);
1746+
bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
17371747

17381748
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
17391749
unsigned TagSpec, SourceLocation TagLoc,
@@ -1844,6 +1854,11 @@ class Sema {
18441854
bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
18451855
QualType EnumUnderlyingTy, const EnumDecl *Prev);
18461856

1857+
/// Determine whether the body of an anonymous enumeration should be skipped.
1858+
/// \param II The name of the first enumerator.
1859+
SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
1860+
SourceLocation IILoc);
1861+
18471862
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
18481863
SourceLocation IdLoc, IdentifierInfo *Id,
18491864
AttributeList *Attrs,
@@ -5382,7 +5397,7 @@ class Sema {
53825397
SourceLocation FriendLoc,
53835398
unsigned NumOuterTemplateParamLists,
53845399
TemplateParameterList **OuterTemplateParamLists,
5385-
bool *SkipBody = nullptr);
5400+
SkipBodyInfo *SkipBody = nullptr);
53865401

53875402
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
53885403
TemplateArgumentListInfo &Out);

clang/lib/Parse/ParseDecl.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3893,6 +3893,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
38933893

38943894
handleDeclspecAlignBeforeClassKey(attrs, DS, TUK);
38953895

3896+
Sema::SkipBodyInfo SkipBody;
3897+
if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) &&
3898+
NextToken().is(tok::identifier))
3899+
SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(),
3900+
NextToken().getIdentifierInfo(),
3901+
NextToken().getLocation());
3902+
38963903
bool Owned = false;
38973904
bool IsDependent = false;
38983905
const char *PrevSpec = nullptr;
@@ -3902,7 +3909,22 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
39023909
AS, DS.getModulePrivateSpecLoc(), TParams,
39033910
Owned, IsDependent, ScopedEnumKWLoc,
39043911
IsScopedUsingClassTag, BaseType,
3905-
DSC == DSC_type_specifier);
3912+
DSC == DSC_type_specifier, &SkipBody);
3913+
3914+
if (SkipBody.ShouldSkip) {
3915+
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
3916+
3917+
BalancedDelimiterTracker T(*this, tok::l_brace);
3918+
T.consumeOpen();
3919+
T.skipToEnd();
3920+
3921+
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
3922+
NameLoc.isValid() ? NameLoc : StartLoc,
3923+
PrevSpec, DiagID, TagDecl, Owned,
3924+
Actions.getASTContext().getPrintingPolicy()))
3925+
Diag(StartLoc, DiagID) << PrevSpec;
3926+
return;
3927+
}
39063928

39073929
if (IsDependent) {
39083930
// This enum has a dependent nested-name-specifier. Handle it as a

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
15531553
TypeResult TypeResult = true; // invalid
15541554

15551555
bool Owned = false;
1556-
bool SkipBody = false;
1556+
Sema::SkipBodyInfo SkipBody;
15571557
if (TemplateId) {
15581558
// Explicit specialization, class template partial specialization,
15591559
// or explicit instantiation.
@@ -1718,7 +1718,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
17181718
assert(Tok.is(tok::l_brace) ||
17191719
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
17201720
isCXX11FinalKeyword());
1721-
if (SkipBody)
1721+
if (SkipBody.ShouldSkip)
17221722
SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
17231723
TagOrTempResult.get());
17241724
else if (getLangOpts().CPlusPlus)

clang/lib/Sema/SemaDecl.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "clang/AST/ASTConsumer.h"
1717
#include "clang/AST/ASTContext.h"
1818
#include "clang/AST/ASTLambda.h"
19-
#include "clang/AST/ASTMutationListener.h"
2019
#include "clang/AST/CXXInheritance.h"
2120
#include "clang/AST/CharUnits.h"
2221
#include "clang/AST/CommentDiagnostic.h"
@@ -1974,9 +1973,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
19741973
New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
19751974

19761975
// Make the old tag definition visible.
1977-
if (auto *Listener = getASTMutationListener())
1978-
Listener->RedefinedHiddenDefinition(Hidden, NewTag->getLocation());
1979-
Hidden->setHidden(false);
1976+
makeMergedDefinitionVisible(Hidden, NewTag->getLocation());
19801977
}
19811978
}
19821979

@@ -11311,8 +11308,8 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S,
1131111308
/// \param IsTypeSpecifier \c true if this is a type-specifier (or
1131211309
/// trailing-type-specifier) other than one in an alias-declaration.
1131311310
///
11314-
/// \param SkipBody If non-null, will be set to true if the caller should skip
11315-
/// the definition of this tag, and treat it as if it were a declaration.
11311+
/// \param SkipBody If non-null, will be set to indicate if the caller should
11312+
/// skip the definition of this tag and treat it as if it were a declaration.
1131611313
Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1131711314
SourceLocation KWLoc, CXXScopeSpec &SS,
1131811315
IdentifierInfo *Name, SourceLocation NameLoc,
@@ -11323,7 +11320,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1132311320
SourceLocation ScopedEnumKWLoc,
1132411321
bool ScopedEnumUsesClassTag,
1132511322
TypeResult UnderlyingType,
11326-
bool IsTypeSpecifier, bool *SkipBody) {
11323+
bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
1132711324
// If this is not a definition, it must have a name.
1132811325
IdentifierInfo *OrigName = Name;
1132911326
assert((Name != nullptr || TUK == TUK_Definition) &&
@@ -11633,6 +11630,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1163311630
}
1163411631
}
1163511632

11633+
// If we have a known previous declaration to use, then use it.
11634+
if (Previous.empty() && SkipBody && SkipBody->Previous)
11635+
Previous.addDecl(SkipBody->Previous);
11636+
1163611637
if (!Previous.empty()) {
1163711638
NamedDecl *PrevDecl = Previous.getFoundDecl();
1163811639
NamedDecl *DirectPrevDecl =
@@ -11774,10 +11775,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
1177411775
// assume that this definition is identical to the hidden one
1177511776
// we already have. Make the existing definition visible and
1177611777
// use it in place of this one.
11777-
*SkipBody = true;
11778-
if (auto *Listener = getASTMutationListener())
11779-
Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
11780-
Hidden->setHidden(false);
11778+
SkipBody->ShouldSkip = true;
11779+
makeMergedDefinitionVisible(Hidden, KWLoc);
1178111780
return Def;
1178211781
} else if (!IsExplicitSpecializationAfterInstantiation) {
1178311782
// A redeclaration in function prototype scope in C isn't
@@ -13465,6 +13464,29 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
1346513464
Val, EnumVal);
1346613465
}
1346713466

13467+
Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
13468+
SourceLocation IILoc) {
13469+
if (!getLangOpts().Modules || !getLangOpts().CPlusPlus)
13470+
return SkipBodyInfo();
13471+
13472+
// We have an anonymous enum definition. Look up the first enumerator to
13473+
// determine if we should merge the definition with an existing one and
13474+
// skip the body.
13475+
NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName,
13476+
ForRedeclaration);
13477+
auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl);
13478+
NamedDecl *Hidden;
13479+
if (PrevECD &&
13480+
!hasVisibleDefinition(cast<NamedDecl>(PrevECD->getDeclContext()),
13481+
&Hidden)) {
13482+
SkipBodyInfo Skip;
13483+
Skip.ShouldSkip = true;
13484+
Skip.Previous = Hidden;
13485+
return Skip;
13486+
}
13487+
13488+
return SkipBodyInfo();
13489+
}
1346813490

1346913491
Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
1347013492
SourceLocation IdLoc, IdentifierInfo *Id,

clang/lib/Sema/SemaLookup.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414
#include "clang/Sema/Lookup.h"
1515
#include "clang/AST/ASTContext.h"
16+
#include "clang/AST/ASTMutationListener.h"
1617
#include "clang/AST/CXXInheritance.h"
1718
#include "clang/AST/Decl.h"
1819
#include "clang/AST/DeclCXX.h"
@@ -1169,6 +1170,12 @@ static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) {
11691170
return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom();
11701171
}
11711172

1173+
void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
1174+
if (auto *Listener = getASTMutationListener())
1175+
Listener->RedefinedHiddenDefinition(ND, Loc);
1176+
ND->setHidden(false);
1177+
}
1178+
11721179
/// \brief Find the module in which the given declaration was defined.
11731180
static Module *getDefiningModule(Decl *Entity) {
11741181
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Entity)) {

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "TreeTransform.h"
1313
#include "clang/AST/ASTConsumer.h"
1414
#include "clang/AST/ASTContext.h"
15-
#include "clang/AST/ASTMutationListener.h"
1615
#include "clang/AST/DeclFriend.h"
1716
#include "clang/AST/DeclTemplate.h"
1817
#include "clang/AST/Expr.h"
@@ -838,7 +837,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
838837
SourceLocation FriendLoc,
839838
unsigned NumOuterTemplateParamLists,
840839
TemplateParameterList** OuterTemplateParamLists,
841-
bool *SkipBody) {
840+
SkipBodyInfo *SkipBody) {
842841
assert(TemplateParams && TemplateParams->size() > 0 &&
843842
"No template parameters");
844843
assert(TUK != TUK_Reference && "Can only declare or define class templates");
@@ -999,16 +998,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
999998
// simply making that previous definition visible.
1000999
NamedDecl *Hidden = nullptr;
10011000
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
1002-
*SkipBody = true;
1001+
SkipBody->ShouldSkip = true;
10031002
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
10041003
assert(Tmpl && "original definition of a class template is not a "
10051004
"class template?");
1006-
if (auto *Listener = getASTMutationListener()) {
1007-
Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
1008-
Listener->RedefinedHiddenDefinition(Tmpl, KWLoc);
1009-
}
1010-
Hidden->setHidden(false);
1011-
Tmpl->setHidden(false);
1005+
makeMergedDefinitionVisible(Hidden, KWLoc);
1006+
makeMergedDefinitionVisible(Tmpl, KWLoc);
10121007
return Def;
10131008
}
10141009

clang/test/Modules/Inputs/submodules-merge-defs/defs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ template<typename T> struct F {
2929
};
3030
template<typename T> int F<T>::f() { return 0; }
3131
template<typename T> template<typename U> int F<T>::g() { return 0; }
32+
33+
namespace G {
34+
enum A { a, b, c, d, e };
35+
enum { f, g, h };
36+
typedef enum { i, j } k;
37+
typedef enum {} l;
38+
}

0 commit comments

Comments
 (0)