diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-03-26 04:09:53 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-03-26 04:09:53 +0000 |
| commit | 65ebb4ac8a7119a16e5a00b075e5b382fd4e434c (patch) | |
| tree | aba5d66b22388b22c9c2f62df8fd03f0ecacfcb1 /clang/lib/Sema | |
| parent | e972c3622113feaeaf4c1a7c8a60d193c385cb06 (diff) | |
| download | bcm5719-llvm-65ebb4ac8a7119a16e5a00b075e5b382fd4e434c.tar.gz bcm5719-llvm-65ebb4ac8a7119a16e5a00b075e5b382fd4e434c.zip | |
[modules] If we reach a definition of a class for which we already have a
non-visible definition, skip the new definition and make the old one visible
instead of trying to parse it again and failing horribly. C++'s ODR allows
us to assume that the two definitions are identical.
llvm-svn: 233250
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 26 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 10 |
3 files changed, 27 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 438ad61ee9b..9e146ed3a64 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -218,6 +218,7 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // Fixed enum types are complete, but they aren't valid as scopes // until we see a definition, so awkwardly pull out this special // case. + // FIXME: The definition might not be visible; complain if it is not. const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType); if (!enumType || enumType->getDecl()->isCompleteDefinition()) return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1234afb8fb7..ffd22390ee3 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16,6 +16,7 @@ #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" @@ -11233,13 +11234,16 @@ static FixItHint createFriendTagNNSFixIt(Sema &SemaRef, NamedDecl *ND, Scope *S, return FixItHint::CreateInsertion(NameLoc, Insertion); } -/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the +/// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. /// -/// IsTypeSpecifier is true if this is a type-specifier (or +/// \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. Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, @@ -11250,7 +11254,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, - bool IsTypeSpecifier) { + bool IsTypeSpecifier, bool *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -11676,7 +11680,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { - if (TagDecl *Def = PrevTagDecl->getDefinition()) { + if (NamedDecl *Def = PrevTagDecl->getDefinition()) { // If we're defining a specialization and the previous definition // is from an implicit instantiation, don't emit an error // here; we'll catch this in the general case below. @@ -11692,7 +11696,19 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TSK_ExplicitSpecialization; } - if (!IsExplicitSpecializationAfterInstantiation) { + if (SkipBody && getLangOpts().CPlusPlus && + !hasVisibleDefinition(Def, &Def)) { + // There is a definition of this tag, but it is not visible. We + // explicitly make use of C++'s one definition rule here, and + // 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(Def, KWLoc); + Def->setHidden(false); + return Def; + } else if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't // visible elsewhere, so merely issue a warning. if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope()) diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 669cb9a9772..485b70a4f9b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5126,9 +5126,9 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// \param D The definition of the entity. /// \param Suggested Filled in with the declaration that should be made visible /// in order to provide a definition of this entity. -static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) { +bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested) { // Easy case: if we don't have modules, all declarations are visible. - if (!S.getLangOpts().Modules) + if (!getLangOpts().Modules) return true; // If this definition was instantiated from a template, map back to the @@ -5144,7 +5144,7 @@ static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) { // If the enum has a fixed underlying type, any declaration of it will do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { - if (LookupResult::isVisible(S, Redecl)) + if (LookupResult::isVisible(*this, Redecl)) return true; if (Redecl->isThisDeclarationADefinition() || (Redecl->isCanonicalDecl() && !*Suggested)) @@ -5159,7 +5159,7 @@ static bool hasVisibleDefinition(Sema &S, NamedDecl *D, NamedDecl **Suggested) { // FIXME: If we merged any other decl into D, and that declaration is visible, // then we should consider a definition to be visible. *Suggested = D; - return LookupResult::isVisible(S, D); + return LookupResult::isVisible(*this, D); } /// Locks in the inheritance model for the given class and all of its bases. @@ -5210,7 +5210,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (!Diagnoser.Suppressed && Def && - !hasVisibleDefinition(*this, Def, &SuggestedDef)) { + !hasVisibleDefinition(Def, &SuggestedDef)) { // Suppress this error outside of a SFINAE context if we've already // emitted the error once for this type. There's no usefulness in // repeating the diagnostic. |

