aaronpuchert created this revision.
aaronpuchert added a reviewer: rsmith.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
aaronpuchert marked 2 inline comments as done.
aaronpuchert added a comment.

If anyone shares my feeling that the boolean output parameters of 
`CompareReferenceRelationship` should rather move to the return value, I would 
be happy to do that.



================
Comment at: clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp:5
+// CHECK: VarDecl {{.*}} fp 'void (&)()' cinit
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()':'void ()' lvalue <NoOp>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'void () noexcept' lvalue Function {{.*}} 
'f' 'void () noexcept'
----------------
This is new.


================
Comment at: clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp:15
+// CHECK: VarDecl {{.*}} xp 'void (&)()' cinit
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()':'void ()' lvalue <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void () noexcept':'void () noexcept' 
lvalue <UserDefinedConversion>
----------------
This is also new.


When initializing a reference to a non-noexcept function from a noexcept
function we didn't add an implicit cast node, which confused a type-
checking assertion in CodeGen. The same conversion is used for function
pointer conversion already.

Fixes PR43154.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D67112

Files:
  clang/include/clang/AST/OperationKinds.def
  clang/include/clang/Sema/Initialization.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCast.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp

Index: clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++17 -ast-dump %s | FileCheck %s
+
+void f() noexcept;
+// CHECK: VarDecl {{.*}} fp 'void (&)()' cinit
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()':'void ()' lvalue <NoOp>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'void () noexcept' lvalue Function {{.*}} 'f' 'void () noexcept'
+void (&fp)() = f;
+
+struct X {
+  typedef void (&fp)() noexcept;
+  operator fp();
+} x;
+
+// CHECK: VarDecl {{.*}} xp 'void (&)()' cinit
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()':'void ()' lvalue <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void () noexcept':'void () noexcept' lvalue <UserDefinedConversion>
+void (&xp)() = x;
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -4296,12 +4296,10 @@
 /// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
 /// type, and the first type (T1) is the pointee type of the reference
 /// type being initialized.
-Sema::ReferenceCompareResult
-Sema::CompareReferenceRelationship(SourceLocation Loc,
-                                   QualType OrigT1, QualType OrigT2,
-                                   bool &DerivedToBase,
-                                   bool &ObjCConversion,
-                                   bool &ObjCLifetimeConversion) {
+Sema::ReferenceCompareResult Sema::CompareReferenceRelationship(
+    SourceLocation Loc, QualType OrigT1, QualType OrigT2, bool &DerivedToBase,
+    bool &FuncRefConversion, bool &ObjCConversion,
+    bool &ObjCLifetimeConversion) {
   assert(!OrigT1->isReferenceType() &&
     "T1 must be the pointee type of the reference type");
   assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4317,6 +4315,7 @@
   //   reference-related to "cv2 T2" if T1 is the same type as T2, or
   //   T1 is a base class of T2.
   DerivedToBase = false;
+  FuncRefConversion = false;
   ObjCConversion = false;
   ObjCLifetimeConversion = false;
   QualType ConvertedT2;
@@ -4331,15 +4330,16 @@
            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.
+    FuncRefConversion = true;
     return Ref_Compatible;
-  else
+  } else
     return Ref_Incompatible;
 
   // At this point, we know that T1 and T2 are reference-related (at
@@ -4418,6 +4418,7 @@
 
     if (AllowRvalues) {
       bool DerivedToBase = false;
+      bool FuncPtrConversion = false;
       bool ObjCConversion = false;
       bool ObjCLifetimeConversion = false;
 
@@ -4432,12 +4433,13 @@
 
       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, FuncPtrConversion, ObjCConversion,
+              ObjCLifetimeConversion) == Sema::Ref_Incompatible)
         continue;
     } else {
       // If the conversion function doesn't return a reference type,
@@ -4539,13 +4541,13 @@
   // Compute some basic properties of the types and the initializer.
   bool isRValRef = DeclType->isRValueReferenceType();
   bool DerivedToBase = false;
+  bool FuncPtrConversion = false;
   bool ObjCConversion = false;
   bool ObjCLifetimeConversion = 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, FuncPtrConversion, ObjCConversion,
+      ObjCLifetimeConversion);
 
   // C++0x [dcl.init.ref]p5:
   //   A reference to type "cv1 T1" is initialized by an expression
