forked from OSchip/llvm-project
Revert "Properly convert all declaration non-type template arguments when"
This reverts commit 11d1052785
.
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
(*)()')").
This commit is contained in:
parent
3882edbe19
commit
93cc9dddd8
|
@ -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);
|
||||
}
|
||||
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);
|
||||
|
||||
ExprResult RefExpr = BuildDeclarationNameExpr(
|
||||
SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD);
|
||||
if (RefExpr.isInvalid())
|
||||
return ExprError();
|
||||
// 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;
|
||||
|
||||
// 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());
|
||||
if (RefExpr.isInvalid())
|
||||
return ExprError();
|
||||
} else {
|
||||
assert(ParamType->isReferenceType() &&
|
||||
"unexpected type for decl template argument");
|
||||
}
|
||||
ExprResult RefExpr = BuildDeclRefExpr(VD,
|
||||
VD->getType().getNonReferenceType(),
|
||||
VK,
|
||||
Loc,
|
||||
&SS);
|
||||
if (RefExpr.isInvalid())
|
||||
return ExprError();
|
||||
|
||||
// At this point we should have the right value category.
|
||||
assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() &&
|
||||
"value kind mismatch for non-type template argument");
|
||||
RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get());
|
||||
|
||||
// The type of the template parameter can differ 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");
|
||||
// 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;
|
||||
}
|
||||
RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK,
|
||||
RefExpr.get()->getValueKind());
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 BuildDeclRefExpr(VD, T, VK, Loc);
|
||||
}
|
||||
|
||||
/// Construct a new expression that refers to the given
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue