[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