[cfe-commits] r100125 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp test/CXX/temp/temp.res/temp.local/p1.cpp test/SemaTemplate/instantiation-default-2.cpp test/SemaTemplate/temp_arg_nontype.cpp

Douglas Gregor dgregor at apple.com
Thu Apr 1 11:32:35 PDT 2010


Author: dgregor
Date: Thu Apr  1 13:32:35 2010
New Revision: 100125

URL: http://llvm.org/viewvc/llvm-project?rev=100125&view=rev
Log:
Overhaul checking of non-type template arguments that should refer to
an object or function. Our previous checking was too lax, and ended up
allowing missing or extraneous address-of operators, among other
evils. The new checking provides better diagnostics and adheres more
closely to the standard.

Fixes PR6563 and PR6749.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
    cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
    cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp
    cfe/trunk/test/SemaTemplate/instantiation-default-2.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Apr  1 13:32:35 2010
@@ -1227,11 +1227,22 @@
 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_unresolved_overloaded_function : Error<
+  "overloaded function cannot be resolved to a non-type template parameter of "
+  "type %0">;
 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">;
+def err_template_arg_not_address_of : Error<
+  "non-type template argument for template parameter of pointer type %0 must "
+  "have its address taken">;
+def err_template_arg_address_of_non_pointer : Error<
+  "address taken in non-type template argument for template parameter of "
+  "reference type %0">;
+def err_template_arg_reference_var : Error<
+  "non-type template argument of reference type %0 is not an object">;
 def err_template_arg_field : Error<
   "non-type template argument refers to non-static data member %0">;
 def err_template_arg_method : Error<

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Apr  1 13:32:35 2010
@@ -2920,8 +2920,6 @@
 
   bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
                              TypeSourceInfo *Arg);
-  bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
-                                                      NamedDecl *&Entity);
   bool CheckTemplateArgumentPointerToMember(Expr *Arg, 
                                             TemplateArgument &Converted);
   bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param,

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Apr  1 13:32:35 2010
@@ -4991,6 +4991,8 @@
   // Look through all of the overloaded functions, searching for one
   // whose type matches exactly.
   llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches;
+  llvm::SmallVector<FunctionDecl *, 4> NonMatches;
+
   bool FoundNonTemplateFunction = false;
   for (UnresolvedSetIterator I = OvlExpr->decls_begin(),
          E = OvlExpr->decls_end(); I != E; ++I) {

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr  1 13:32:35 2010
@@ -2266,18 +2266,20 @@
 
 /// \brief Checks whether the given template argument is the address
 /// of an object or function according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
-                                                          NamedDecl *&Entity) {
+static bool 
+CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
+                                               NonTypeTemplateParmDecl *Param,
+                                               QualType ParamType,
+                                               Expr *ArgIn,
+                                               TemplateArgument &Converted) {
   bool Invalid = false;
+  Expr *Arg = ArgIn;
+  QualType ArgType = Arg->getType();
 
   // See through any implicit casts we added to fix the type.
   while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
     Arg = Cast->getSubExpr();
 
-  // C++0x allows nullptr, and there's no further checking to be done for that.
-  if (Arg->getType()->isNullPtrType())
-    return false;
-
   // C++ [temp.arg.nontype]p1:
   //
   //   A template-argument for a non-type, non-template
@@ -2294,8 +2296,8 @@
   // Ignore (and complain about) any excess parentheses.
   while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
     if (!Invalid) {
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_extra_parens)
+      S.Diag(Arg->getSourceRange().getBegin(),
+             diag::err_template_arg_extra_parens)
         << Arg->getSourceRange();
       Invalid = true;
     }
@@ -2303,77 +2305,227 @@
     Arg = Parens->getSubExpr();
   }
 
+  bool AddressTaken = false;
+  SourceLocation AddrOpLoc;
   if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) {
-    if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+    if (UnOp->getOpcode() == UnaryOperator::AddrOf) {
       DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr());
+      AddressTaken = true;
+      AddrOpLoc = UnOp->getOperatorLoc();
+    }
   } else
     DRE = dyn_cast<DeclRefExpr>(Arg);
 
