]> granicus.if.org Git - clang/commitdiff
Fix PR6159 and several other problems with value-dependent non-type template
authorChandler Carruth <chandlerc@gmail.com>
Sun, 31 Jan 2010 10:01:20 +0000 (10:01 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sun, 31 Jan 2010 10:01:20 +0000 (10:01 +0000)
arguments. This both prevents meaningless checks on these arguments and ensures
that they are represented as an expression by the instantiation.

Cleaned up and added standard text to the relevant test case. Also started
adding tests for *rejected* cases. At least one FIXME here where (I think) we
allow something we shouldn't. More to come in the area of rejecting crazy
arguments with decent diagnostics. Suggestions welcome for still better
diagnostics on these errors!

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp

index 423988f47bdf205a90f2d3ad50663ab7290bd4aa..1f48cd75b1d63e8c901bb8a907806c5f9bd7a6a4 100644 (file)
@@ -1128,6 +1128,8 @@ def err_template_arg_no_ref_bind : Error<
 def err_template_arg_ref_bind_ignores_quals : Error<
   "reference binding of non-type template parameter of type %0 to template "
   "argument of type %1 ignores qualifiers">;
+def err_template_arg_not_decl_ref : Error<
+  "non-type template argument does not refer to any declaration">;
 def err_template_arg_not_object_or_func_form : Error<
   "non-type template argument does not directly refer to an object or "
   "function">;
index f660b3c2ee91d858a48f9f7a5a3e0d81010ea5c3..44b0d83b466cd863e1c8136cc3c0d4abf6e5000c 100644 (file)
@@ -2307,7 +2307,17 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
   } else
     DRE = dyn_cast<DeclRefExpr>(Arg);
 
-  if (!DRE || !isa<ValueDecl>(DRE->getDecl()))
+  if (!DRE)
+    return Diag(Arg->getSourceRange().getBegin(),
+                diag::err_template_arg_not_decl_ref)
+      << Arg->getSourceRange();
+
+  // Stop checking the precise nature of the argument if it is value dependent,
+  // it should be checked when instantiated.
+  if (Arg->isValueDependent())
+    return false;
+
+  if (!isa<ValueDecl>(DRE->getDecl()))
     return Diag(Arg->getSourceRange().getBegin(),
                 diag::err_template_arg_not_object_or_func_form)
       << Arg->getSourceRange();
@@ -2658,9 +2668,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    if (Entity)
-      Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-    Converted = TemplateArgument(Entity);
+    if (Arg->isValueDependent()) {
+      Converted = TemplateArgument(Arg);
+    } else {
+      if (Entity)
+        Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+      Converted = TemplateArgument(Entity);
+    }
     return false;
   }
 
@@ -2698,9 +2712,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    if (Entity)
-      Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-    Converted = TemplateArgument(Entity);
+    if (Arg->isValueDependent()) {
+      Converted = TemplateArgument(Arg);
+    } else {
+      if (Entity)
+        Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+      Converted = TemplateArgument(Entity);
+    }
     return false;
   }
 
@@ -2740,8 +2758,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-    Converted = TemplateArgument(Entity);
+    if (Arg->isValueDependent()) {
+      Converted = TemplateArgument(Arg);
+    } else {
+      Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
+      Converted = TemplateArgument(Entity);
+    }
     return false;
   }
 
index f9834dfed20d28da7936e0e3379bb15c21550f3d..83365a2a082c982ff4ba8bbfc011403299d7ed83 100644 (file)
@@ -1,10 +1,57 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-template <const int* p> struct X { };
+// C++0x [temp.arg.nontype]p1:
+//
+//   A template-argument for a non-type, non-template template-parameter shall
+//   be one of:
+//   -- an integral constant expression; or
+//   -- the name of a non-type template-parameter ; or
+namespace non_type_tmpl_param {
+  template <int N> struct X0 { X0(); };
+  template <int N> X0<N>::X0() { }
+  template <int* N> struct X1 { X1(); };
+  template <int* N> X1<N>::X1() { }
+  template <int& N> struct X3 { X3(); };
+  template <int& N> X3<N>::X3() { }
+  template <int (*F)(int)> struct X4 { X4(); };
+  template <int (*F)(int)> X4<F>::X4() { }
+  template <typename T, int (T::* M)(int)> struct X5 { X5(); };
+  template <typename T, int (T::* M)(int)> X5<T, M>::X5() { }
+}
+
+//   -- the address of an object or function with external linkage, including
+//      function templates and function template-ids but excluding non-static
+//      class members, expressed as & id-expression where the & is optional if
+//      the name refers to a function or array, or if the corresponding
+//      template-parameter is a reference; or
+namespace addr_of_obj_or_func {
+  template <int* p> struct X0 { };
+  template <int (*fp)(int)> struct X1 { };
+  // FIXME: Add reference template parameter tests.
+
+  int i = 42;
+  int iarr[10];
+  int f(int i);
+  template <typename T> T f_tmpl(T t);
+  void test() {
+    X0<&i> x0a;
+    X0<iarr> x0b;
+    X1<&f> x1a;
+    X1<f> x1b;
+    X1<f_tmpl> x1c;
+    X1<f_tmpl<int> > x1d;
+  }
+}
+
+//   -- a constant expression that evaluates to a null pointer value (4.10); or
+//   -- a constant expression that evaluates to a null member pointer value
+//      (4.11); or
+//   -- a pointer to member expressed as described in 5.3.1.
 
-int i = 42;
-int* iptr = &i;
-void test() {
-  X<&i> x1;
-  X<iptr> x2;
+namespace bad_args {
+  template <int* N> struct X0 { };
+  int i = 42;
+  X0<&i + 2> x0a; // expected-error{{non-type template argument does not refer to any declaration}}
+  int* iptr = &i;
+  X0<iptr> x0b; // FIXME: This should not be accepted.
 }