[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