]> granicus.if.org Git - clang/commitdiff
Fixed enum types can be complete without actually being valid to use
authorJohn McCall <rjmccall@apple.com>
Wed, 6 Jul 2011 06:57:57 +0000 (06:57 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 6 Jul 2011 06:57:57 +0000 (06:57 +0000)
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

include/clang/AST/NestedNameSpecifier.h
include/clang/Sema/DeclSpec.h
lib/Sema/DeclSpec.cpp
lib/Sema/SemaCXXScopeSpec.cpp
test/SemaCXX/enum-scoped.cpp

index 5deefe9d974a020665e48aaeb2b110d7dbda5545..018041f8ba209ad18949cdbc420f3b8fcd8e7def 100644 (file)
@@ -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() {
index db811d06f2e4b88779e540205e4d44ca63613f6e..e3bc5bff57bed03dfad29c7136c9688e508697bb 100644 (file)
@@ -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.
index c5b883e46d3f539f4112ed78e3697815871c72d7..a61188c3c47a337c1ece5e7836516468342c1f49 100644 (file)
@@ -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())
index e54857196a3cb889e9a5d37112f419f055f00738..5f8c9c62a4092a63faa5a665c8694c4e523aaae8 100644 (file)
@@ -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;
index 2c3537e163fde980bc99cff00d17bea9f4df5c95..73e7578ecb6e6810b917e2d8d83a690f2229caaf 100644 (file)
@@ -120,7 +120,7 @@ namespace rdar9366066 {
   }
 }
 
-// Part of PR10264
+// Part 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}}
+  }
+}