From: John McCall Date: Wed, 6 Jul 2011 06:57:57 +0000 (+0000) Subject: Fixed enum types can be complete without actually being valid to use X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9dc71d2fddcd283e07d45f3894c8559e2f7dd9a7;p=clang Fixed enum types can be complete without actually being valid to use as scope specifiers; diagnose the attempt, rather than letting it go to an assert. The rest of PR10264. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134479 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 5deefe9d97..018041f8ba 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -439,6 +439,14 @@ public: /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + /// \brief Retrieve a nested-name-specifier with location + /// information based on the information in this builder. This loc + /// will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + /// \brief Clear out this builder, and prepare it to build another /// nested-name-specifier with source-location information. void Clear() { diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index db811d06f2..e3bc5bff57 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -154,6 +154,12 @@ public: /// copied. NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + /// \brief Retrieve the location of the name in the last qualifier + /// in this nested name specifier. For example: + /// ::foo::bar<0>:: + /// ^~~ + SourceLocation getLastQualifierNameLoc() const; + /// No scope specifier. bool isEmpty() const { return !Range.isValid(); } /// A scope specifier is present, but may be valid or invalid. diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index c5b883e46d..a61188c3c4 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -126,6 +126,12 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { Builder.Adopt(Other); } +SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const { + if (!Builder.getRepresentation()) + return SourceLocation(); + return Builder.getTemporary().getLocalBeginLoc(); +} + NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) const { if (!Builder.getRepresentation()) diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index e54857196a..5f8c9c62a4 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -211,25 +211,40 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC) { assert(DC != 0 && "given null context"); - if (TagDecl *Tag = dyn_cast(DC)) { + if (TagDecl *tag = dyn_cast(DC)) { // If this is a dependent type, then we consider it complete. - if (Tag->isDependentContext()) + if (tag->isDependentContext()) return false; // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. - const TagType *TagT = Context.getTypeDeclType(Tag)->getAs(); - if (TagT && TagT->isBeingDefined()) + QualType type = Context.getTypeDeclType(tag); + const TagType *tagType = type->getAs(); + if (tagType && tagType->isBeingDefined()) return false; + SourceLocation loc = SS.getLastQualifierNameLoc(); + if (loc.isInvalid()) loc = SS.getRange().getBegin(); + // The type must be complete. - if (RequireCompleteType(SS.getRange().getBegin(), - Context.getTypeDeclType(Tag), + if (RequireCompleteType(loc, type, PDiag(diag::err_incomplete_nested_name_spec) << SS.getRange())) { SS.SetInvalid(SS.getRange()); return true; } + + // Fixed enum types are complete, but they aren't valid as scopes + // until we see a definition, so awkwardly pull out this special + // case. + if (const EnumType *enumType = dyn_cast_or_null(tagType)) { + if (!enumType->getDecl()->isDefinition()) { + Diag(loc, diag::err_incomplete_nested_name_spec) + << type << SS.getRange(); + SS.SetInvalid(SS.getRange()); + return true; + } + } } return false; diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp index 2c3537e163..73e7578ecb 100644 --- a/test/SemaCXX/enum-scoped.cpp +++ b/test/SemaCXX/enum-scoped.cpp @@ -120,7 +120,7 @@ namespace rdar9366066 { } } -// Part of PR10264 +// Part 1 of PR10264 namespace test5 { namespace ns { typedef unsigned Atype; @@ -130,3 +130,15 @@ namespace test5 { x, y, z }; } + +// Part 2 of PR10264 +namespace test6 { + enum A : unsigned; + struct A::a; // expected-error {{incomplete type 'test6::A' named in nested name specifier}} + enum A::b; // expected-error {{incomplete type 'test6::A' named in nested name specifier}} + int A::c; // expected-error {{incomplete type 'test6::A' named in nested name specifier}} + void A::d(); // expected-error {{incomplete type 'test6::A' named in nested name specifier}} + void test() { + (void) A::e; // expected-error {{incomplete type 'test6::A' named in nested name specifier}} + } +}