]> granicus.if.org Git - clang/commitdiff
Fix several crash-on-invalids when using template-ids that aren't
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 4 Dec 2013 00:28:23 +0000 (00:28 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 4 Dec 2013 00:28:23 +0000 (00:28 +0000)
simple-template-ids (eg, 'operator+<int>') in weird places.

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

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/TemplateKinds.h
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/drs/dr3xx.cpp
test/SemaCXX/cxx1y-variable-templates_top_level.cpp

index 2feab52ef4d1887dd7af3c38173c56c4fe4cc1ca..3415a0078c8bd399e15a5aadae191c87e7db7608 100644 (file)
@@ -578,8 +578,8 @@ def err_class_on_template_template_param : Error<
   "template template parameter requires 'class' after the parameter list">;
 def err_template_spec_syntax_non_template : Error<
   "identifier followed by '<' indicates a class template specialization but "
-  "%0 %select{does not refer to a template|refers to a function "
-  "template|<unused>|refers to a template template parameter}1">;
+  "%0 %select{does not refer to a template|refers to a function template|"
+  "<unused>|refers to a variable template|<unused>}1">;
 def err_id_after_template_in_nested_name_spec : Error<
   "expected template name after 'template' keyword in nested name specifier">;
 def err_two_right_angle_brackets_need_space : Error<
@@ -643,7 +643,7 @@ def err_expected_semi_after_tagdecl : Error<
   "expected ';' after %0">;
 
 def err_typename_refers_to_non_type_template : Error<
-  "typename specifier refers to a non-template">;
+  "typename specifier refers to a non-type template">;
 def err_expected_type_name_after_typename : Error<
   "expected an identifier or template-id after '::'">;
 def err_explicit_spec_non_template : Error<
index c5218933a226a739b016d57e9d303af7cfb53125..b730143b6391db5794ee0c93cab001ff09768c6d 100644 (file)
@@ -17,6 +17,7 @@
 namespace clang {
 
 /// \brief Specifies the kind of template name that an identifier refers to.
+/// Be careful when changing this: this enumeration is used in diagnostics.
 enum TemplateNameKind {
   /// The name does not refer to a template.
   TNK_Non_template = 0,
index d4a4ded252bd647a92af9f591148e4b4984c71c4..9c560229410243f6a38b6f1ab008c115ed807363 100644 (file)
@@ -1287,6 +1287,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
       if (SS.isNotEmpty())
         Range.setBegin(SS.getBeginLoc());
 
+      // FIXME: Name may be null here.
       Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
         << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;
 
index fe357cf0ada6e1664cd1749b82dc7be30ab56673..f07428a0f3f41ab20b5b14ac2cd259116af6428a 100644 (file)
@@ -341,10 +341,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
     if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
       // We have
       //
-      //   simple-template-id '::'
+      //   template-id '::'
       //
-      // So we need to check whether the simple-template-id is of the
-      // right kind (it should name a type or be dependent), and then
+      // So we need to check whether the template-id is a simple-template-id of
+      // the right kind (it should name a type or be dependent), and then
       // convert it into a type within the nested-name-specifier.
       TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
       if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
@@ -1882,6 +1882,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
     TemplateIdAnnotation *TemplateId
       = TemplateIdAnnotation::Allocate(TemplateArgs.size(), TemplateIds);
 
+    // FIXME: Store name for literal operator too.
     if (Id.getKind() == UnqualifiedId::IK_Identifier) {
       TemplateId->Name = Id.Identifier;
       TemplateId->Operator = OO_None;
index 59ffc0562aac52bbad382d1f24fd4d362ec43900..c4c0898661b7428936e0d9c24f81ecffe1a4fe7d 100644 (file)
@@ -1615,7 +1615,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
                                      Tok.getLocation());
     } else if (Tok.is(tok::annot_template_id)) {
       TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
-      if (TemplateId->Kind == TNK_Function_template) {
+      if (TemplateId->Kind != TNK_Type_template &&
+          TemplateId->Kind != TNK_Dependent_template_name) {
         Diag(Tok, diag::err_typename_refers_to_non_type_template)
           << Tok.getAnnotationRange();
         return true;
@@ -1740,6 +1741,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext,
       AnnotateTemplateIdTokenAsType();
       return false;
     } else if (TemplateId->Kind == TNK_Var_template)
+      // FIXME: This looks suspicious. Why are we not annotating the scope token
+      // in this case?
       return false;
   }
 
index 674411ec06224f880a7fc8e6a87926910343be1b..13c9993bf4cd5af3614e8dbc79e2298388233cb9 100644 (file)
@@ -747,7 +747,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
   TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
   translateTemplateArguments(TemplateArgsIn, TemplateArgs);
 
-  if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
+  DependentTemplateName *DTN = Template.get().getAsDependentTemplateName();
+  if (DTN && DTN->isIdentifier()) {
     // Handle a dependent template specialization for which we cannot resolve
     // the template name.
     assert(DTN->getQualifier() == SS.getScopeRep());
@@ -773,20 +774,20 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
               CCLoc);
     return false;
   }
-  
-  
-  if (Template.get().getAsOverloadedTemplate() ||
+
+  // FIXME: Variable templates
+  if (Template.get().getAsOverloadedTemplate() || DTN ||
       isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) {
     SourceRange R(TemplateNameLoc, RAngleLoc);
     if (SS.getRange().isValid())
       R.setBegin(SS.getRange().getBegin());
-      
+
     Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
       << Template.get() << R;
     NoteAllFoundTemplates(Template.get());
     return true;
   }
-                                
+
   // We were able to resolve the template name to an actual template. 
   // Build an appropriate nested-name-specifier.
   QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc, 
index 7b901d2df876ca9ed3fe1ede316b37a438f287ce..eb10758bc16e6a200a02c3186fbc00d6800d1436 100644 (file)
@@ -2910,7 +2910,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
   case UnqualifiedId::IK_OperatorFunctionId:
     Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier,
                                              Name.OperatorFunctionId.Operator));
-    return TNK_Dependent_template_name;
+    return TNK_Function_template;
 
   case UnqualifiedId::IK_LiteralOperatorId:
     llvm_unreachable(
index b7bf6ffa8e800eb2e7c3e0c4c8e9f63df9f1aecd..c9b1fe7733845d615665ddbc2530de1d36bf51c1 100644 (file)
@@ -8,4 +8,29 @@ namespace dr300 { // dr300: yes
   void h() { f(g); }
 }
 
-// expected-no-diagnostics
+namespace dr301 { // dr301 WIP
+  // see also dr38
+  struct S;
+  template<typename T> void operator+(T, T);
+  void operator-(S, S);
+
+  void f() {
+    bool a = (void(*)(S, S))operator+<S> <
+             (void(*)(S, S))operator+<S>;
+    bool b = (void(*)(S, S))operator- <
+             (void(*)(S, S))operator-;
+    bool c = (void(*)(S, S))operator+ <
+             (void(*)(S, S))operator-; // expected-error {{expected '>'}}
+  }
+
+  template<typename T> void f() {
+    typename T::template operator+<int> a; // expected-error {{typename specifier refers to a non-type template}} expected-error +{{}}
+    // FIXME: This shouldn't say (null).
+    class T::template operator+<int> b; // expected-error {{identifier followed by '<' indicates a class template specialization but (null) refers to a function template}}
+    enum T::template operator+<int> c; // expected-error {{expected identifier}} expected-error {{does not declare anything}}
+    enum T::template operator+<int>::E d; // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}} expected-error {{forward reference}}
+    enum T::template X<int>::E e;
+    T::template operator+<int>::foobar(); // expected-error {{qualified name refers into a specialization of function template 'T::template operator +'}}
+    T::template operator+<int>(0); // ok
+  }
+}
index b6e8762f5d59d6b8133ef97a991bad40246c3067..5af6c0ab5bf7b9c1123118888364f9b19f4f0f62 100644 (file)
@@ -432,3 +432,11 @@ namespace nested {
   }
 }
 
+namespace nested_name {
+  template<typename T> int a;
+  // FIXME: This triggers a crash.
+  //a<int>::b c;
+
+  class a<int> {}; // expected-error {{identifier followed by '<' indicates a class template specialization but 'a' refers to a variable template}}
+  enum a<int> {}; // expected-error {{expected identifier or '{'}} expected-warning {{does not declare anything}}
+}