diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 40 | ||||
-rw-r--r-- | test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp | 59 |
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. } |