[cfe-commits] r64256 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaType.cpp test/SemaTemplate/temp_arg_nontype.cpp
Douglas Gregor
dgregor at apple.com
Tue Feb 10 15:36:10 PST 2009
Author: dgregor
Date: Tue Feb 10 17:36:10 2009
New Revision: 64256
URL: http://llvm.org/viewvc/llvm-project?rev=64256&view=rev
Log:
Add type-checking and implicit conversions for template parameters of
integral or enumeration type.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=64256&r1=64255&r2=64256&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Tue Feb 10 17:36:10 2009
@@ -525,6 +525,12 @@
"template argument refers to function template %0, here")
DIAG(err_template_arg_template_params_mismatch, ERROR,
"template template argument has different template parameters than its corresponding template template parameter")
+DIAG(err_template_arg_not_integral_or_enumeral, ERROR,
+ "non-type template argument of type %0 must have an integral or enumeration type")
+DIAG(err_template_arg_not_ice, ERROR,
+ "non-type template argument of type %0 is not an integral constant expression")
+DIAG(err_template_arg_not_convertible, ERROR,
+ "non-type template argument of type %0 cannot be converted to a value of type %1")
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name %0: expected expression")
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64256&r1=64255&r2=64256&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Feb 10 17:36:10 2009
@@ -281,6 +281,9 @@
SourceRange Range2 = SourceRange(),
QualType PrintType = QualType());
+ bool hasSameType(QualType T1, QualType T2);
+ bool hasSameUnqualifiedType(QualType T1, QualType T2);
+
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
//
@@ -1547,7 +1550,7 @@
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
SourceLocation ArgLoc);
- bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *Arg);
+ bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64256&r1=64255&r2=64256&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 10 17:36:10 2009
@@ -827,7 +827,75 @@
/// This routine implements the semantics of C++ [temp.arg.nontype].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
- Expr *Arg) {
+ Expr *&Arg) {
+ // If either the parameter has a dependent type or the argument is
+ // type-dependent, there's nothing we can check now.
+ if (Param->getType()->isDependentType() || Arg->isTypeDependent())
+ return false;
+
+ // C++ [temp.arg.nontype]p5:
+ // The following conversions are performed on each expression used
+ // as a non-type template-argument. If a non-type
+ // template-argument cannot be converted to the type of the
+ // corresponding template-parameter then the program is
+ // ill-formed.
+ //
+ // -- for a non-type template-parameter of integral or
+ // enumeration type, integral promotions (4.5) and integral
+ // conversions (4.7) are applied.
+ QualType ParamType = Param->getType();
+ if (ParamType->isIntegralType() || ParamType->isEnumeralType()) {
+ QualType ArgType = Arg->getType();
+
+ // C++ [temp.arg.nontype]p1:
+ // A template-argument for a non-type, non-template
+ // template-parameter shall be one of:
+ //
+ // -- an integral constant-expression of integral or enumeration
+ // type; or
+ // -- the name of a non-type template-parameter; or
+ SourceLocation NonConstantLoc;
+ if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_integral_or_enumeral)
+ << ArgType << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ } else if (!Arg->isValueDependent() &&
+ !Arg->isIntegerConstantExpr(Context, &NonConstantLoc)) {
+ Diag(NonConstantLoc, diag::err_template_arg_not_ice)
+ << ArgType << Arg->getSourceRange();
+ return true;
+ }
+
+ // FIXME: We need some way to more easily get the unqualified form
+ // of the types without going all the way to the
+ // canonical type.
+ if (Context.getCanonicalType(ParamType).getCVRQualifiers())
+ ParamType = Context.getCanonicalType(ParamType).getUnqualifiedType();
+ if (Context.getCanonicalType(ArgType).getCVRQualifiers())
+ ArgType = Context.getCanonicalType(ArgType).getUnqualifiedType();
+
+ // Try to convert the argument to the parameter's type.
+ if (ParamType == ArgType) {
+ // Okay: no conversion necessary
+ } else if (IsIntegralPromotion(Arg, ArgType, ParamType) ||
+ !ParamType->isEnumeralType()) {
+ // This is an integral promotion or conversion.
+ ImpCastExprToType(Arg, ParamType);
+ } else {
+ // We can't perform this conversion.
+ Diag(Arg->getSourceRange().getBegin(),
+ diag::err_template_arg_not_convertible)
+ << Arg->getType() << Param->getType() << Arg->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+
+ return false;
+ }
+ // FIXME: p5 has a lot more checks to perform!
+
return false;
}
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=64256&r1=64255&r2=64256&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Feb 10 17:36:10 2009
@@ -835,3 +835,17 @@
return true;
}
+
+/// \brief Determine whether the given types are equivalent.
+bool Sema::hasSameType(QualType T1, QualType T2) {
+ return Context.getCanonicalType(T1) == Context.getCanonicalType(T2);
+}
+
+/// \brief Determine whether the given types are equivalent after
+/// cvr-qualifiers have been removed.
+bool Sema::hasSameUnqualifiedType(QualType T1, QualType T2) {
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+ return T1.getUnqualifiedType() == T2.getUnqualifiedType();
+}
+
Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=64256&r1=64255&r2=64256&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Tue Feb 10 17:36:10 2009
@@ -1,6 +1,5 @@
// RUN: clang -fsyntax-only -std=c++98 -verify %s
-
-template<int N> struct A; // expected-note 2{{template parameter is declared here}}
+template<int N> struct A; // expected-note 5{{template parameter is declared here}}
A<0> *a0;
@@ -10,5 +9,32 @@
A<1 >> 2> *a3;
-// FIXME: We haven't tried actually checking the expressions yet.
-// A<A> *a4;
+// C++ [temp.arg.nontype]p5:
+A<A> *a4; // expected-error{{must have an integral or enumeration type}} \
+ // FIXME: the error message above is a bit lame \
+ // FIXME: expected-error{{expected unqualified-id}}
+
+enum E { Enumerator = 17 };
+A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}}
+
+template<E Value> struct A1; // expected-note{{template parameter is declared here}}
+A1<Enumerator> *a6; // okay
+A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} \
+ // FIXME: expected-error{{expected unqualified-id}}
+
+const long LongValue = 12345678;
+A<LongValue> *a8;
+const short ShortValue = 17;
+A<ShortValue> *a9;
+
+int f(int);
+A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}} \
+ // FIXME: expected-error{{expected unqualified-id}}
+
+class X {
+public:
+ X(int, int);
+ operator int() const;
+};
+A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}} \
+ // FIXME:expected-error{{expected unqualified-id}}
More information about the cfe-commits
mailing list