yronglin updated this revision to Diff 544386.
yronglin added a comment.

Try implement


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153701/new/

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/AST/ExprCXX.h
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp

Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -410,6 +410,7 @@
   case BuildingBuiltinDumpStructCall:
   case LambdaExpressionSubstitution:
   case BuildingDeductionGuides:
+  case BuiltingCXXForRangeVariable:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -1009,7 +1010,12 @@
           << convertCallArgsToString(
                  *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
       break;
-
+    case CodeSynthesisContext::BuiltingCXXForRangeVariable:
+      Diags.Report(Active->PointOfInstantiation,
+                   diag::note_building_builtin_dump_struct_call)
+          << convertCallArgsToString(
+                 *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
+      break;
     case CodeSynthesisContext::Memoization:
       break;
 
@@ -1138,6 +1144,7 @@
     case CodeSynthesisContext::MarkingClassDllexported:
     case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
     case CodeSynthesisContext::BuildingDeductionGuides:
+    case CodeSynthesisContext::BuiltingCXXForRangeVariable:
       // This happens in a context unrelated to template instantiation, so
       // there is no SFINAE.
       return std::nullopt;
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2522,6 +2522,12 @@
     }
   }
 
+  // Register a note to explain why we're performing the call.
+  CodeSynthesisContext Ctx;
+  Ctx.Kind = CodeSynthesisContext::BuiltingCXXForRangeVariable;
+  Ctx.PointOfInstantiation = ForLoc;
+  pushCodeSynthesisContext(Ctx);
+
   // Build  auto && __range = range-init
   // Divide by 2, since the variables are in the inner scope (loop body).
   const auto DepthStr = std::to_string(S->getDepth() / 2);
@@ -2529,8 +2535,10 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
                                            Context.getAutoRRefDeductType(),
                                            std::string("__range") + DepthStr);
-  if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
-                            diag::err_for_range_deduction_failure)) {
+  bool Res = FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+                                   diag::err_for_range_deduction_failure);
+  popCodeSynthesisContext();
+  if (Res) {
     ActOnInitializerError(LoopVar);
     return StmtError();
   }
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -7355,15 +7355,15 @@
   });
 }
 
-static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
-                                             Expr *Init, LocalVisitor Visit,
-                                             bool RevisitSubinits,
-                                             bool EnableLifetimeWarnings);
+static void
+visitLocalsRetainedByInitializer(IndirectLocalPath &Path, Expr *Init,
+                                 LocalVisitor Visit, bool RevisitSubinits,
+                                 bool EnableLifetimeWarnings,
+                                 bool isCXXForRangeVariable = false);
 
-static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
-                                                  Expr *Init, ReferenceKind RK,
-                                                  LocalVisitor Visit,
-                                                  bool EnableLifetimeWarnings);
+static void visitLocalsRetainedByReferenceBinding(
+    IndirectLocalPath &Path, Expr *Init, ReferenceKind RK, LocalVisitor Visit,
+    bool EnableLifetimeWarnings, bool isCXXForRangeVariable = false);
 
 template <typename T> static bool isRecordWithAttr(QualType Type) {
   if (auto *RD = Type->getAsCXXRecordDecl())
@@ -7543,7 +7543,8 @@
 }
 
 static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
-                                        LocalVisitor Visit) {
+                                        LocalVisitor Visit,
+                                        bool isCXXForRangeVariable = false) {
   const FunctionDecl *Callee;
   ArrayRef<Expr*> Args;
 
@@ -7584,7 +7585,8 @@
   for (unsigned I = 0,
                 N = std::min<unsigned>(Callee->getNumParams(), Args.size());
        I != N; ++I) {
-    if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
+    if (Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>() ||
+        isCXXForRangeVariable)
       VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
   }
 }
@@ -7594,7 +7596,8 @@
 static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
                                                   Expr *Init, ReferenceKind RK,
                                                   LocalVisitor Visit,
