Author: David L. Jones Date: 2019-12-04T22:12:15-08:00 New Revision: 93cc9dddd82f9e971f382ade6acf6634c5914966
URL: https://github.com/llvm/llvm-project/commit/93cc9dddd82f9e971f382ade6acf6634c5914966 DIFF: https://github.com/llvm/llvm-project/commit/93cc9dddd82f9e971f382ade6acf6634c5914966.diff LOG: Revert "Properly convert all declaration non-type template arguments when" This reverts commit 11d10527852b4d3ed738aa90d8bec0f398160593. This change is problematic with function pointer template parameters. For example, building libcxxabi with futexes (-D_LIBCXXABI_USE_FUTEX) produces this diagnostic: In file included from .../llvm-project/libcxxabi/src/cxa_guard.cpp:15: .../llvm-project/libcxxabi/src/cxa_guard_impl.h:416:54: error: address of function 'PlatformThreadID' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] has_thread_id_support(this->thread_id_address && GetThreadIDArg), ~~ ^~~~~~~~~~~~~~ .../llvm-project/libcxxabi/src/cxa_guard.cpp:38:26: note: in instantiation of member function '__cxxabiv1::(anonymous namespace)::InitByteFutex<&__cxxabiv1::(anonymous namespace)::PlatformFutexWait, &__cxxabiv1::(anonymous namespace)::PlatformFutexWake, &__cxxabiv1::(anonymous namespace)::PlatformThreadID>::InitByteFutex' requested here SelectedImplementation imp(raw_guard_object); ^ .../llvm-project/libcxxabi/src/cxa_guard_impl.h:416:54: note: prefix with the address-of operator to silence this warning has_thread_id_support(this->thread_id_address && GetThreadIDArg), ^ & 1 error generated. The diagnostic is incorrect: adding the address-of operator also fails ("cannot take the address of an rvalue of type 'uint32_t (*)()' (aka 'unsigned int (*)()')"). Added: Modified: clang/lib/Sema/SemaTemplate.cpp clang/test/SemaCXX/exceptions-seh.cpp clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 85240e1aeec8..e800f7fe7424 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6968,77 +6968,100 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, ValueDecl *VD = Arg.getAsDecl(); - CXXScopeSpec SS; - if (ParamType->isMemberPointerType()) { - // If this is a pointer to member, we need to use a qualified name to - // form a suitable pointer-to-member constant. - assert(VD->getDeclContext()->isRecord() && - (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || - isa<IndirectFieldDecl>(VD))); - QualType ClassType - = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); - NestedNameSpecifier *Qualifier - = NestedNameSpecifier::Create(Context, nullptr, false, - ClassType.getTypePtr()); - SS.MakeTrivial(Context, Qualifier, Loc); - } - - ExprResult RefExpr = BuildDeclarationNameExpr( - SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD); - if (RefExpr.isInvalid()) - return ExprError(); + if (VD->getDeclContext()->isRecord() && + (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || + isa<IndirectFieldDecl>(VD))) { + // If the value is a class member, we might have a pointer-to-member. + // Determine whether the non-type template template parameter is of + // pointer-to-member type. If so, we need to build an appropriate + // expression for a pointer-to-member, since a "normal" DeclRefExpr + // would refer to the member itself. + if (ParamType->isMemberPointerType()) { + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(Context, nullptr, false, + ClassType.getTypePtr()); + CXXScopeSpec SS; + SS.MakeTrivial(Context, Qualifier, Loc); + + // The actual value-ness of this is unimportant, but for + // internal consistency's sake, references to instance methods + // are r-values. + ExprValueKind VK = VK_LValue; + if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance()) + VK = VK_RValue; + + ExprResult RefExpr = BuildDeclRefExpr(VD, + VD->getType().getNonReferenceType(), + VK, + Loc, + &SS); + if (RefExpr.isInvalid()) + return ExprError(); - // For a pointer, the argument declaration is the pointee. Take its address. - QualType T = RefExpr.get()->getType(); - bool ObjCLifetimeConversion; - if (ParamType->isPointerType() && - (T->isFunctionType() || - (T->isArrayType() && - !Context.hasSameUnqualifiedType(T, ParamType->getPointeeType()) && - !IsQualificationConversion(T, ParamType->getPointeeType(), false, - ObjCLifetimeConversion)))) { - // Decay functions and arrays unless we're forming a pointer to array. - RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); - if (RefExpr.isInvalid()) - return ExprError(); - } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { - RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + + // We might need to perform a trailing qualification conversion, since + // the element type on the parameter could be more qualified than the + // element type in the expression we constructed, and likewise for a + // function conversion. + bool ObjCLifetimeConversion; + QualType Ignored; + if (IsFunctionConversion(RefExpr.get()->getType(), ParamType, Ignored) || + IsQualificationConversion(RefExpr.get()->getType(), + ParamType.getUnqualifiedType(), false, + ObjCLifetimeConversion)) + RefExpr = ImpCastExprToType(RefExpr.get(), + ParamType.getUnqualifiedType(), CK_NoOp); + + // FIXME: We need to perform derived-to-base or base-to-derived + // pointer-to-member conversions here too. + assert(!RefExpr.isInvalid() && + Context.hasSameType(RefExpr.get()->getType(), + ParamType.getUnqualifiedType())); + return RefExpr; + } + } + + QualType T = VD->getType().getNonReferenceType(); + + if (ParamType->isPointerType()) { + // When the non-type template parameter is a pointer, take the + // address of the declaration. + ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc); if (RefExpr.isInvalid()) return ExprError(); - } else { - assert(ParamType->isReferenceType() && - "unexpected type for decl template argument"); - } - - // At this point we should have the right value category. - assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() && - "value kind mismatch for non-type template argument"); - - // The type of the template parameter can diff er from the type of the - // argument in various ways; convert it now if necessary. - QualType DestExprType = ParamType.getNonLValueExprType(Context); - if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) { - CastKind CK; - QualType Ignored; - if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) || - IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) { - CK = CK_NoOp; - } else if (ParamType->isVoidPointerType() && - RefExpr.get()->getType()->isPointerType()) { - CK = CK_BitCast; - } else { - // FIXME: Pointers to members can need conversion derived-to-base or - // base-to-derived conversions. We currently don't retain enough - // information to convert properly (we need to track a cast path or - // subobject number in the template argument). - llvm_unreachable( - "unexpected conversion required for non-type template argument"); + + if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) && + (T->isFunctionType() || T->isArrayType())) { + // Decay functions and arrays unless we're forming a pointer to array. + RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); + if (RefExpr.isInvalid()) + return ExprError(); + + return RefExpr; } - RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK, - RefExpr.get()->getValueKind()); + + // Take the address of everything else + return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + } + + ExprValueKind VK = VK_RValue; + + // If the non-type template parameter has reference type, qualify the + // resulting declaration reference with the extra qualifiers on the + // type that the reference refers to. + if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) { + VK = VK_LValue; + T = Context.getQualifiedType(T, + TargetRef->getPointeeType().getQualifiers()); + } else if (isa<FunctionDecl>(VD)) { + // References to functions are always lvalues. + VK = VK_LValue; } - return RefExpr; + return BuildDeclRefExpr(VD, T, VK, Loc); } /// Construct a new expression that refers to the given diff --git a/clang/test/SemaCXX/exceptions-seh.cpp b/clang/test/SemaCXX/exceptions-seh.cpp index 02bb786160dc..1d8cc4917e98 100644 --- a/clang/test/SemaCXX/exceptions-seh.cpp +++ b/clang/test/SemaCXX/exceptions-seh.cpp @@ -39,13 +39,14 @@ void instantiate_bad_scope_tmpl() { } #if __cplusplus < 201103L +// FIXME: Diagnose this case. For now we produce undef in codegen. template <typename T, T FN()> T func_template() { - return FN(); // expected-error 2{{builtin functions must be directly called}} + return FN(); } void inject_builtins() { - func_template<void *, __exception_info>(); // expected-note {{instantiation of}} - func_template<unsigned long, __exception_code>(); // expected-note {{instantiation of}} + func_template<void *, __exception_info>(); + func_template<unsigned long, __exception_code>(); } #endif diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 7232598215ac..7a58dd5dcaed 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -394,21 +394,6 @@ namespace PR42362 { Z<f, f, f>::Q q; } -namespace QualConv { - int *X; - template<const int *const *P> void f() { - using T = decltype(P); - using T = const int* const*; - } - template void f<&X>(); - - template<const int *const &R> void g() { - using T = decltype(R); - using T = const int *const &; - } - template void g<(const int *const&)X>(); -} - namespace FunctionConversion { struct a { void c(char *) noexcept; }; template<void (a::*f)(char*)> void g() { @@ -416,21 +401,4 @@ namespace FunctionConversion { using T = void (a::*)(char*); // (not 'noexcept') } template void g<&a::c>(); - - void c() noexcept; - template<void (*p)()> void h() { - using T = decltype(p); - using T = void (*)(); // (not 'noexcept') - } - template void h<&c>(); -} - -namespace VoidPtr { - // Note, this is an extension in C++17 but valid in C++20. - template<void *P> void f() { - using T = decltype(P); - using T = void*; - } - int n; - template void f<(void*)&n>(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits