]> granicus.if.org Git - clang/commitdiff
Add type-checking and implicit conversions for template parameters of
authorDouglas Gregor <dgregor@apple.com>
Tue, 10 Feb 2009 23:36:10 +0000 (23:36 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 10 Feb 2009 23:36:10 +0000 (23:36 +0000)
integral or enumeration type.

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

include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaType.cpp
test/SemaTemplate/temp_arg_nontype.cpp

index 5dfe9d6f35b7fdcd7e2161a2bec402305a5e7e27..a4aa94982247a5057e711457239c9f716ddfcb5f 100644 (file)
@@ -525,6 +525,12 @@ DIAG(note_template_arg_refers_here, NOTE,
      "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")
index 669fd9258408b2ca14c821dc22c7221576e96929..5ee14faaca7ba6d8851812eb855f4b3506b8e715 100644 (file)
@@ -281,6 +281,9 @@ public:
                               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 @@ public:
 
   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,
index 5eb2b2145c96dedbf9dea680eb300b2d5a3081bc..7aab4a585e099e08d05437898833ca6d832e73eb 100644 (file)
@@ -827,7 +827,75 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
 /// 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;
 }
 
index e898782f31d80c0f97c3caf47e4ba16217f18245..7049a301f72b804d9537293233b30ceb78f9a9d5 100644 (file)
@@ -835,3 +835,17 @@ bool Sema::DiagnoseIncompleteType(SourceLocation Loc, QualType T, unsigned diag,
 
   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();
+}
+
index 8cbede4cd0d354ae03a9ebfce33e17493bef1314..46d92c537b106ac1a493c5cbafd74e76aa5e61f9 100644 (file)
@@ -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<int> *a2; // expected-error{{template argument for non-type template parameter
 
 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}}