aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2010-01-31 10:01:20 +0000
committerChandler Carruth <chandlerc@gmail.com>2010-01-31 10:01:20 +0000
commit038cc399940deefc0f55aad8be97312a7390e2ad (patch)
tree2b0474358c2757d2de936e38d346c4d9d146e17f
parent9db7dbb918ca49f4ee6c181e4917e7b6ec547353 (diff)
Fix PR6159 and several other problems with value-dependent non-type template
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/Sema/SemaTemplate.cpp40
-rw-r--r--test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp59
3 files changed, 86 insertions, 15 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 423988f47b..1f48cd75b1 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f660b3c2ee..44b0d83b46 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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;
}
diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index f9834dfed2..83365a2a08 100644
--- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -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.
}