-                                                  bool EnableLifetimeWarnings) {
+                                                  bool EnableLifetimeWarnings,
+                                                  bool isCXXForRangeVariable) {
   RevertToOldSizeRAII RAII(Path);
 
   // Walk past any constructs which we can lifetime-extend across.
@@ -7613,7 +7616,15 @@
 
     // Step over any subobject adjustments; we may have a materialized
     // temporary inside them.
-    Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
+    SmallVector<const Expr *, 32> CommaLHS;
+    SmallVector<SubobjectAdjustment, 32> Adjustments;
+    Init = const_cast<Expr *>(
+        Init->skipRValueSubobjectAdjustments(CommaLHS, Adjustments));
+
+    for (auto *LHS : CommaLHS)
+      visitLocalsRetainedByReferenceBinding(Path, const_cast<Expr *>(LHS),
+                                            RK_ReferenceBinding, Visit,
+                                            EnableLifetimeWarnings);
 
     // Per current approach for DR1376, look through casts to reference type
     // when performing lifetime extension.
@@ -7653,7 +7664,8 @@
   if (isa<CallExpr>(Init)) {
     if (EnableLifetimeWarnings)
       handleGslAnnotatedTypes(Path, Init, Visit);
-    return visitLifetimeBoundArguments(Path, Init, Visit);
+    return visitLifetimeBoundArguments(Path, Init, Visit,
+                                       isCXXForRangeVariable);
   }
 
   switch (Init->getStmtClass()) {
@@ -7680,6 +7692,17 @@
     break;
   }
 
+  case Stmt::BinaryOperatorClass: {
+    const BinaryOperator *BO = cast<BinaryOperator>(Init);
+    visitLocalsRetainedByReferenceBinding(
+        Path, BO->getLHS(), RK_ReferenceBinding, Visit, EnableLifetimeWarnings,
+        isCXXForRangeVariable);
+    visitLocalsRetainedByReferenceBinding(
+        Path, BO->getRHS(), RK_ReferenceBinding, Visit, EnableLifetimeWarnings,
+        isCXXForRangeVariable);
+    break;
+  }
+
   case Stmt::UnaryOperatorClass: {
     // The only unary operator that make sense to handle here
     // is Deref.  All others don't resolve to a "name."  This includes
@@ -7722,7 +7745,8 @@
 static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
                                              Expr *Init, LocalVisitor Visit,
                                              bool RevisitSubinits,
-                                             bool EnableLifetimeWarnings) {
+                                             bool EnableLifetimeWarnings,
+                                             bool isCXXForRangeVariable) {
   RevertToOldSizeRAII RAII(Path);
 
   Expr *Old;
@@ -8068,6 +8092,10 @@
   LifetimeResult LR = getEntityLifetime(&Entity);
   LifetimeKind LK = LR.getInt();
   const InitializedEntity *ExtendingEntity = LR.getPointer();
+  bool isInitCXXForRangeVarDecl =
+      !CodeSynthesisContexts.empty() &&
+      CodeSynthesisContexts.back().Kind ==
+          CodeSynthesisContext::BuiltingCXXForRangeVariable;
 
   // If this entity doesn't have an interesting lifetime, don't bother looking
   // for temporaries within its initializer.
@@ -8081,6 +8109,13 @@
 
     auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
 
+    if (getLangOpts().CPlusPlus23 && MTE && isInitCXXForRangeVarDecl) {
+      MTE->setCanIgnore(false);
+      MTE->setExtendingDecl(ExtendingEntity->getDecl(),
+                            ExtendingEntity->allocateManglingNumber());
+      return true;
+    }
+
     bool IsGslPtrInitWithGslTempOwner = false;
     bool IsLocalGslOwner = false;
     if (pathOnlyInitializesGslPointer(Path)) {
@@ -8328,12 +8363,13 @@
       diag::warn_dangling_lifetime_pointer, SourceLocation());
   llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
   if (Init->isGLValue())
-    visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
-                                          TemporaryVisitor,
-                                          EnableLifetimeWarnings);
+    visitLocalsRetainedByReferenceBinding(
+        Path, Init, RK_ReferenceBinding, TemporaryVisitor,
+        EnableLifetimeWarnings, isInitCXXForRangeVarDecl);
   else
     visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
-                                     EnableLifetimeWarnings);
+                                     EnableLifetimeWarnings,
+                                     isInitCXXForRangeVarDecl);
 }
 
 static void DiagnoseNarrowingInInitList(Sema &S,
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8189,16 +8189,17 @@
   //   [Except in specific positions,] an lvalue that does not have
   //   array type is converted to the value stored in the
   //   designated object (and is no longer an lvalue).
-  if (E->isPRValue()) {
-    // In C, function designators (i.e. expressions of function type)
-    // are r-values, but we still want to do function-to-pointer decay
-    // on them.  This is both technically correct and convenient for
-    // some clients.
-    if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType())
-      return DefaultFunctionArrayConversion(E);
-
-    return E;
-  }
+  // if ( {
+  // In C, function designators (i.e. expressions of function type)
+  // are r-values, but we still want to do function-to-pointer decay
+  // on them.  This is both technically correct and convenient for
+  // some clients.
+  if (E->isPRValue() && !getLangOpts().CPlusPlus &&
+      E->getType()->isFunctionType())
+    return DefaultFunctionArrayConversion(E);
+
+  // return E;
+  // }
 
   if (getLangOpts().CPlusPlus) {
     // The C++11 standard defines the notion of a discarded-value expression;
@@ -8225,6 +8226,17 @@
     // just clutter.
     // FIXME: We don't emit lifetime markers for the temporaries due to this.
     // FIXME: Do any other AST consumers care about this?
+
+    // 6.7.7.2.6 - when a prvalue that has type other than cv void appears as
+    // a discarded-value expression ([expr.context]).
+    if (getLangOpts().CPlusPlus17 && E->isPRValue() &&
+        !E->getType()->isVoidType()) {
+      ExprResult Res = TemporaryMaterializationConversion(E);
+      if (Res.isInvalid())
+        return E;
+      E = Res.get();
+      dyn_cast<MaterializeTemporaryExpr>(E)->setCanIgnore();
+    }
     return E;
   }
 
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -414,6 +414,8 @@
       return "BuildingBuiltinDumpStructCall";
     case CodeSynthesisContext::BuildingDeductionGuides:
       return "BuildingDeductionGuides";