-  if (!DRE)
-    return Diag(Arg->getSourceRange().getBegin(),
-                diag::err_template_arg_not_decl_ref)
-      << Arg->getSourceRange();
+  if (!DRE) {
+    if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) {
+      S.Diag(Arg->getLocStart(), 
+             diag::err_template_arg_unresolved_overloaded_function)
+        << ParamType << Arg->getSourceRange();
+    } else {
+      S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref)
+        << Arg->getSourceRange();
+    }
+    S.Diag(Param->getLocation(), diag::note_template_param_here);
+    return true;
+  }
 
   // Stop checking the precise nature of the argument if it is value dependent,
   // it should be checked when instantiated.
-  if (Arg->isValueDependent())
+  if (Arg->isValueDependent()) {
+    Converted = TemplateArgument(ArgIn->Retain());
     return false;
+  }
 
-  if (!isa<ValueDecl>(DRE->getDecl()))
-    return Diag(Arg->getSourceRange().getBegin(),
-                diag::err_template_arg_not_object_or_func_form)
+  if (!isa<ValueDecl>(DRE->getDecl())) {
+    S.Diag(Arg->getSourceRange().getBegin(),
+           diag::err_template_arg_not_object_or_func_form)
       << Arg->getSourceRange();
+    S.Diag(Param->getLocation(), diag::note_template_param_here);
+    return true;
+  }
+
+  NamedDecl *Entity = 0;
 
   // Cannot refer to non-static data members
-  if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl()))
-    return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
+  if (FieldDecl *Field = dyn_cast<FieldDecl>(DRE->getDecl())) {
+    S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field)
       << Field << Arg->getSourceRange();
+    S.Diag(Param->getLocation(), diag::note_template_param_here);
+    return true;
+  }
 
   // Cannot refer to non-static member functions
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(DRE->getDecl()))
-    if (!Method->isStatic())
-      return Diag(Arg->getSourceRange().getBegin(),
-                  diag::err_template_arg_method)
+    if (!Method->isStatic()) {
+      S.Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_method)
         << Method << Arg->getSourceRange();
+      S.Diag(Param->getLocation(), diag::note_template_param_here);
+      return true;
+    }
 
   // Functions must have external linkage.
   if (FunctionDecl *Func = dyn_cast<FunctionDecl>(DRE->getDecl())) {
     if (!isExternalLinkage(Func->getLinkage())) {
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_function_not_extern)
+      S.Diag(Arg->getSourceRange().getBegin(),
+             diag::err_template_arg_function_not_extern)
         << Func << Arg->getSourceRange();
-      Diag(Func->getLocation(), diag::note_template_arg_internal_object)
+      S.Diag(Func->getLocation(), diag::note_template_arg_internal_object)
         << true;
       return true;
     }
 
     // Okay: we've named a function with external linkage.
     Entity = Func;
-    return Invalid;
-  }
 
-  if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+    // If the template parameter has pointer type, the function decays.
+    if (ParamType->isPointerType() && !AddressTaken)
+      ArgType = S.Context.getPointerType(Func->getType());
+    else if (AddressTaken && ParamType->isReferenceType()) {
+      // If we originally had an address-of operator, but the
+      // parameter has reference type, complain and (if things look
+      // like they will work) drop the address-of operator.
+      if (!S.Context.hasSameUnqualifiedType(Func->getType(),
+                                            ParamType.getNonReferenceType())) {
+        S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+          << ParamType;
+        S.Diag(Param->getLocation(), diag::note_template_param_here);
+        return true;
+      }
+
+      S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+        << ParamType
+        << FixItHint::CreateRemoval(AddrOpLoc);
+      S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+      ArgType = Func->getType();
+    }
+  } else if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
     if (!isExternalLinkage(Var->getLinkage())) {
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_object_not_extern)
+      S.Diag(Arg->getSourceRange().getBegin(),
+             diag::err_template_arg_object_not_extern)
         << Var << Arg->getSourceRange();
