From b7a09260204f2079e0f998bf7ee52b95122a4c5d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 1 Apr 2010 18:32:35 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100125 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 11 + lib/Sema/Sema.h | 2 - lib/Sema/SemaOverload.cpp | 2 + lib/Sema/SemaTemplate.cpp | 417 +++++++++++------- .../CXX/temp/temp.arg/temp.arg.nontype/p1.cpp | 4 +- .../CXX/temp/temp.arg/temp.arg.nontype/p5.cpp | 80 +++- test/CXX/temp/temp.res/temp.local/p1.cpp | 3 +- test/SemaTemplate/instantiation-default-2.cpp | 2 +- test/SemaTemplate/temp_arg_nontype.cpp | 14 +- 9 files changed, 347 insertions(+), 188 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4e177fbb18..be00972dac 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1227,11 +1227,22 @@ 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_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< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 10b6746095..4d19bf7b26 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2920,8 +2920,6 @@ public: bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); - bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, - NamedDecl *&Entity); bool CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index be367c3660..bc10a58d6b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4991,6 +4991,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. llvm::SmallVector, 4> Matches; + llvm::SmallVector NonMatches; + bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 888fa062ea..40ec4bcb58 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2266,18 +2266,20 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, /// \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(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 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, // Ignore (and complain about) any excess parentheses. while (ParenExpr *Parens = dyn_cast(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 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, Arg = Parens->getSubExpr(); } + bool AddressTaken = false; + SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast(Arg)) { - if (UnOp->getOpcode() == UnaryOperator::AddrOf) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) { DRE = dyn_cast(UnOp->getSubExpr()); + AddressTaken = true; + AddrOpLoc = UnOp->getOperatorLoc(); + } } else DRE = dyn_cast(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(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_not_object_or_func_form) + if (!isa(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(DRE->getDecl())) - return Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_field) + if (FieldDecl *Field = dyn_cast(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(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(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(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(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()->getPointeeType()->isFunctionType() && + S.IsQualificationConversion(ArgType, ParamType)) { + // For pointer-to-object types, qualification conversions are + // permitted. + } else { + if (const ReferenceType *ParamRef = ParamType->getAs()) { + 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 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, while (ImplicitCastExpr *Cast = dyn_cast(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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // 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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // 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()->getPointeeType()->isFunctionType()) || // -- For a non-type template-parameter of type reference to @@ -2637,39 +2793,30 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // 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()->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 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentPointerToMember(Arg, Converted); } if (ParamType->isPointerType()) { @@ -2703,40 +2836,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getAs()->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(Entity->getCanonicalDecl()); - Converted = TemplateArgument(Entity); - } - return false; + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted); } if (const ReferenceType *ParamRefType = ParamType->getAs()) { @@ -2749,53 +2851,31 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, 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(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 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, 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 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 83365a2a08..14dace89a1 100644 --- a/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp @@ -49,9 +49,9 @@ namespace addr_of_obj_or_func { // -- a pointer to member expressed as described in 5.3.1. namespace bad_args { - template struct X0 { }; + template 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 x0b; // FIXME: This should not be accepted. + X0 x0b; // expected-error{{non-type template argument for template parameter of pointer type 'int *' must have its address taken}} } diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp index 458aff2f02..b0f1c46a52 100644 --- a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp @@ -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 struct X0 { }; + X0<17> x0i; + X0<'a'> x0c; + template 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 @@ namespace pointer_to_object_parameters { operator int() const; }; - template struct A2; + template struct A2; // expected-note{{template parameter is declared here}} X *X_ptr; X an_X; X array_of_Xs[10]; - A2 *a12; + A2 *a12; // expected-error{{must have its address taken}} A2 *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 @@ namespace pointer_to_object_parameters { template struct X2 { }; template struct X3 : X2 { }; struct X4 : X3<&X1v> { }; + + // PR6563 + int *bar; + template struct zed {}; // expected-note 2{{template parameter is declared here}} + void g(zed*); // expected-error{{must have its address taken}} + + int baz; + void g2(zed*); // 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 @@ namespace reference_parameters { bind(); // expected-note{{instantiation of}} } } + + namespace PR6749 { + template struct foo {}; // expected-note{{template parameter is declared here}} + int x, &y = x; + foo f; // expected-error{{is not an object}} + } } // -- For a non-type template-parameter of type pointer to function, the @@ -113,17 +137,69 @@ namespace reference_parameters { // 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 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); + void x0b(X0<&f>); + void x0c(X0); // 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); // 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 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); + void x0b(X0<&f>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}} + void x0c(X0); // 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); // 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 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 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 struct X1 {}; + X1<&Y::y> x1a; +} diff --git a/test/CXX/temp/temp.res/temp.local/p1.cpp b/test/CXX/temp/temp.res/temp.local/p1.cpp index ed534a4627..1ad4464c97 100644 --- a/test/CXX/temp/temp.res/temp.local/p1.cpp +++ b/test/CXX/temp/temp.res/temp.local/p1.cpp @@ -26,8 +26,7 @@ template struct X1 { // FIXME: Test this clause. int i = 42; -int* iptr = &i; void test() { X0 x0; (void)x0; - X1<42, i, iptr> x1; (void)x1; + X1<42, i, &i> x1; (void)x1; } diff --git a/test/SemaTemplate/instantiation-default-2.cpp b/test/SemaTemplate/instantiation-default-2.cpp index 4d6756eca3..5a744a0c38 100644 --- a/test/SemaTemplate/instantiation-default-2.cpp +++ b/test/SemaTemplate/instantiation-default-2.cpp @@ -13,6 +13,6 @@ Constant *c3; Constant *c4; Constant *c5; -Constant *c6; // expected-error{{non-type template argument of type 'float (*)(int, double)' cannot be converted to a value of type 'float (*)(int, int)'}} +Constant *c6; // expected-error{{non-type template argument of type 'float (int, double)' cannot be converted to a value of type 'float (*)(int, int)'}} Constant *c7; // expected-note{{while substituting}} diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index 51e12e994c..6e4f751d47 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -47,10 +47,8 @@ A3 *a14_1; A3<&h> *a14_2; A3 *a14_3; A3<&f> *a14_4; -A3

*a14_6; // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} -A3 *a14_7; // expected-error{{non-type template argument of type '' cannot be converted to a value of type 'int (*)(int)'}} -// FIXME: the first error includes the string , which makes Doug slightly unhappy. +A3

*a14_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (*)(int)'}} +A3 *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 @@ volatile X * X_volatile_ptr; template struct A4; // expected-note 2{{template parameter is declared here}} X an_X; A4 *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 *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 struct A5; // expected-note 2{{template parameter is declared here}} A5 *a16_1; A5 *a16_3; -A5

*a16_6; // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} -A5 *a14_7; // expected-error{{non-type template argument of type '' cannot be converted to a value of type 'int (&)(int)'}} -// FIXME: the first error includes the string , which makes Doug slightly unhappy. +A5

*a16_6; // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'float (float)'}} +A5 *a14_7; // expected-error{{overloaded function cannot be resolved to a non-type template parameter of type 'int (&)(int)'}} struct Z { int foo(int); -- 2.40.0