Skip to content

Commit

Permalink
Sema: Create a no-op implicit cast for lvalue function conversions.
Browse files Browse the repository at this point in the history
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

llvm-svn: 375313
  • Loading branch information
pcc committed Oct 19, 2019
1 parent 0904f92 commit 766f158
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 40 deletions.
10 changes: 5 additions & 5 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -10419,11 +10419,11 @@ class Sema {
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,
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaCast.cpp
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
17 changes: 9 additions & 8 deletions clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -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()) {
Expand Down
32 changes: 20 additions & 12 deletions clang/lib/Sema/SemaInit.cpp
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
33 changes: 19 additions & 14 deletions clang/lib/Sema/SemaOverload.cpp
Expand Up @@ -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");
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down
7 changes: 7 additions & 0 deletions clang/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);

0 comments on commit 766f158

Please sign in to comment.