-      Diag(Var->getLocation(), diag::note_template_arg_internal_object)
+      S.Diag(Var->getLocation(), diag::note_template_arg_internal_object)
         << true;
       return true;
     }
 
+    // A value of reference type is not an object.
+    if (Var->getType()->isReferenceType()) {
+      S.Diag(Arg->getSourceRange().getBegin(), 
+             diag::err_template_arg_reference_var)
+        << Var->getType() << Arg->getSourceRange();
+      S.Diag(Param->getLocation(), diag::note_template_param_here);
+      return true;
+    }
+
     // Okay: we've named an object with external linkage
     Entity = Var;
-    return Invalid;
-  }
 
-  // We found something else, but we don't know specifically what it is.
-  Diag(Arg->getSourceRange().getBegin(),
-       diag::err_template_arg_not_object_or_func)
+    // If the template parameter has pointer type, we must have taken
+    // the address of this object.
+    if (ParamType->isReferenceType()) {
+      if (AddressTaken) {
+        // If we originally had an address-of operator, but the
+        // parameter has reference type, complain and (if things look
+        // like they will work) drop the address-of operator.
+        if (!S.Context.hasSameUnqualifiedType(Var->getType(),
+                                            ParamType.getNonReferenceType())) {
+          S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+            << ParamType;
+          S.Diag(Param->getLocation(), diag::note_template_param_here);
+          return true;
+        }
+
+        S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer)
+          << ParamType
+          << FixItHint::CreateRemoval(AddrOpLoc);
+        S.Diag(Param->getLocation(), diag::note_template_param_here);
+
+        ArgType = Var->getType();
+      }
+    } else if (!AddressTaken && ParamType->isPointerType()) {
+      if (Var->getType()->isArrayType()) {
+        // Array-to-pointer decay.
+        ArgType = S.Context.getArrayDecayedType(Var->getType());
+      } else {
+        // If the template parameter has pointer type but the address of
+        // this object was not taken, complain and (possibly) recover by
+        // taking the address of the entity.
+        ArgType = S.Context.getPointerType(Var->getType());
+        if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) {
+          S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+            << ParamType;
+          S.Diag(Param->getLocation(), diag::note_template_param_here);
+          return true;
+        }
+
+        S.Diag(Arg->getLocStart(), diag::err_template_arg_not_address_of)
+          << ParamType
+          << FixItHint::CreateInsertion(Arg->getLocStart(), "&");
+
+        S.Diag(Param->getLocation(), diag::note_template_param_here);
+      }
+    }
+  } else {
+    // We found something else, but we don't know specifically what it is.
+    S.Diag(Arg->getSourceRange().getBegin(),
+           diag::err_template_arg_not_object_or_func)
       << Arg->getSourceRange();
-  Diag(DRE->getDecl()->getLocation(),
-       diag::note_template_arg_refers_here);
-  return true;
+    S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here);
+    return true;
+  }
+
+  if (ParamType->isPointerType() && 
+      !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+      S.IsQualificationConversion(ArgType, ParamType)) {
+    // For pointer-to-object types, qualification conversions are
+    // permitted.
+  } else {
+    if (const ReferenceType *ParamRef = ParamType->getAs<ReferenceType>()) {
+      if (!ParamRef->getPointeeType()->isFunctionType()) {
+        // C++ [temp.arg.nontype]p5b3:
+        //   For a non-type template-parameter of type reference to
+        //   object, no conversions apply. The type referred to by the
+        //   reference may be more cv-qualified than the (otherwise
+        //   identical) type of the template- argument. The
+        //   template-parameter is bound directly to the
+        //   template-argument, which shall be an lvalue.
+
+        // FIXME: Other qualifiers?
+        unsigned ParamQuals = ParamRef->getPointeeType().getCVRQualifiers();
+        unsigned ArgQuals = ArgType.getCVRQualifiers();
+
+        if ((ParamQuals | ArgQuals) != ParamQuals) {
+          S.Diag(Arg->getSourceRange().getBegin(),
+                 diag::err_template_arg_ref_bind_ignores_quals)
+            << ParamType << Arg->getType()
+            << Arg->getSourceRange();
+          S.Diag(Param->getLocation(), diag::note_template_param_here);
+          return true;
+        }     
+      }
+    }
+
+    // At this point, the template argument refers to an object or
+    // function with external linkage. We now need to check whether the
+    // argument and parameter types are compatible.
+    if (!S.Context.hasSameUnqualifiedType(ArgType,
+                                          ParamType.getNonReferenceType())) {
+      // We can't perform this conversion or binding.
+      if (ParamType->isReferenceType())
+        S.Diag(Arg->getLocStart(), diag::err_template_arg_no_ref_bind)
+          << ParamType << Arg->getType() << Arg->getSourceRange();
+      else
+        S.Diag(Arg->getLocStart(),  diag::err_template_arg_not_convertible)
+          << Arg->getType() << ParamType << Arg->getSourceRange();
+      S.Diag(Param->getLocation(), diag::note_template_param_here);
+      return true;
+    }
+  }
+
+  // Create the template argument.
+  Converted = TemplateArgument(Entity->getCanonicalDecl());
+  return false;
 }
 
 /// \brief Checks whether the given template argument is a pointer to