@@ -4970,9 +4972,10 @@
       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(),
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -3417,6 +3417,7 @@
   case SK_QualificationConversionRValue:
   case SK_QualificationConversionXValue:
   case SK_QualificationConversionLValue:
+  case SK_FunctionReferenceConversion:
   case SK_AtomicConversion:
   case SK_ListInitialization:
   case SK_UnwrapInitList:
@@ -3594,6 +3595,13 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddFunctionReferenceConversionStep(QualType Ty) {
+  Step S;
+  S.Kind = SK_FunctionReferenceConversion;
+  S.Type = Ty;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::AddAtomicConversionStep(QualType Ty) {
   Step S;
   S.Kind = SK_AtomicConversion;
@@ -4228,10 +4236,10 @@
       return;
 
     SourceLocation DeclLoc = Initializer->getBeginLoc();
-    bool dummy1, dummy2, dummy3;
-    Sema::ReferenceCompareResult RefRelationship
-      = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
-                                       dummy2, dummy3);
+    bool dummy1, dummy2, dummy3, dummy4;
+    Sema::ReferenceCompareResult RefRelationship =
+        S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1, dummy2,
+                                       dummy3, dummy4);
     if (RefRelationship >= Sema::Ref_Related) {
       // Try to bind the reference here.
       TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4469,13 +4477,15 @@
   QualType T2 = cv2T2.getUnqualifiedType();
 
   bool DerivedToBase;
+  bool FuncRefConversion;
   bool ObjCConversion;
   bool ObjCLifetimeConversion;
-  assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2,
-                                         DerivedToBase, ObjCConversion,
-                                         ObjCLifetimeConversion) &&
+  assert(!S.CompareReferenceRelationship(
+             Initializer->getBeginLoc(), T1, T2, DerivedToBase,
+             FuncRefConversion, ObjCConversion, ObjCLifetimeConversion) &&
          "Must have incompatible references when binding via conversion");
   (void)DerivedToBase;
+  (void)FuncRefConversion;
   (void)ObjCConversion;
   (void)ObjCLifetimeConversion;
 
@@ -4602,11 +4612,12 @@
   // Determine whether we'll need to perform derived-to-base adjustments or
   // other conversions.
   bool NewDerivedToBase = false;
+  bool NewFuncRefConversion = false;
   bool NewObjCConversion = false;
   bool NewObjCLifetimeConversion = false;
-  Sema::ReferenceCompareResult NewRefRelationship
-    = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
-                                     NewDerivedToBase, NewObjCConversion,
+  Sema::ReferenceCompareResult NewRefRelationship =
+      S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, NewDerivedToBase,
+                                     NewFuncRefConversion, NewObjCConversion,
                                      NewObjCLifetimeConversion);
 
   // Add the final conversion sequence, if necessary.
@@ -4639,6 +4650,8 @@
 
   if (NewDerivedToBase)
     Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
+  else if (NewFuncRefConversion)
+    Sequence.AddFunctionReferenceConversionStep(cv1T1);
   else if (NewObjCConversion)
     Sequence.AddObjCObjectConversionStep(cv1T1);
 
@@ -4698,12 +4711,13 @@
   bool isLValueRef = DestType->isLValueReferenceType();
   bool isRValueRef = !isLValueRef;
   bool DerivedToBase = false;
+  bool FuncRefConversion = false;
   bool ObjCConversion = false;
   bool ObjCLifetimeConversion = 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, FuncRefConversion, ObjCConversion,
+      ObjCLifetimeConversion);
 
   // C++0x [dcl.init.ref]p5:
   //   A reference to type "cv1 T1" is initialized by an expression of type
@@ -4732,6 +4746,8 @@
             Initializer->getValueKind());
       if (DerivedToBase)
         Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
+      else if (FuncRefConversion)
+        Sequence.AddFunctionReferenceConversionStep(cv1T1);
       else if (ObjCConversion)
         Sequence.AddObjCObjectConversionStep(cv1T1);
 
@@ -7863,6 +7879,7 @@
   case SK_QualificationConversionLValue:
   case SK_QualificationConversionXValue:
   case SK_QualificationConversionRValue:
+  case SK_FunctionReferenceConversion:
   case SK_AtomicConversion:
   case SK_ConversionSequence:
   case SK_ConversionSequenceNoNarrowing:
@@ -8128,6 +8145,13 @@
       break;
     }
 
