diff options
-rw-r--r-- | include/clang/AST/NestedNameSpecifier.h | 8 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 6 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 27 | ||||
-rw-r--r-- | test/SemaCXX/enum-scoped.cpp | 14 |
5 files changed, 54 insertions, 7 deletions
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<TagDecl>(DC)) { + if (TagDecl *tag = dyn_cast<TagDecl>(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<TagType>(); - if (TagT && TagT->isBeingDefined()) + QualType type = Context.getTypeDeclType(tag); + const TagType *tagType = type->getAs<TagType>(); + 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<EnumType>(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}} + } +} |