@@ -2386,10 +2538,6 @@
   while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
     Arg = Cast->getSubExpr();
 
-  // C++0x allows nullptr, and there's no further checking to be done for that.
-  if (Arg->getType()->isNullPtrType())
-    return false;
-
   // C++ [temp.arg.nontype]p1:
   //
   //   A template-argument for a non-type, non-template
@@ -2482,7 +2630,6 @@
 
   // If either the parameter has a dependent type or the argument is
   // type-dependent, there's nothing we can check now.
-  // FIXME: Add template argument to Converted!
   if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
     // FIXME: Produce a cloned, canonical expression?
     Converted = TemplateArgument(Arg);
@@ -2616,6 +2763,16 @@
 
   DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction
 
+  // C++0x [temp.arg.nontype]p5 bullets 2, 4 and 6 permit conversion
+  // from a template argument of type std::nullptr_t to a non-type
+  // template parameter of type pointer to object, pointer to
+  // function, or pointer-to-member, respectively.
+  if (ArgType->isNullPtrType() && 
+      (ParamType->isPointerType() || ParamType->isMemberPointerType())) {
+    Converted = TemplateArgument((NamedDecl *)0);
+    return false;
+  }
+
   // Handle pointer-to-function, reference-to-function, and
   // pointer-to-member-function all in (roughly) the same way.
   if (// -- For a non-type template-parameter of type pointer to
@@ -2623,7 +2780,6 @@
       //    applied. If the template-argument represents a set of
       //    overloaded functions (or a pointer to such), the matching
       //    function is selected from the set (13.4).
-      // In C++0x, any std::nullptr_t value can be converted.
       (ParamType->isPointerType() &&
        ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
       // -- For a non-type template-parameter of type reference to
@@ -2637,39 +2793,30 @@
       //    template-argument represents a set of overloaded member
       //    functions, the matching member function is selected from
       //    the set (13.4).
-      // Again, C++0x allows a std::nullptr_t value.
       (ParamType->isMemberPointerType() &&
        ParamType->getAs<MemberPointerType>()->getPointeeType()
          ->isFunctionType())) {
-    if (Context.hasSameUnqualifiedType(ArgType,
-                                       ParamType.getNonReferenceType())) {
-      // We don't have to do anything: the types already match.
-    } else if (ArgType->isNullPtrType() && (ParamType->isPointerType() ||
-                 ParamType->isMemberPointerType())) {
-      ArgType = ParamType;
-      if (ParamType->isMemberPointerType())
-        ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
-      else
-        ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
-    } else if (ArgType->isFunctionType() && ParamType->isPointerType()) {
-      ArgType = Context.getPointerType(ArgType);
-      ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
-    } else if (FunctionDecl *Fn
-                 = ResolveAddressOfOverloadedFunction(Arg, ParamType, true,
-                                                      FoundResult)) {
+
+    if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, 
+                                                              true,
+                                                              FoundResult)) {
       if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
         return true;
 
       Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
       ArgType = Arg->getType();
-      if (ArgType->isFunctionType() && ParamType->isPointerType()) {
-        ArgType = Context.getPointerType(Arg->getType());
-        ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay);
-      }
     }
 