+    case SK_FunctionReferenceConversion:
+      assert(CurInit.get()->isLValue() &&
+             "function reference should be lvalue");
+      CurInit =
+          S.ImpCastExprToType(CurInit.get(), Step->Type, CK_NoOp, VK_LValue);
+      break;
+
     case SK_AtomicConversion: {
       assert(CurInit.get()->isRValue() && "cannot convert glvalue to atomic");
       CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
@@ -9357,6 +9381,10 @@
       OS << "qualification conversion (lvalue)";
       break;
 
+    case SK_FunctionReferenceConversion:
+      OS << "function reference conversion";
+      break;
+
     case SK_AtomicConversion:
       OS << "non-atomic-to-atomic conversion";
       break;
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -5835,9 +5835,10 @@
       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;
+    bool DerivedToBase, FuncRefConversion, ObjCConversion,
+        ObjCLifetimeConversion;
     if (CompareReferenceRelationship(
-            QuestionLoc, LTy, RTy, DerivedToBase,
+            QuestionLoc, LTy, RTy, DerivedToBase, FuncRefConversion,
             ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
         !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
         // [...] subject to the constraint that the reference must bind
@@ -5847,7 +5848,7 @@
       RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
       RTy = RHS.get()->getType();
     } else if (CompareReferenceRelationship(
-                   QuestionLoc, RTy, LTy, DerivedToBase,
+                   QuestionLoc, RTy, LTy, DerivedToBase, FuncRefConversion,
                    ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
                !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
                !LHS.get()->refersToBitField() &&
Index: clang/lib/Sema/SemaCast.cpp
===================================================================
--- clang/lib/Sema/SemaCast.cpp
+++ clang/lib/Sema/SemaCast.cpp
@@ -1302,6 +1302,7 @@
   // this is the only cast possibility, so we issue an error if we fail now.
   // FIXME: Should allow casting away constness if CStyle.
   bool DerivedToBase;
+  bool FuncRefConversion;
   bool ObjCConversion;
   bool ObjCLifetimeConversion;
   QualType FromType = SrcExpr->getType();
@@ -1312,8 +1313,8 @@
   }
 
   Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
-      SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
-      ObjCLifetimeConversion);
+      SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase,
+      FuncRefConversion, ObjCConversion, ObjCLifetimeConversion);
   if (RefResult != Sema::Ref_Compatible) {
     if (CStyle || RefResult == Sema::Ref_Incompatible)
       return TC_NotApplicable;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10167,11 +10167,11 @@
     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 &FuncRefConversion,
+                               bool &ObjCConversion,
+                               bool &ObjCLifetimeConversion);
 
   ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
                                  Expr *CastExpr, CastKind &CastKind,
Index: clang/include/clang/Sema/Initialization.h
===================================================================
--- clang/include/clang/Sema/Initialization.h
+++ clang/include/clang/Sema/Initialization.h
@@ -818,6 +818,9 @@
     /// Perform a qualification conversion, producing an lvalue.
     SK_QualificationConversionLValue,
 
+    /// Perform a function reference conversion, see [dcl.init.ref]p4.
+    SK_FunctionReferenceConversion,
+
     /// Perform a conversion adding _Atomic to a type.
     SK_AtomicConversion,
 
@@ -1263,6 +1266,10 @@
   void AddQualificationConversionStep(QualType Ty,
                                      ExprValueKind Category);
 
+  /// Add a new step that performs a function reference conversion to the
+  /// given type.
+  void AddFunctionReferenceConversionStep(QualType Ty);
+
   /// Add a new step that performs conversion from non-atomic to atomic
   /// type.
   void AddAtomicConversionStep(QualType Ty);
Index: clang/include/clang/AST/OperationKinds.def
===================================================================
--- clang/include/clang/AST/OperationKinds.def
+++ clang/include/clang/AST/OperationKinds.def
@@ -76,9 +76,10 @@
 CAST_OPERATION(LValueToRValue)
 
 /// CK_NoOp - A conversion which does not affect the type other than
-/// (possibly) adding qualifiers.
+/// (possibly) adding qualifiers or removing noexcept.
 ///   int    -> int
 ///   char** -> const char * const *
+///   void () noexcept -> void ()
 CAST_OPERATION(NoOp)
 
 /// CK_BaseToDerived - A conversion from a C++ class pointer/reference
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to