Sema: Create a no-op implicit cast for lvalue function conversions.
authorPeter Collingbourne <peter@pcc.me.uk>
Sat, 19 Oct 2019 00:34:54 +0000 (00:34 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Sat, 19 Oct 2019 00:34:54 +0000 (00:34 +0000)
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

include/clang/Sema/Sema.h
lib/Sema/SemaCast.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
test/CodeGenCXX/implicit-function-conversion.cpp [new file with mode: 0644]

index bf8e59d607fb9bd1f67f46e1031af90f24e745ac..a911c61a07f89b3f79ed3028837749cd9a5c8056 100644 (file)
@@ -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,
index 8c6abc448d977bbf7fdf1cefc3af1ff1b5628992..0ebb5c68f7c2350c9328125317a1992faff8b6ab 100644 (file)
@@ -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;
index 61203b0a0bfa698b0a226231b4e1256ad4f9ae54..9aae9289b514c4487d36bfadc9f08ccb40f00dbf 100644 (file)
@@ -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()) {
index 6255e1bf0caadd913cb11baff48cba594ef45151..10cb7acad5672765e2c0e6e074f28901fc87a191 100644 (file)
@@ -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
index 6793079ff0ab5d8c471c1ac153bda80eaef9c7d7..47c1e3cec0ea785d6b00b6e121d146a2f5793c09 100644 (file)
@@ -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 (file)
index 0000000..2d14c6a
--- /dev/null
@@ -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);