-    if (!Context.hasSameUnqualifiedType(ArgType,
-                                        ParamType.getNonReferenceType())) {
+    if (!ParamType->isMemberPointerType())
+      return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param,
+                                                            ParamType, 
+                                                            Arg, Converted);
+
+    if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType())) {
+      ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+                        Arg->isLvalue(Context) == Expr::LV_Valid);
+    } else if (!Context.hasSameUnqualifiedType(ArgType,
+                                           ParamType.getNonReferenceType())) {
       // We can't perform this conversion.
       Diag(Arg->getSourceRange().getBegin(),
            diag::err_template_arg_not_convertible)
@@ -2678,21 +2825,7 @@
       return true;
     }
 
-    if (ParamType->isMemberPointerType())
-      return CheckTemplateArgumentPointerToMember(Arg, Converted);
-
-    NamedDecl *Entity = 0;
-    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
-      return true;
-
-    if (Arg->isValueDependent()) {
-      Converted = TemplateArgument(Arg);
-    } else {
-      if (Entity)
-        Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-      Converted = TemplateArgument(Entity);
-    }
-    return false;
+    return CheckTemplateArgumentPointerToMember(Arg, Converted);
   }
 
   if (ParamType->isPointerType()) {
@@ -2703,40 +2836,9 @@
     assert(ParamType->getAs<PointerType>()->getPointeeType()->isObjectType() &&
            "Only object pointers allowed here");
 
-    if (ArgType->isNullPtrType()) {
-      ArgType = ParamType;
-      ImpCastExprToType(Arg, ParamType, CastExpr::CK_BitCast);
-    } else if (ArgType->isArrayType()) {
-      ArgType = Context.getArrayDecayedType(ArgType);
-      ImpCastExprToType(Arg, ArgType, CastExpr::CK_ArrayToPointerDecay);
-    }
-
-    if (IsQualificationConversion(ArgType, ParamType)) {
-      ArgType = ParamType;
-      ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
-    }
-
-    if (!Context.hasSameUnqualifiedType(ArgType, ParamType)) {
-      // We can't perform this conversion.
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_not_convertible)
-        << Arg->getType() << InstantiatedParamType << Arg->getSourceRange();
-      Diag(Param->getLocation(), diag::note_template_param_here);
-      return true;
-    }
-
-    NamedDecl *Entity = 0;
-    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
-      return true;
-
-    if (Arg->isValueDependent()) {
-      Converted = TemplateArgument(Arg);
-    } else {
-      if (Entity)
-        Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-      Converted = TemplateArgument(Entity);
-    }
-    return false;
+    return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, 
+                                                          ParamType,
+                                                          Arg, Converted);
   }
 
   if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) {
@@ -2749,53 +2851,31 @@
     assert(ParamRefType->getPointeeType()->isObjectType() &&
            "Only object references allowed here");
 
-    QualType ReferredType = ParamRefType->getPointeeType();
-    if (!Context.hasSameUnqualifiedType(ReferredType, ArgType)) {
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_no_ref_bind)
-        << InstantiatedParamType << Arg->getType()
-        << Arg->getSourceRange();
-      Diag(Param->getLocation(), diag::note_template_param_here);
-      return true;
-    }
-
-    unsigned ParamQuals
-      = Context.getCanonicalType(ReferredType).getCVRQualifiers();
-    unsigned ArgQuals = Context.getCanonicalType(ArgType).getCVRQualifiers();
+    if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, 
+                                               ParamRefType->getPointeeType(), 
+                                                              true,
+                                                              FoundResult)) {
+      if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+        return true;
 
-    if ((ParamQuals | ArgQuals) != ParamQuals) {
-      Diag(Arg->getSourceRange().getBegin(),
-           diag::err_template_arg_ref_bind_ignores_quals)
-        << InstantiatedParamType << Arg->getType()
-        << Arg->getSourceRange();
-      Diag(Param->getLocation(), diag::note_template_param_here);
-      return true;
+      Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn);
+      ArgType = Arg->getType();
     }
 
