]> granicus.if.org Git - clang/commitdiff
Diagnose attempst to template using declarations and using directives.
authorJohn McCall <rjmccall@apple.com>
Wed, 10 Nov 2010 02:40:36 +0000 (02:40 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 10 Nov 2010 02:40:36 +0000 (02:40 +0000)
Recover from the latter and fail early for the former.  Fixes PR8022.

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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/ParsedTemplate.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseTemplate.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
test/SemaCXX/using-decl-1.cpp
test/SemaCXX/using-directive.cpp

index 93f5bbcba80f0b72699589dc62eb99d6eb04d771..bff6a38bcb76958ca774be9994f6af0174329047 100644 (file)
@@ -200,6 +200,10 @@ def err_unknown_typename : Error<
   "unknown type name %0">;
 def err_use_of_tag_name_without_tag : Error<
   "must use '%1' tag to refer to type %0%select{| in this scope}2">;
+def err_templated_using_directive : Error<
+  "cannot template a using directive">;
+def err_templated_using_declaration : Error<
+  "cannot template a using declaration">;
 def err_expected_ident_in_using : Error<
   "expected an identifier in using directive">;
 def err_unexected_colon_in_nested_name_spec : Error<
index 89e49c33ba98d4e89cfb660306e3b664ad38cd87..f72cf63d4706cd84bb2e72939c42e85b2edd7bb6 100644 (file)
@@ -892,6 +892,8 @@ private:
     
     /// \brief Whether the last template parameter list was empty.
     bool LastParameterListWasEmpty;
+
+    SourceRange getSourceRange() const;
   };
 
   void PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
@@ -1508,11 +1510,15 @@ private:
                        SourceLocation InlineLoc = SourceLocation());
   Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
   Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
+                                         const ParsedTemplateInfo &TemplateInfo,
                                          SourceLocation &DeclEnd,
                                          CXX0XAttributeList Attrs);
-  Decl *ParseUsingDirective(unsigned Context, SourceLocation UsingLoc,
+  Decl *ParseUsingDirective(unsigned Context,
+                            SourceLocation UsingLoc,
                             SourceLocation &DeclEnd, AttributeList *Attr);
-  Decl *ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc,
+  Decl *ParseUsingDeclaration(unsigned Context,
+                              const ParsedTemplateInfo &TemplateInfo,
+                              SourceLocation UsingLoc,
                               SourceLocation &DeclEnd,
                               AccessSpecifier AS = AS_none);
   Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd);
index da68a494bf7b22570243a08feba264730351686f..9d814c712d30e167f83aec1149e60ad61c8aa785 100644 (file)
@@ -161,7 +161,10 @@ namespace clang {
     
     void Destroy() { free(this); }
   };
-  
+
+  /// Retrieves the range of the given template parameter lists.
+  SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params,
+                                     unsigned NumParams);  
   
   inline const ParsedTemplateArgument &
   ASTTemplateArgsPtr::operator[](unsigned Arg) const { 
index 7e01bacf5cf2f567fc329116006fe1f4620e6285..2ba47641a039fac48a29c5968a9151eb827dfc26 100644 (file)
@@ -354,7 +354,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
     SingleDecl = ParseNamespace(Context, DeclEnd);
     break;
   case tok::kw_using:
-    SingleDecl = ParseUsingDirectiveOrDeclaration(Context, DeclEnd, Attr);
+    SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
+                                                  DeclEnd, Attr);
     break;
   case tok::kw_static_assert:
     if (Attr.HasAttr)
index a1e67d76997a59a3d4d573c14105c351be16ffc2..743442a39c908065834ffe7e81c487e28be324da 100644 (file)
@@ -239,8 +239,9 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
 /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
 /// using-directive. Assumes that current token is 'using'.
 Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
-                                                     SourceLocation &DeclEnd,
-                                                     CXX0XAttributeList Attr) {
+                                         const ParsedTemplateInfo &TemplateInfo,
+                                               SourceLocation &DeclEnd,
+                                               CXX0XAttributeList Attr) {
   assert(Tok.is(tok::kw_using) && "Not using token");
 
   // Eat 'using'.
@@ -251,17 +252,26 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
     ConsumeCodeCompletionToken();
   }
 
