From: Douglas Gregor Date: Wed, 11 Feb 2009 16:16:59 +0000 (+0000) Subject: Implement semantic checking for template arguments that correspond to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=658bbb5e8072ccd68b5ddc299d1b868aa047a746;p=clang Implement semantic checking for template arguments that correspond to pointer-to-member-data non-type template parameters. Also, get consistent about what it means to returned a bool from CheckTemplateArgument. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64305 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index eb7db25d6e..d816151ef2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -655,8 +655,8 @@ Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD, // Check that the template argument list is well-formed for this // template. - if (!CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, - TemplateArgs, TemplateArgLocs, RAngleLoc)) + if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, + TemplateArgs, TemplateArgLocs, RAngleLoc)) return 0; // Yes, all class template specializations are just silly sugar for @@ -730,7 +730,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (TemplateTypeParmDecl *TTP = dyn_cast(*Param)) { // Check template type parameters. if (!ArgType.isNull()) { - if (!CheckTemplateArgument(TTP, ArgType, ArgLoc)) + if (CheckTemplateArgument(TTP, ArgType, ArgLoc)) Invalid = true; continue; } @@ -749,7 +749,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, = dyn_cast(*Param)) { // Check non-type template parameters. if (ArgExpr) { - if (!CheckTemplateArgument(NTTP, ArgExpr)) + if (CheckTemplateArgument(NTTP, ArgExpr)) Invalid = true; continue; } @@ -778,7 +778,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (ArgExpr && isa(ArgExpr) && isa(cast(ArgExpr)->getDecl())) { - if (!CheckTemplateArgument(TempParm, cast(ArgExpr))) + if (CheckTemplateArgument(TempParm, cast(ArgExpr))) Invalid = true; continue; } @@ -1014,7 +1014,25 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // this. return false; } - // FIXME: p5 has a lot more checks to perform! + + // -- For a non-type template-parameter of type pointer to data + // member, qualification conversions (4.4) are applied. + assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); + + if (hasSameUnqualifiedType(ParamType, ArgType)) { + // Types match exactly: nothing more to do here. + } else if (IsQualificationConversion(ArgType, ParamType)) { + 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; + } + + // FIXME: Check the restrictions in p1. return false; } diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp index d62f681f39..0f69b5f4b1 100644 --- a/test/SemaTemplate/temp_arg.cpp +++ b/test/SemaTemplate/temp_arg.cpp @@ -8,6 +8,7 @@ template class X; A * a1; -A *a2; // expected-error{{too many template arguments for class template 'A'}} - -A *a3; // expected-error{{too few template arguments for class template 'A'}} +A *a2; // expected-error{{too many template arguments for class template 'A'}} \ + // expected-error{{unqualified-id}} +A *a3; // expected-error{{too few template arguments for class template 'A'}} \ + // expected-error{{unqualified-id}} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index f069accb63..63cfa8fac3 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -3,9 +3,11 @@ template struct A; // expected-note 5{{template parameter is declared her A<0> *a0; -A *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} +A *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} \ + // FIXME: expected-error{{unqualified-id}} -A *a2; // expected-error{{template argument for non-type template parameter must be an expression}} +A *a2; // expected-error{{template argument for non-type template parameter must be an expression}} \ + // FIXME: expected-error{{unqualified-id}} A<1 >> 2> *a3; @@ -15,8 +17,8 @@ A *a4; // expected-error{{must have an integral or enumeration type}} \ // FIXME: expected-error{{expected unqualified-id}} enum E { Enumerator = 17 }; -A *a5; // expected-error{{template argument for non-type template parameter must be an expression}} - +A *a5; // expected-error{{template argument for non-type template parameter must be an expression}} \ + // FIXME: expected-error{{unqualified-id}} template struct A1; // expected-note{{template parameter is declared here}} A1 *a6; // okay A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} \ @@ -96,9 +98,20 @@ struct Z { float bar(float); int bar(int); double baz(double); + + int int_member; + float float_member; }; template struct A6; // expected-note{{template parameter is declared here}} A6<&Z::foo> *a17_1; A6<&Z::bar> *a17_2; A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} \ // FIXME: expected-error{{expected unqualified-id}} + + +template struct A7; // expected-note{{template parameter is declared here}} +template struct A7c; +A7<&Z::int_member> *a18_1; +A7c<&Z::int_member> *a18_2; +A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} \ + // FIXME: expected-error{{unqualified-id}} diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp index 3e8e6f25ce..e1b9bb4874 100644 --- a/test/SemaTemplate/temp_arg_template.cpp +++ b/test/SemaTemplate/temp_arg_template.cpp @@ -35,7 +35,8 @@ template void f(int); // FIXME: we're right to provide an error message, but it should say // that we need a class template. We won't get this right until name // lookup of 'f' returns a TemplateDecl. -A *a9; // expected-error{{template argument for template template parameter must be a template}} +A *a9; // expected-error{{template argument for template template parameter must be a template}} \ + // expected-error{{unqualified-id}} // FIXME: The code below is ill-formed, because of the evil digraph '<:'. // We should provide a much better error message than we currently do. diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp index c755362884..36764fc8e4 100644 --- a/test/SemaTemplate/temp_arg_type.cpp +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -2,9 +2,11 @@ template class A; // expected-note 2 {{template parameter is declared here}} // [temp.arg.type]p1 -A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} +A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} \ + // expected-error{{unqualified-id}} -A *a2; // expected-error{{template argument for template type parameter must be a type}} +A *a2; // expected-error{{template argument for template type parameter must be a type}} \ + // expected-error{{unqualified-id}} A *a3; A *a4;