aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2019-10-19 00:34:54 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2019-10-19 00:34:54 +0000
commitb300d3566a7bb528c0ca2994a74dcab46f50eb97 (patch)
treef397399f29ec1c40c18d88303ac917c4c91c180b
parentae6164e81a997145838d60883a373e79de1b8e78 (diff)
downloadclang-b300d3566a7bb528c0ca2994a74dcab46f50eb97.tar.gz
Sema: Create a no-op implicit cast for lvalue function conversions.
This fixes an assertion failure in the case where an implicit conversion for a function call involves an lvalue function conversion, and makes the AST for initializations involving implicit lvalue function conversions more accurate. Differential Revision: https://reviews.llvm.org/D66437 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@375313 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/Sema.h10
-rw-r--r--lib/Sema/SemaCast.cpp3
-rw-r--r--lib/Sema/SemaExprCXX.cpp17
-rw-r--r--lib/Sema/SemaInit.cpp32
-rw-r--r--lib/Sema/SemaOverload.cpp33
-rw-r--r--test/CodeGenCXX/implicit-function-conversion.cpp7
6 files changed, 62 insertions, 40 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index bf8e59d607..a911c61a07 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -10419,11 +10419,11 @@ public:
Ref_Compatible
};
- ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
- QualType T1, QualType T2,
- bool &DerivedToBase,
- bool &ObjCConversion,
- bool &ObjCLifetimeConversion);
+ ReferenceCompareResult
+ CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2,
+ bool &DerivedToBase, bool &ObjCConversion,
+ bool &ObjCLifetimeConversion,
+ bool &FunctionConversion);
ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
Expr *CastExpr, CastKind &CastKind,
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 8c6abc448d..0ebb5c68f7 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1304,6 +1304,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
+ bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -1313,7 +1314,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion);
+ ObjCLifetimeConversion, FunctionConversion);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 61203b0a0b..9aae9289b5 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -5852,20 +5852,21 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
- if (CompareReferenceRelationship(
- QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
+ ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
// [...] subject to the constraint that the reference must bind
// directly [...]
- !RHS.get()->refersToBitField() &&
- !RHS.get()->refersToVectorElement()) {
+ !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
} else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 6255e1bf0c..10cb7acad5 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -4229,10 +4229,10 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3;
+ bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4472,13 +4472,15 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
- assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2,
- DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion) &&
+ bool FunctionConversion;
+ assert(!S.CompareReferenceRelationship(
+ Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
+ (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4605,10 +4607,11 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
bool NewObjCLifetimeConversion = false;
- Sema::ReferenceCompareResult NewRefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
- NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion);
+ bool NewFunctionConversion = false;
+ Sema::ReferenceCompareResult NewRefRelationship =
+ S.CompareReferenceRelationship(
+ DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion, NewFunctionConversion);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4642,6 +4645,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (NewObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (NewFunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
return OR_Success;
}
@@ -4701,10 +4706,11 @@ static void TryReferenceInitializationCore(Sema &S,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4735,6 +4741,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else if (ObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (FunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6793079ff0..47c1e3cec0 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -4372,7 +4372,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
bool &ObjCConversion,
- bool &ObjCLifetimeConversion) {
+ bool &ObjCLifetimeConversion,
+ bool &FunctionConversion) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4402,15 +4403,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
ObjCConversion = true;
else if (UnqualT2->isFunctionType() &&
- IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2))
+ IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
// C++1z [dcl.init.ref]p4:
// cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
// function" and T1 is "function"
//
// We extend this to also apply to 'noreturn', so allow any function
// conversion between function types.
+ FunctionConversion = true;
return Ref_Compatible;
- else
+ } else
return Ref_Incompatible;
// At this point, we know that T1 and T2 are reference-related (at
@@ -4491,6 +4493,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
@@ -4503,12 +4506,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!ConvTemplate &&
S.CompareReferenceRelationship(
- DeclLoc,
- Conv->getConversionType().getNonReferenceType()
- .getUnqualifiedType(),
- DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
- Sema::Ref_Incompatible)
+ DeclLoc,
+ Conv->getConversionType()
+ .getNonReferenceType()
+ .getUnqualifiedType(),
+ DeclType.getNonReferenceType().getUnqualifiedType(),
+ DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@@ -4612,11 +4616,11 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
-
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -5041,9 +5045,10 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool dummy1 = false;
bool dummy2 = false;
bool dummy3 = false;
+ bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
diff --git a/test/CodeGenCXX/implicit-function-conversion.cpp b/test/CodeGenCXX/implicit-function-conversion.cpp
new file mode 100644
index 0000000000..2d14c6ae51
--- /dev/null
+++ b/test/CodeGenCXX/implicit-function-conversion.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-unknown-linux -std=c++17 | FileCheck %s
+
+double a(double) noexcept;
+int b(double (&)(double));
+
+// CHECK: call i32 @_Z1bRFddE(double (double)* @_Z1ad)
+int c = b(a);