forked from OSchip/llvm-project
[modules] Suport for merging a parsed enum definition into an existing imported but not visible definition.
llvm-svn: 236690
This commit is contained in:
parent
69a4779965
commit
d9ba224f66
|
@ -1279,6 +1279,10 @@ private:
|
|||
bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
|
||||
TypeDiagnoser &Diagnoser);
|
||||
public:
|
||||
/// \brief Make a merged definition of an existing hidden definition \p ND
|
||||
/// visible at the specified location.
|
||||
void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc);
|
||||
|
||||
/// Determine if \p D has a visible definition. If not, suggest a declaration
|
||||
/// that should be made visible to expose the definition.
|
||||
bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested);
|
||||
|
@ -1724,6 +1728,12 @@ public:
|
|||
TUK_Friend // Friend declaration: 'friend struct foo;'
|
||||
};
|
||||
|
||||
struct SkipBodyInfo {
|
||||
SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {}
|
||||
bool ShouldSkip;
|
||||
NamedDecl *Previous;
|
||||
};
|
||||
|
||||
Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
SourceLocation KWLoc, CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
|
@ -1733,7 +1743,7 @@ public:
|
|||
bool &OwnedDecl, bool &IsDependent,
|
||||
SourceLocation ScopedEnumKWLoc,
|
||||
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType,
|
||||
bool IsTypeSpecifier, bool *SkipBody = nullptr);
|
||||
bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr);
|
||||
|
||||
Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
||||
unsigned TagSpec, SourceLocation TagLoc,
|
||||
|
@ -1844,6 +1854,11 @@ public:
|
|||
bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
|
||||
QualType EnumUnderlyingTy, const EnumDecl *Prev);
|
||||
|
||||
/// Determine whether the body of an anonymous enumeration should be skipped.
|
||||
/// \param II The name of the first enumerator.
|
||||
SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
|
||||
SourceLocation IILoc);
|
||||
|
||||
Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
AttributeList *Attrs,
|
||||
|
@ -5382,7 +5397,7 @@ public:
|
|||
SourceLocation FriendLoc,
|
||||
unsigned NumOuterTemplateParamLists,
|
||||
TemplateParameterList **OuterTemplateParamLists,
|
||||
bool *SkipBody = nullptr);
|
||||
SkipBodyInfo *SkipBody = nullptr);
|
||||
|
||||
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
|
||||
TemplateArgumentListInfo &Out);
|
||||
|
|
|
@ -3893,6 +3893,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
|
||||
handleDeclspecAlignBeforeClassKey(attrs, DS, TUK);
|
||||
|
||||
Sema::SkipBodyInfo SkipBody;
|
||||
if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) &&
|
||||
NextToken().is(tok::identifier))
|
||||
SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(),
|
||||
NextToken().getIdentifierInfo(),
|
||||
NextToken().getLocation());
|
||||
|
||||
bool Owned = false;
|
||||
bool IsDependent = false;
|
||||
const char *PrevSpec = nullptr;
|
||||
|
@ -3902,7 +3909,22 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
|
|||
AS, DS.getModulePrivateSpecLoc(), TParams,
|
||||
Owned, IsDependent, ScopedEnumKWLoc,
|
||||
IsScopedUsingClassTag, BaseType,
|
||||
DSC == DSC_type_specifier);
|
||||
DSC == DSC_type_specifier, &SkipBody);
|
||||
|
||||
if (SkipBody.ShouldSkip) {
|
||||
assert(TUK == Sema::TUK_Definition && "can only skip a definition");
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_brace);
|
||||
T.consumeOpen();
|
||||
T.skipToEnd();
|
||||
|
||||
if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
|
||||
NameLoc.isValid() ? NameLoc : StartLoc,
|
||||
PrevSpec, DiagID, TagDecl, Owned,
|
||||
Actions.getASTContext().getPrintingPolicy()))
|
||||
Diag(StartLoc, DiagID) << PrevSpec;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsDependent) {
|
||||
// This enum has a dependent nested-name-specifier. Handle it as a
|
||||
|
|
|
@ -1553,7 +1553,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
TypeResult TypeResult = true; // invalid
|
||||
|
||||
bool Owned = false;
|
||||
bool SkipBody = false;
|
||||
Sema::SkipBodyInfo SkipBody;
|
||||
if (TemplateId) {
|
||||
// Explicit specialization, class template partial specialization,
|
||||
// or explicit instantiation.
|
||||
|
@ -1718,7 +1718,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
assert(Tok.is(tok::l_brace) ||
|
||||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
|
||||
isCXX11FinalKeyword());
|
||||
if (SkipBody)
|
||||
if (SkipBody.ShouldSkip)
|
||||
SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType,
|
||||
TagOrTempResult.get());
|
||||
else if (getLangOpts().CPlusPlus)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTLambda.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/CommentDiagnostic.h"
|
||||
|
@ -1974,9 +1973,7 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
|
|||
New->setTypeSourceInfo(OldTD->getTypeSourceInfo());
|
||||
|
||||
// Make the old tag definition visible.
|
||||
if (auto *Listener = getASTMutationListener())
|
||||
Listener->RedefinedHiddenDefinition(Hidden, NewTag->getLocation());
|
||||
Hidden->setHidden(false);
|
||||
makeMergedDefinitionVisible(Hidden, NewTag->getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11311,8 +11308,8 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S,
|
|||
/// \param IsTypeSpecifier \c true if this is a type-specifier (or
|
||||
/// trailing-type-specifier) other than one in an alias-declaration.
|
||||
///
|
||||
/// \param SkipBody If non-null, will be set to true if the caller should skip
|
||||
/// the definition of this tag, and treat it as if it were a declaration.
|
||||
/// \param SkipBody If non-null, will be set to indicate if the caller should
|
||||
/// skip the definition of this tag and treat it as if it were a declaration.
|
||||
Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
SourceLocation KWLoc, CXXScopeSpec &SS,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
|
@ -11323,7 +11320,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
SourceLocation ScopedEnumKWLoc,
|
||||
bool ScopedEnumUsesClassTag,
|
||||
TypeResult UnderlyingType,
|
||||
bool IsTypeSpecifier, bool *SkipBody) {
|
||||
bool IsTypeSpecifier, SkipBodyInfo *SkipBody) {
|
||||
// If this is not a definition, it must have a name.
|
||||
IdentifierInfo *OrigName = Name;
|
||||
assert((Name != nullptr || TUK == TUK_Definition) &&
|
||||
|
@ -11633,6 +11630,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
}
|
||||
}
|
||||
|
||||
// If we have a known previous declaration to use, then use it.
|
||||
if (Previous.empty() && SkipBody && SkipBody->Previous)
|
||||
Previous.addDecl(SkipBody->Previous);
|
||||
|
||||
if (!Previous.empty()) {
|
||||
NamedDecl *PrevDecl = Previous.getFoundDecl();
|
||||
NamedDecl *DirectPrevDecl =
|
||||
|
@ -11774,10 +11775,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
// assume that this definition is identical to the hidden one
|
||||
// we already have. Make the existing definition visible and
|
||||
// use it in place of this one.
|
||||
*SkipBody = true;
|
||||
if (auto *Listener = getASTMutationListener())
|
||||
Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
|
||||
Hidden->setHidden(false);
|
||||
SkipBody->ShouldSkip = true;
|
||||
makeMergedDefinitionVisible(Hidden, KWLoc);
|
||||
return Def;
|
||||
} else if (!IsExplicitSpecializationAfterInstantiation) {
|
||||
// A redeclaration in function prototype scope in C isn't
|
||||
|
@ -13465,6 +13464,29 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
|
|||
Val, EnumVal);
|
||||
}
|
||||
|
||||
Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
|
||||
SourceLocation IILoc) {
|
||||
if (!getLangOpts().Modules || !getLangOpts().CPlusPlus)
|
||||
return SkipBodyInfo();
|
||||
|
||||
// We have an anonymous enum definition. Look up the first enumerator to
|
||||
// determine if we should merge the definition with an existing one and
|
||||
// skip the body.
|
||||
NamedDecl *PrevDecl = LookupSingleName(S, II, IILoc, LookupOrdinaryName,
|
||||
ForRedeclaration);
|
||||
auto *PrevECD = dyn_cast_or_null<EnumConstantDecl>(PrevDecl);
|
||||
NamedDecl *Hidden;
|
||||
if (PrevECD &&
|
||||
!hasVisibleDefinition(cast<NamedDecl>(PrevECD->getDeclContext()),
|
||||
&Hidden)) {
|
||||
SkipBodyInfo Skip;
|
||||
Skip.ShouldSkip = true;
|
||||
Skip.Previous = Hidden;
|
||||
return Skip;
|
||||
}
|
||||
|
||||
return SkipBodyInfo();
|
||||
}
|
||||
|
||||
Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
|
@ -1169,6 +1170,12 @@ static Decl *getInstantiatedFrom(Decl *D, MemberSpecializationInfo *MSInfo) {
|
|||
return MSInfo->isExplicitSpecialization() ? D : MSInfo->getInstantiatedFrom();
|
||||
}
|
||||
|
||||
void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
|
||||
if (auto *Listener = getASTMutationListener())
|
||||
Listener->RedefinedHiddenDefinition(ND, Loc);
|
||||
ND->setHidden(false);
|
||||
}
|
||||
|
||||
/// \brief Find the module in which the given declaration was defined.
|
||||
static Module *getDefiningModule(Decl *Entity) {
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Entity)) {
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "TreeTransform.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/DeclFriend.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
|
@ -838,7 +837,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
SourceLocation FriendLoc,
|
||||
unsigned NumOuterTemplateParamLists,
|
||||
TemplateParameterList** OuterTemplateParamLists,
|
||||
bool *SkipBody) {
|
||||
SkipBodyInfo *SkipBody) {
|
||||
assert(TemplateParams && TemplateParams->size() > 0 &&
|
||||
"No template parameters");
|
||||
assert(TUK != TUK_Reference && "Can only declare or define class templates");
|
||||
|
@ -999,16 +998,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
// simply making that previous definition visible.
|
||||
NamedDecl *Hidden = nullptr;
|
||||
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
|
||||
*SkipBody = true;
|
||||
SkipBody->ShouldSkip = true;
|
||||
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
|
||||
assert(Tmpl && "original definition of a class template is not a "
|
||||
"class template?");
|
||||
if (auto *Listener = getASTMutationListener()) {
|
||||
Listener->RedefinedHiddenDefinition(Hidden, KWLoc);
|
||||
Listener->RedefinedHiddenDefinition(Tmpl, KWLoc);
|
||||
}
|
||||
Hidden->setHidden(false);
|
||||
Tmpl->setHidden(false);
|
||||
makeMergedDefinitionVisible(Hidden, KWLoc);
|
||||
makeMergedDefinitionVisible(Tmpl, KWLoc);
|
||||
return Def;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,3 +29,10 @@ template<typename T> struct F {
|
|||
};
|
||||
template<typename T> int F<T>::f() { return 0; }
|
||||
template<typename T> template<typename U> int F<T>::g() { return 0; }
|
||||
|
||||
namespace G {
|
||||
enum A { a, b, c, d, e };
|
||||
enum { f, g, h };
|
||||
typedef enum { i, j } k;
|
||||
typedef enum {} l;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue