[cfe-commits] r118669 - in /cfe/trunk: 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

John McCall rjmccall at apple.com
Tue Nov 9 18:40:36 PST 2010


Author: rjmccall
Date: Tue Nov  9 20:40:36 2010
New Revision: 118669

URL: http://llvm.org/viewvc/llvm-project?rev=118669&view=rev
Log:
Diagnose attempst to template using declarations and using directives.
Recover from the latter and fail early for the former.  Fixes PR8022.


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

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Nov  9 20:40:36 2010
@@ -200,6 +200,10 @@
   "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<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Nov  9 20:40:36 2010
@@ -892,6 +892,8 @@
     
     /// \brief Whether the last template parameter list was empty.
     bool LastParameterListWasEmpty;
+
+    SourceRange getSourceRange() const;
   };
 
   void PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
@@ -1508,11 +1510,15 @@
                        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);

Modified: cfe/trunk/include/clang/Sema/ParsedTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ParsedTemplate.h?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/ParsedTemplate.h (original)
+++ cfe/trunk/include/clang/Sema/ParsedTemplate.h Tue Nov  9 20:40:36 2010
@@ -161,7 +161,10 @@
     
     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 { 

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Nov  9 20:40:36 2010
@@ -354,7 +354,8 @@
     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)

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Nov  9 20:40:36 2010
@@ -239,8 +239,9 @@
 /// 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 @@
     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 @@
 ///                 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 @@
 ///       '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 @@
                    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 @@
     } else {
       SourceLocation DeclEnd;
       // Otherwise, it must be using-declaration.
-      ParseUsingDeclaration(Declarator::MemberContext, UsingLoc, DeclEnd, AS);
+      ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
+                            UsingLoc, DeclEnd, AS);
     }
     return;
   }

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Nov  9 20:40:36 2010
@@ -196,12 +196,20 @@
     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 @@
                                              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;
+}

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Nov  9 20:40:36 2010
@@ -3402,6 +3402,10 @@
   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 @@
 
 
 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()) {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Nov  9 20:40:36 2010
@@ -30,6 +30,14 @@
 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.

Modified: cfe/trunk/test/SemaCXX/using-decl-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-decl-1.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/using-decl-1.cpp (original)
+++ cfe/trunk/test/SemaCXX/using-decl-1.cpp Tue Nov  9 20:40:36 2010
@@ -95,3 +95,16 @@
     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}}
+  };
+}

Modified: cfe/trunk/test/SemaCXX/using-directive.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-directive.cpp?rev=118669&r1=118668&r2=118669&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/using-directive.cpp (original)
+++ cfe/trunk/test/SemaCXX/using-directive.cpp Tue Nov  9 20:40:36 2010
@@ -126,3 +126,10 @@
 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;
+}





More information about the cfe-commits mailing list