]> granicus.if.org Git - clang/commitdiff
Be more careful around dependent nested-name-specifiers, complaining
authorDouglas Gregor <dgregor@apple.com>
Sat, 24 Apr 2010 16:38:41 +0000 (16:38 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 24 Apr 2010 16:38:41 +0000 (16:38 +0000)
when they are not complete (since we could not match them up to
anything) and ensuring that enum parsing can cope with dependent
elaborated-type-specifiers. Fixes PR6915 and PR6649.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102247 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Parse/ParseDecl.cpp
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/elaborated-type-specifier.cpp [new file with mode: 0644]

index af8946d16c0002be6cd0924b4f0616c505577e5c..d26566684b5b4e391a54a17e0820803546fdec51 100644 (file)
@@ -513,6 +513,9 @@ def note_access_constrained_by_path : Note<
 // C++ name lookup
 def err_incomplete_nested_name_spec : Error<
   "incomplete type %0 named in nested name specifier">;
+def err_dependent_nested_name_spec : Error<
+  "nested name specifier for a declaration cannot depend on a template "
+  "parameter">;
 def err_nested_name_member_ref_lookup_ambiguous : Error<
   "lookup of %0 in member access expression is ambiguous">;
 def note_ambig_member_ref_object_type : Note<
@@ -1590,6 +1593,9 @@ def err_tag_reference_non_tag : Error<
 def err_tag_reference_conflict : Error<
   "implicit declaration introduced by elaborated type conflicts with "
   "%select{a declaration|a typedef|a template}0 of the same name">;
+def err_dependent_tag_decl : Error<
+  "%select{declaration|definition}0 of %select{struct|union|class|enum}1 "
+  "in a dependent scope">;
 def err_tag_definition_of_typedef : Error<
   "definition of type %0 conflicts with typedef of the same name">;
 def err_conflicting_types : Error<"conflicting types for %0">;
index a034a325f4fc4f44bb1f19736368af5b98cbe754..6669d40cca0d6fa67eb3ff6bdd16dc6496fd2c1f 100644 (file)
@@ -1934,21 +1934,55 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
     TUK = Action::TUK_Reference;
   bool Owned = false;
   bool IsDependent = false;
+  SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
+  const char *PrevSpec = 0;
+  unsigned DiagID;
   DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
                                        StartLoc, SS, Name, NameLoc, Attr.get(),
                                        AS,
                                        Action::MultiTemplateParamsArg(Actions),
                                        Owned, IsDependent);
-  assert(!IsDependent && "didn't expect dependent enum");
+  if (IsDependent) {
+    // This enum has a dependent nested-name-specifier. Handle it as a 
+    // dependent tag.
+    if (!Name) {
+      DS.SetTypeSpecError();
+      Diag(Tok, diag::err_expected_type_name_after_typename);
+      return;
+    }
+    
+    TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum,
+                                                TUK, SS, Name, StartLoc, 
+                                                NameLoc);
+    if (Type.isInvalid()) {
+      DS.SetTypeSpecError();
+      return;
+    }
+    
+    if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID,
+                           Type.get(), false))
+      Diag(StartLoc, DiagID) << PrevSpec;
+    
+    return;
+  }
 
+  if (!TagDecl.get()) {
+    // The action failed to produce an enumeration tag. If this is a 
+    // definition, consume the entire definition.
+    if (Tok.is(tok::l_brace)) {
+      ConsumeBrace();
+      SkipUntil(tok::r_brace);
+    }
+    
+    DS.SetTypeSpecError();
+    return;
+  }
+  
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);
 
   // FIXME: The DeclSpec should keep the locations of both the keyword and the
   // name (if there is one).
-  SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc;
-  const char *PrevSpec = 0;
-  unsigned DiagID;
   if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID,
                          TagDecl.getAs<void>(), Owned))
     Diag(StartLoc, DiagID) << PrevSpec;
index e9d206e53be0260bf4a88c060d165cc1fe9f0a8f..89f8aec6e0185d32ea415ea6db09841478299c20 100644 (file)
@@ -235,6 +235,16 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS) {
     return false;
 
   DeclContext *DC = computeDeclContext(SS, true);
+  if (!DC) {
+    // It's dependent.
+    assert(isDependentScopeSpecifier(SS) && 
+           "No context for non-dependent scope specifier?");
+    Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec)
+      << SS.getRange();
+    SS.setScopeRep(0);
+    return true;
+  }
+  
   if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
     // If this is a dependent type, then we consider it complete.
     if (Tag->isDependentContext())
index b8ff182be087fe4cf48d138544bb3965d2196a60..bf2cba10c7903a99b1240900cc8b1d0c4aae40a2 100644 (file)
@@ -5313,7 +5313,7 @@ CreateNewDecl:
 void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) {
   AdjustDeclIfTemplate(TagD);
   TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>());
-
+  
   // Enter the tag context.
   PushDeclContext(S, Tag);
 }
index 1075f41399840d98e59a05533cc4effb95b49d40..14d04563d69aab8b5e0062a41b2d4e69134dabef 100644 (file)
@@ -5117,6 +5117,13 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
   }
   assert(Keyword != ETK_None && "Invalid tag kind!");
 
+  if (TUK == TUK_Declaration || TUK == TUK_Definition) {
+    Diag(NameLoc, diag::err_dependent_tag_decl)
+      << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec)
+      << SS.getRange();
+    return true;
+  }
+  
   return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr();
 }
 
diff --git a/test/SemaTemplate/elaborated-type-specifier.cpp b/test/SemaTemplate/elaborated-type-specifier.cpp
new file mode 100644 (file)
index 0000000..c38bf54
--- /dev/null
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR6915 {
+  template <typename T>
+  class D {
+    enum T::X v; // expected-error{{use of 'X' with tag type that does not match previous declaration}} \
+    // expected-error{{no enum named 'X' in 'PR6915::D3'}}
+  };
+
+  struct D1 {
+    enum X { value };
+  };
+  struct D2 { 
+    class X { }; // expected-note{{previous use is here}}
+  };
+  struct D3 { };
+
+  template class D<D1>;
+  template class D<D2>; // expected-note{{in instantiation of}}
+  template class D<D3>; // expected-note{{in instantiation of}}
+}
+
+template<typename T>
+struct DeclOrDef {
+  enum T::foo; // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+  enum T::bar { // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+    value 
+  };
+};
+
+namespace PR6649 {
+  template <typename T> struct foo { 
+    class T::bar;  // expected-error{{nested name specifier for a declaration cannot depend on a template parameter}}
+  };
+}