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);
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,
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,
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,
SourceLocation FriendLoc,
unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists,
- bool *SkipBody = nullptr);
+ SkipBodyInfo *SkipBody = nullptr);
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
TemplateArgumentListInfo &Out);
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;
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
TypeResult TypeResult = true; // invalid
bool Owned = false;
- bool SkipBody = false;
+ Sema::SkipBodyInfo SkipBody;
if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
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)
#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"
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());
}
}
/// \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,
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) &&
}
}
+ // 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 =
// 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
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,
//===----------------------------------------------------------------------===//
#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"
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)) {
#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"
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");
// 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;
}
};
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;
+}