-    NamedDecl *Entity = 0;
-    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
-      return true;
-
-    if (Arg->isValueDependent()) {
-      Converted = TemplateArgument(Arg);
-    } else {
-      Entity = cast<NamedDecl>(Entity->getCanonicalDecl());
-      Converted = TemplateArgument(Entity);
-    }
-    return false;
+    return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, 
+                                                          ParamType,
+                                                          Arg, Converted);
   }
 
   //     -- For a non-type template-parameter of type pointer to data
   //        member, qualification conversions (4.4) are applied.
-  // C++0x allows std::nullptr_t values.
   assert(ParamType->isMemberPointerType() && "Only pointers to members remain");
 
   if (Context.hasSameUnqualifiedType(ParamType, ArgType)) {
     // Types match exactly: nothing more to do here.
-  } else if (ArgType->isNullPtrType()) {
-    ImpCastExprToType(Arg, ParamType, CastExpr::CK_NullToMemberPointer);
   } else if (IsQualificationConversion(ArgType, ParamType)) {
-    ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp);
+    ImpCastExprToType(Arg, ParamType, CastExpr::CK_NoOp,
+                      Arg->isLvalue(Context) == Expr::LV_Valid);
   } else {
     // We can't perform this conversion.
     Diag(Arg->getSourceRange().getBegin(),
@@ -2893,29 +2973,26 @@
   
   QualType T = VD->getType().getNonReferenceType();
   if (ParamType->isPointerType()) {
-    // C++03 [temp.arg.nontype]p5:
-    //  - For a non-type template-parameter of type pointer to
-    //    object, qualification conversions and the array-to-pointer
-    //    conversion are applied.
-    //  - For a non-type template-parameter of type pointer to
-    //    function, only the function-to-pointer conversion is
-    //    applied.
+    // When the non-type template parameter is a pointer, take the
+    // address of the declaration.
     OwningExprResult RefExpr = BuildDeclRefExpr(VD, T, Loc);
     if (RefExpr.isInvalid())
       return ExprError();
-    
-    // Decay functions and arrays.
-    Expr *RefE = (Expr *)RefExpr.get();
-    DefaultFunctionArrayConversion(RefE);
-    if (RefE != RefExpr.get()) {
-      RefExpr.release();
-      RefExpr = Owned(RefE);
+
+    if (T->isFunctionType() || T->isArrayType()) {
+      // Decay functions and arrays.
+      Expr *RefE = (Expr *)RefExpr.get();
+      DefaultFunctionArrayConversion(RefE);
+      if (RefE != RefExpr.get()) {
+        RefExpr.release();
+        RefExpr = Owned(RefE);
+      }
+
+      return move(RefExpr);
     }
     
-    // Qualification conversions.
-    RefExpr.release();
-    ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CastExpr::CK_NoOp);
-    return Owned(RefE);
+    // Take the address of everything else
+    return CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr));
   }
 
   // If the non-type template parameter has reference type, qualify the

Modified: cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp Thu Apr  1 13:32:35 2010
@@ -49,9 +49,9 @@
 //   -- a pointer to member expressed as described in 5.3.1.
 
 namespace bad_args {
-  template <int* N> struct X0 { };
+  template <int* N> struct X0 { }; // expected-note 2{{template parameter is declared here}}
   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.
+  X0<iptr> x0b; // expected-error{{non-type template argument for template parameter of pointer type 'int *' must have its address taken}}
 }