+    case CodeSynthesisContext::BuiltingCXXForRangeVariable:
+      return "BuiltingCXXForRangeVariable";
     }
     return "";
   }
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -193,6 +193,11 @@
       return EmitIgnoredConditionalOperator(CondOp);
   }
 
+  if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) {
+    if (MTE->canIgnore())
+      E = MTE->getSubExpr();
+  }
+
   // Just emit it as an l-value and drop the result.
   EmitLValue(E);
 }
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1353,6 +1353,8 @@
 
     bool IsCurrentlyCheckingDefaultArgumentOrInitializer = false;
 
+    bool IsCXXForRangeVariable = false;
+
     // When evaluating immediate functions in the initializer of a default
     // argument or default member initializer, this is the declaration whose
     // default initializer is being evaluated and the location of the call
@@ -9400,6 +9402,9 @@
 
       /// We are building deduction guides for a class.
       BuildingDeductionGuides,
+
+      /// We are building an C++ for-range variable.
+      BuiltingCXXForRangeVariable
     } Kind;
 
     /// Was the enclosing context a non-instantiation SFINAE context?
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -4575,6 +4575,7 @@
   friend class ASTStmtWriter;
 
   llvm::PointerUnion<Stmt *, LifetimeExtendedTemporaryDecl *> State;
+  bool CanIgnore = false;
 
 public:
   MaterializeTemporaryExpr(QualType T, Expr *Temporary,
@@ -4593,6 +4594,10 @@
             : State.get<LifetimeExtendedTemporaryDecl *>()->getTemporaryExpr());
   }
 
+  // Wether the MaterializeTemporaryExpr can be ignored.
+  bool canIgnore() const { return CanIgnore; }
+  void setCanIgnore(bool Val = true) { CanIgnore = Val; }
+
   /// Retrieve the storage duration for the materialized temporary.
   StorageDuration getStorageDuration() const {
     return State.is<Stmt *>() ? SD_FullExpression
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to