]> granicus.if.org Git - clang/commitdiff
Implement semantic checking for template arguments that correspond to
authorDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 16:16:59 +0000 (16:16 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 11 Feb 2009 16:16:59 +0000 (16:16 +0000)
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

lib/Sema/SemaTemplate.cpp
test/SemaTemplate/temp_arg.cpp
test/SemaTemplate/temp_arg_nontype.cpp
test/SemaTemplate/temp_arg_template.cpp
test/SemaTemplate/temp_arg_type.cpp

index eb7db25d6ef336d0a232842fb152d67c7da5fc1f..d816151ef270a3cb52bcb270f926ebe798205ef4 100644 (file)
@@ -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<TemplateTypeParmDecl>(*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<NonTypeTemplateParmDecl>(*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<DeclRefExpr>(ArgExpr) &&
           isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
-        if (!CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
+        if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(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;
 }
index d62f681f3934c1ba41a4c3ef5a38dc2c5c76385f..0f69b5f4b1aa6cb784ef887a4ef946549ed71228 100644 (file)
@@ -8,6 +8,7 @@ template<typename> class X;
 
 A<int, 0, X> * a1;
 
-A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
-
-A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
+A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} \
+          // expected-error{{unqualified-id}}
+A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} \
+          // expected-error{{unqualified-id}}
index f069accb63b5a7d01f6bf919838d1f166e42828c..63cfa8fac31384ad45061adc3919ee84f5b3095d 100644 (file)
@@ -3,9 +3,11 @@ template<int N> struct A; // expected-note 5{{template parameter is declared her
 
 A<0> *a0;
 
-A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}}
+A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} \
+              // FIXME: expected-error{{unqualified-id}}
 
-A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}}
+A<int> *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<A> *a4; // expected-error{{must have an integral or enumeration type}} \
           // FIXME: expected-error{{expected unqualified-id}}
 
 enum E { Enumerator = 17 };
-A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}}
-
+A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}} \
+          // FIXME: expected-error{{unqualified-id}}
 template<E Value> struct A1; // expected-note{{template parameter is declared here}}
 A1<Enumerator> *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<int (Z::*pmf)(int)> 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<int Z::*pm> struct A7;  // expected-note{{template parameter is declared here}}
+template<int Z::*pm> 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}}
index 3e8e6f25ceae9e202bcf848469ce43247c229870..e1b9bb4874f791367ea5bd2c8081ae7f962817cd 100644 (file)
@@ -35,7 +35,8 @@ template<typename T> 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<f> *a9; // expected-error{{template argument for template template parameter must be a template}}
+A<f> *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.
index c75536288447060bd1ad8440e731284ff676488a..36764fc8e43b6555ed2507536cdadfa5f9d62a4b 100644 (file)
@@ -2,9 +2,11 @@
 template<typename T> 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<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
+A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} \
+          // expected-error{{unqualified-id}}
 
 A<int> *a3;
 A<int()> *a4;