[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