diff options
author | David L. Jones <dlj@google.com> | 2019-12-04 22:08:38 -0800 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2019-12-04 22:12:15 -0800 |
commit | 93cc9dddd82f9e971f382ade6acf6634c5914966 (patch) | |
tree | 90d0ea59b9f2c275cdbcdfe6480e64fa97b95442 /clang/lib/Sema/SemaTemplate.cpp | |
parent | 3882edbe191f78547445424cb20983a20b71f4cf (diff) | |
download | bcm5719-llvm-93cc9dddd82f9e971f382ade6acf6634c5914966.tar.gz bcm5719-llvm-93cc9dddd82f9e971f382ade6acf6634c5914966.zip |
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
(*)()')").
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 153 |
1 files changed, 88 insertions, 65 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 85240e1aeec..e800f7fe742 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 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"); + + 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 |