Modified: cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp Thu Apr  1 13:32:35 2010
@@ -7,6 +7,14 @@
 //   program is ill-formed.
 //     -- for a non-type template-parameter of integral or enumeration type,
 //        integral promotions (4.5) and integral conversions (4.7) are applied.
+namespace integral_parameters {
+  template<short s> struct X0 { };
+  X0<17> x0i;
+  X0<'a'> x0c;
+  template<char c> struct X1 { };
+  X1<100l> x1l;
+}
+
 //     -- for a non-type template-parameter of type pointer to object,
 //        qualification conversions (4.4) and the array-to-pointer conversion
 //        (4.2) are applied; if the template-argument is of type
@@ -37,12 +45,12 @@
     operator int() const;
   };
   
-  template<X const *Ptr> struct A2;
+  template<X const *Ptr> struct A2; // expected-note{{template parameter is declared here}}
   
   X *X_ptr;
   X an_X;
   X array_of_Xs[10];
-  A2<X_ptr> *a12;
+  A2<X_ptr> *a12; // expected-error{{must have its address taken}}
   A2<array_of_Xs> *a13;
   A2<&an_X> *a13_2;
   A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
@@ -52,6 +60,16 @@
   template <X1*> struct X2 { };
   template <X1* Value> struct X3 : X2<Value> { };
   struct X4 : X3<&X1v> { };
+
+  // PR6563
+  int *bar;
+  template <int *> struct zed {}; // expected-note 2{{template parameter is declared here}}
+  void g(zed<bar>*); // expected-error{{must have its address taken}}
+
+  int baz;
+  void g2(zed<baz>*); // expected-error{{must have its address taken}}
+
+  void g3(zed<&baz>*); // okay
 }
 
 //     -- For a non-type template-parameter of type reference to object, no
@@ -105,6 +123,12 @@
       bind<int, counter>(); // expected-note{{instantiation of}}
     }
   }
+
+  namespace PR6749 {
+    template <int& i> struct foo {}; // expected-note{{template parameter is declared here}}
+    int x, &y = x;
+    foo<y> f; // expected-error{{is not an object}}
+  }
 }
 
 //     -- For a non-type template-parameter of type pointer to function, the
@@ -113,17 +137,69 @@
 //        conversion (4.10) is applied. If the template-argument represents
 //        a set of overloaded functions (or a pointer to such), the matching
 //        function is selected from the set (13.4).
+namespace pointer_to_function {
+  template<int (*)(int)> struct X0 { }; // expected-note 3{{template parameter is declared here}}
+  int f(int);
+  int f(float);
+  int g(float);
+  int (*funcptr)(int);
+  void x0a(X0<f>);
+  void x0b(X0<&f>);
+  void x0c(X0<g>); // expected-error{{non-type template argument of type 'int (float)' cannot be converted to a value of type 'int (*)(int)'}}
+  void x0d(X0<&g>); // expected-error{{non-type template argument of type 'int (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
+  void x0e(X0<funcptr>); // expected-error{{must have its address taken}}
+}
+
 //     -- For a non-type template-parameter of type reference to function, no
 //        conversions apply. If the template-argument represents a set of
 //        overloaded functions, the matching function is selected from the set
 //        (13.4).