-  if (Tok.is(tok::kw_namespace))
-    // Next token after 'using' is 'namespace' so it must be using-directive
+  // 'using namespace' means this is a using-directive.
+  if (Tok.is(tok::kw_namespace)) {
+    // Template parameters are always an error here.
+    if (TemplateInfo.Kind) {
+      SourceRange R = TemplateInfo.getSourceRange();
+      Diag(UsingLoc, diag::err_templated_using_directive)
+        << R << FixItHint::CreateRemoval(R);
+    }
+
     return ParseUsingDirective(Context, UsingLoc, DeclEnd, Attr.AttrList);
+  }
 
+  // Otherwise, it must be a using-declaration.
+
+  // Using declarations can't have attributes.
   if (Attr.HasAttr)
     Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed)
       << Attr.Range;
 
-  // Otherwise, it must be using-declaration.
-  // Ignore illegal attributes (the caller should already have issued an error.
-  return ParseUsingDeclaration(Context, UsingLoc, DeclEnd);
+  return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd);
 }
 
 /// ParseUsingDirective - Parse C++ using-directive, assumes
@@ -275,9 +285,9 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
 ///                 namespace-name attributes[opt] ;
 ///
 Decl *Parser::ParseUsingDirective(unsigned Context,
-                                              SourceLocation UsingLoc,
-                                              SourceLocation &DeclEnd,
-                                              AttributeList *Attr) {
+                                  SourceLocation UsingLoc,
+                                  SourceLocation &DeclEnd,
+                                  AttributeList *Attr) {
   assert(Tok.is(tok::kw_namespace) && "Not 'namespace' token");
 
   // Eat 'namespace'.
@@ -335,13 +345,18 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
 ///       'using' :: unqualified-id
 ///
 Decl *Parser::ParseUsingDeclaration(unsigned Context,
-                                                SourceLocation UsingLoc,
-                                                SourceLocation &DeclEnd,
-                                                AccessSpecifier AS) {
+                                    const ParsedTemplateInfo &TemplateInfo,
+                                    SourceLocation UsingLoc,
+                                    SourceLocation &DeclEnd,
+                                    AccessSpecifier AS) {
   CXXScopeSpec SS;
   SourceLocation TypenameLoc;
   bool IsTypeName;
 
+  // TODO: in C++0x, if we have template parameters this must be a
+  // template alias:
+  //   template <...> using id = type;
+
   // Ignore optional 'typename'.
   // FIXME: This is wrong; we should parse this as a typename-specifier.
   if (Tok.is(tok::kw_typename)) {
@@ -386,6 +401,18 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
                    AttrList ? "attributes list" : "using declaration",
                    tok::semi);
 
+  // Diagnose an attempt to declare a templated using-declaration.
+  if (TemplateInfo.Kind) {
+    SourceRange R = TemplateInfo.getSourceRange();
+    Diag(UsingLoc, diag::err_templated_using_declaration)
+      << R << FixItHint::CreateRemoval(R);
+
+    // Unfortunately, we have to bail out instead of recovering by
+    // ignoring the parameters, just in case the nested name specifier
+    // depends on the parameters.
+    return 0;
+  }
+
   return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name,
                                        AttrList.get(), IsTypeName, TypenameLoc);
 }
@@ -1360,7 +1387,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
     } else {
       SourceLocation DeclEnd;
       // Otherwise, it must be using-declaration.
-      ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
+      ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
+                            UsingLoc, DeclEnd, AS);
     }
     return;
   }
index c472972e5cb10e16e96bddd5606981344033c194..333d72a754c4fc62aa200e33a728e776bd966479 100644 (file)
@@ -196,12 +196,20 @@ Parser::ParseSingleDeclarationAfterTemplate(
     return 0;
   }
 
+  CXX0XAttributeList PrefixAttrs;
+  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
+    PrefixAttrs = ParseCXX0XAttributes();
+
+  if (Tok.is(tok::kw_using))
+    return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
+                                            PrefixAttrs);
+
   // Parse the declaration specifiers, stealing the accumulated
   // diagnostics from the template parameters.
   ParsingDeclSpec DS(DiagsFromTParams);
 
