[cfe-commits] r64189 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def include/clang/Parse/Parser.h lib/Parse/ParseTemplate.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/temp_arg_nontype.cpp test/SemaTemplate/temp_arg_type.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 9 16:53:15 PST 2009


Author: dgregor
Date: Mon Feb  9 18:53:15 2009
New Revision: 64189

URL: http://llvm.org/viewvc/llvm-project?rev=64189&view=rev
Log:
Teach the type-id/expression disambiguator about different
disambiguation contexts, so that we properly parse template arguments
such as

  A<int()>

as type-ids rather than as expressions. Since this can be confusing
(especially when the template parameter is a non-type template
parameter), we try to give a friendly error message.

Almost, eliminate a redundant error message (that should have been a
note) and add some ultra-basic checks for non-type template
arguments.


Added:
    cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_type.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Mon Feb  9 18:53:15 2009
@@ -497,8 +497,6 @@
 // C++ Template Argument Lists
 DIAG(err_template_arg_list_different_arity, ERROR,
      "%select{too few|too many}0 template arguments for %select{class template|function template|template template parameter|template}1 %2")
-DIAG(note_template_parameter_here, ERROR,
-     "template parameter is declared here")
 DIAG(err_template_arg_must_be_type, ERROR,
      "template argument for template type parameter must be a type")
 DIAG(err_template_arg_must_be_expr, ERROR,

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Feb  9 18:53:15 2009
@@ -819,12 +819,20 @@
     return isDeclarationSpecifier();
   }
 
+  /// \brief Specifies the context in which type-id/expression
+  /// disambiguation will occur.
+  enum TentativeCXXTypeIdContext {
+    TypeIdInParens,
+    TypeIdAsTemplateArgument
+  };
+
+
   /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know
   /// whether the parens contain an expression or a type-id.
   /// Returns true for a type-id and false for an expression.
   bool isTypeIdInParens() {
     if (getLang().CPlusPlus)
-      return isCXXTypeIdInParens();
+      return isCXXTypeId(TypeIdInParens);
     return isTypeSpecifierQualifier();
   }
 
@@ -855,12 +863,7 @@
   /// the function returns true to let the declaration parsing code handle it.
   bool isCXXConditionDeclaration();
 
-  /// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to
-  /// know whether the parens contain an expression or a type-id.
-  /// Returns true for a type-id and false for an expression.
-  /// If during the disambiguation process a parsing error is encountered,
-  /// the function returns true to let the declaration parsing code handle it.
-  bool isCXXTypeIdInParens();
+  bool isCXXTypeId(TentativeCXXTypeIdContext Context);
 
   /// TPResult - Used as the result value for functions whose purpose is to
   /// disambiguate C++ constructs by "tentatively parsing" them.

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Feb  9 18:53:15 2009
@@ -456,7 +456,7 @@
   //   the corresponding template-parameter.
   //
   // Therefore, we initially try to parse a type-id.
-  if (isTypeIdInParens()) {
+  if (isCXXTypeId(TypeIdAsTemplateArgument)) {
     ArgIsType = true;
     return ParseTypeName();
   }

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Feb  9 18:53:15 2009
@@ -270,16 +270,24 @@
   return TPR == TPResult::True();
 }
 
-/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to
-/// know whether the parens contain an expression or a type-id.
-/// Returns true for a type-id and false for an expression.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
-///
-/// type-id:
-///   type-specifier-seq abstract-declarator[opt]
-///
-bool Parser::isCXXTypeIdInParens() {
+  /// \brief Determine whether the next set of tokens contains a type-id. 
+  ///
+  /// The context parameter states what context we're parsing right
+  /// now, which affects how this routine copes with the token
+  /// following the type-id. If the context is TypeIdInParens, we have
+  /// already parsed the '(' and we will cease lookahead when we hit
+  /// the corresponding ')'. If the context is
+  /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
+  /// before this template argument, and will cease lookahead when we
+  /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
+  /// and false for an expression.  If during the disambiguation
+  /// process a parsing error is encountered, the function returns
+  /// true to let the declaration parsing code handle it.
+  ///
+  /// type-id:
+  ///   type-specifier-seq abstract-declarator[opt]
+  ///
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
 
   // C++ 8.2p2:
   // The ambiguity arising from the similarity between a function-style cast and
@@ -318,7 +326,14 @@
   if (TPR == TPResult::Ambiguous()) {
     // We are supposed to be inside parens, so if after the abstract declarator
     // we encounter a ')' this is a type-id, otherwise it's an expression.
-    if (Tok.is(tok::r_paren))
+    if (Context == TypeIdInParens && Tok.is(tok::r_paren))
+      TPR = TPResult::True();
+    // We are supposed to be inside a template argument, so if after
+    // the abstract declarator we encounter a '>', '>>' (in C++0x), or
+    // ',', this is a type-id. Otherwise, it's an expression.
+    else if (Context == TypeIdAsTemplateArgument &&
+             (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+              (getLang().CPlusPlus0x && Tok.is(tok::greatergreater))))
       TPR = TPResult::True();
     else
       TPR = TPResult::False();

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb  9 18:53:15 2009
@@ -458,7 +458,7 @@
       // is an expression.
       Diag(ArgExpr->getSourceRange().getBegin(), 
            diag::err_template_arg_must_be_type);
-      Diag((*Param)->getLocation(), diag::note_template_parameter_here);
+      Diag((*Param)->getLocation(), diag::note_template_param_here);
       Invalid = true;
     } else if (NonTypeTemplateParmDecl *NTTP 
                  = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
@@ -484,7 +484,7 @@
           << ArgType;
       else
         Diag(ArgLoc, diag::err_template_arg_must_be_expr);
-      Diag((*Param)->getLocation(), diag::note_template_parameter_here);
+      Diag((*Param)->getLocation(), diag::note_template_param_here);
       Invalid = true;
     } else { 
       // Check template template parameters.

Added: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=64189&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Mon Feb  9 18:53:15 2009
@@ -0,0 +1,14 @@
+// RUN: clang -fsyntax-only -std=c++98 -verify %s
+
+template<int N> struct A; // expected-note 2{{template parameter is declared here}}
+
+A<0> *a0;
+
+A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}}
+
+A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}}
+
+A<1 >> 2> *a3;
+
+// FIXME: We haven't tried actually checking the expressions yet.
+// A<A> *a4; 

Modified: cfe/trunk/test/SemaTemplate/temp_arg_type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_type.cpp?rev=64189&r1=64188&r2=64189&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_type.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_type.cpp Mon Feb  9 18:53:15 2009
@@ -1,5 +1,5 @@
 // RUN: clang -fsyntax-only -verify %s
-template<typename T> class A; // expected-error 2 {{template parameter is declared here}}
+template<typename T> class A; // expected-note 2 {{template parameter is declared here}}
 
 // [temp.arg.type]p1
 A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
@@ -7,9 +7,8 @@
 A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
 
 A<int> *a3;
-// FIXME: The two below are well-formed, but we're not parsing them as type-ids.
-// A<int()> *a4; 
-// A<int(float)> *a5;
+A<int()> *a4; 
+A<int(float)> *a5;
 A<A<int> > *a6;
 
 // [temp.arg.type]p2





More information about the cfe-commits mailing list