+namespace reference_to_function {
+  template<int (&)(int)> struct X0 { }; // expected-note 4{{template parameter is declared here}}
+  int f(int);
+  int f(float);
+  int g(float);
+  int (*funcptr)(int);
+  void x0a(X0<f>);
+  void x0b(X0<&f>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
+  void x0c(X0<g>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (float)'}}
+  void x0d(X0<&g>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
+  void x0e(X0<funcptr>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (*)(int)'}}
+}
 //     -- For a non-type template-parameter of type pointer to member function,
 //        if the template-argument is of type std::nullptr_t, the null member
 //        pointer conversion (4.11) is applied; otherwise, no conversions
 //        apply. If the template-argument represents a set of overloaded member
 //        functions, the matching member function is selected from the set
 //        (13.4).
+namespace pointer_to_member_function {
+  struct X { };
+  struct Y : X { 
+    int f(int);
+    int g(int);
+    int g(float);
+    float h(float);
+  };
+
+  template<int (Y::*)(int)> struct X0 {}; // expected-note{{template parameter is declared here}}
+  X0<&Y::f> x0a;
+  X0<&Y::g> x0b;
+  X0<&Y::h> x0c; // expected-error{{non-type template argument of type 'float (pointer_to_member_function::Y::*)(float)' cannot be converted to a value of type 'int (pointer_to_member_function::Y::*)(int)'}}
+}
+
 //     -- For a non-type template-parameter of type pointer to data member,
 //        qualification conversions (4.4) are applied; if the template-argument
 //        is of type std::nullptr_t, the null member pointer conversion (4.11)
 //        is applied.
+namespace pointer_to_member_data {
+  struct X { int x; };
+  struct Y : X { int y; };
+
+  template<int Y::*> struct X0 {}; // expected-note{{template parameter is declared here}}
+  X0<&Y::y> x0a;
+  X0<&Y::x> x0b;  // expected-error{{non-type template argument of type 'int pointer_to_member_data::X::*' cannot be converted to a value of type 'int pointer_to_member_data::Y::*'}}
+
+  // Test qualification conversions
+  template<const int Y::*> struct X1 {};
+  X1<&Y::y> x1a;
+}

Modified: cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p1.cpp Thu Apr  1 13:32:35 2010
@@ -26,8 +26,7 @@
 // FIXME: Test this clause.
 
 int i = 42;
-int* iptr = &i;
 void test() {
   X0<int> x0; (void)x0;
-  X1<42, i, iptr> x1; (void)x1;
+  X1<42, i, &i> x1; (void)x1;
 }

Modified: cfe/trunk/test/SemaTemplate/instantiation-default-2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-default-2.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiation-default-2.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiation-default-2.cpp Thu Apr  1 13:32:35 2010
@@ -13,6 +13,6 @@
 Constant<float (*)(int, double), f> *c4;
 Constant<float (*)(int, double), &f> *c5;
 
-Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
+Constant<float (*)(int, int), f> *c6; // expected-error{{non-type template argument of type 'float (int, double)' cannot be converted to a value of type 'float (*)(int, int)'}}
 
 Constant<float, 0> *c7; // expected-note{{while substituting}}

Modified: cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp?rev=100125&r1=100124&r2=100125&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Thu Apr  1 13:32:35 2010
@@ -47,10 +47,8 @@
 A3<&h> *a14_2;
 A3<f> *a14_3;
 A3<&f> *a14_4;
-A3<h2> *a14_6;  // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
-A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}
-// FIXME: the first error includes the string <overloaded function
-// type>, which makes Doug slightly unhappy.
+A3<h2> *a14_6;  // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (*)(int)'}}
+A3<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (*)(int)'}}
 
 
 struct Y { } y;
@@ -59,17 +57,15 @@
 template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
 X an_X;
 A4<an_X> *a15_1; // okay
-A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'X const &' to template argument of type 'X volatile' ignores qualifiers}}
+A4<*X_volatile_ptr> *a15_2; // expected-error{{non-type template argument does not refer to any declaration}}
 A4<y> *15_3; //  expected-error{{non-type template parameter of reference type 'X const &' cannot bind to template argument of type 'struct Y'}} \
             // FIXME: expected-error{{expected unqualified-id}}
 
 template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
 A5<h> *a16_1;
 A5<f> *a16_3;
-A5<h2> *a16_6;  // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}}
-A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}
-// FIXME: the first error includes the string <overloaded function
-// type>, which makes Doug slightly unhappy.
+A5<h2> *a16_6;  // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'float (float)'}}
+A5<g> *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (&)(int)'}}
 
 struct Z {
   int foo(int);





More information about the cfe-commits mailing list