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!

llvm-svn: 94953
This commit is contained in:
Chandler Carruth 2010-01-31 10:01:20 +00:00
parent 7ae2d7758f
commit 724a8a1fef
3 changed files with 87 additions and 16 deletions

View 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">;

View 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;
}

View File

@ -1,10 +1,57 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
template <const int* p> struct X { };
int i = 42;
int* iptr = &i;
void test() {
X<&i> x1;
X<iptr> x2;
// 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.
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.
}