summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorDavid L. Jones <dlj@google.com>2019-12-04 22:08:38 -0800
committerDavid L. Jones <dlj@google.com>2019-12-04 22:12:15 -0800
commit93cc9dddd82f9e971f382ade6acf6634c5914966 (patch)
tree90d0ea59b9f2c275cdbcdfe6480e64fa97b95442 /clang/lib/Sema/SemaTemplate.cpp
parent3882edbe191f78547445424cb20983a20b71f4cf (diff)
downloadbcm5719-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.cpp153
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
OpenPOWER on IntegriCloud