-  if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier())
-    DS.AddAttributes(ParseCXX0XAttributes().AttrList);
+  if (PrefixAttrs.HasAttr)
+    DS.AddAttributes(PrefixAttrs.AttrList);
 
   ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
                              getDeclSpecContextFromDeclaratorContext(Context));
@@ -1075,3 +1083,14 @@ Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc,
                                              ParsingTemplateParams,
                                              DeclEnd, AS_none);
 }
+
+SourceRange Parser::ParsedTemplateInfo::getSourceRange() const {
+  if (TemplateParams)
+    return getTemplateParamsRange(TemplateParams->data(),
+                                  TemplateParams->size());
+
+  SourceRange R(TemplateLoc);
+  if (ExternLoc.isValid())
+    R.setBegin(ExternLoc);
+  return R;
+}
index 55dd66f073f8b2eb203802e9021fa6c5f5f147a7..33b312409040232bf2308164a7e704800a7e86a4 100644 (file)
@@ -3402,6 +3402,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
   assert(!SS.isInvalid() && "Invalid CXXScopeSpec.");
   assert(NamespcName && "Invalid NamespcName.");
   assert(IdentLoc.isValid() && "Invalid NamespceName location.");
+
+  // This can only happen along a recovery path.
+  while (S->getFlags() & Scope::TemplateParamScope)
+    S = S->getParent();
   assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
 
   UsingDirectiveDecl *UDir = 0;
@@ -3497,14 +3501,14 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
 
 
 Decl *Sema::ActOnUsingDeclaration(Scope *S,
-                                            AccessSpecifier AS,
-                                            bool HasUsingKeyword,
-                                            SourceLocation UsingLoc,
-                                            CXXScopeSpec &SS,
-                                            UnqualifiedId &Name,
-                                            AttributeList *AttrList,
-                                            bool IsTypeName,
-                                            SourceLocation TypenameLoc) {
+                                  AccessSpecifier AS,
+                                  bool HasUsingKeyword,
+                                  SourceLocation UsingLoc,
+                                  CXXScopeSpec &SS,
+                                  UnqualifiedId &Name,
+                                  AttributeList *AttrList,
+                                  bool IsTypeName,
+                                  SourceLocation TypenameLoc) {
   assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
 
   switch (Name.getKind()) {
index d7c809f35dd4be3067a1d2a7cbabd65715f1463a..3243903863d9dbf5bcca4d5f9f4b53b9c8ab547a 100644 (file)
 using namespace clang;
 using namespace sema;
 
+// Exported for use by Parser.
+SourceRange
+clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
+                              unsigned N) {
+  if (!N) return SourceRange();
+  return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
+}
+
 /// \brief Determine whether the declaration found is acceptable as the name
 /// of a template and, if so, return that template declaration. Otherwise,
 /// returns NULL.
index 30c4cfd997a1df7e3e9beb5ab852669afc0d3e92..65be0bc3aae6179e7a85edd4dd0d3979aeb1c31a 100644 (file)
@@ -95,3 +95,16 @@ namespace test1 {
     foo(p); // expected-error {{no matching function}}
   }
 }
+
+namespace test2 {
+  namespace ns { int foo; }
+  template <class T> using ns::foo; // expected-error {{cannot template a using declaration}}
+
+  // PR8022
+  struct A {
+    template <typename T> void f(T);
+  };
+  class B : A {
+    template <typename T> using A::f<T>; // expected-error {{cannot template a using declaration}}
+  };
+}
index 162f7fa07a36621d64955cc30d5553f0be2dc348..22c6e14ce54f6a98012c7b085099b9e029b6b24e 100644 (file)
@@ -126,3 +126,10 @@ void f4() { f2(1); }
 using namespace std; // expected-warning{{using directive refers to implicitly-defined namespace 'std'}}
 using namespace ::std; // expected-warning{{using directive refers to implicitly-defined namespace 'std'}}
 
+namespace test1 {
+  namespace ns { typedef int test1; }
+  template <class T> using namespace ns; // expected-error {{cannot template a using directive}}
+
+  // Test that we recovered okay.
+  test1 x;
+}