r337744 - Do not try to perform lifetime-extension through conditional

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 23 14:21:24 PDT 2018


Author: rsmith
Date: Mon Jul 23 14:21:24 2018
New Revision: 337744

URL: http://llvm.org/viewvc/llvm-project?rev=337744&view=rev
Log:
Do not try to perform lifetime-extension through conditional
expressions.

CodeGen can't cope with that yet. Instead, produce a "not supported"
warning for now and don't extend lifetime.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/SemaCXX/conditional-expr.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337744&r1=337743&r2=337744&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 23 14:21:24 2018
@@ -7895,13 +7895,16 @@ def warn_new_dangling_initializer_list :
   "the allocated initializer list}0 "
   "will be destroyed at the end of the full-expression">,
   InGroup<DanglingInitializerList>;
-def warn_default_member_init_temporary_not_extended : Warning<
-  "sorry, lifetime extension of temporary created by aggregate initialization "
-  "using default member initializer is not supported; lifetime of temporary "
+def warn_unsupported_temporary_not_extended : Warning<
+  "sorry, lifetime extension of temporary created "
+  "%select{by aggregate initialization using default member initializer|"
+  "within conditional expression}0 "
+  "is not supported; lifetime of temporary "
   "will end at the end of the full-expression">, InGroup<DanglingField>;
-def warn_default_member_init_init_list_not_extended : Warning<
-  "sorry, lifetime extension of backing array of initializer list "
-  "created by aggregate initialization using default member initializer "
+def warn_unsupported_init_list_not_extended : Warning<
+  "sorry, lifetime extension of backing array of initializer list created "
+  "%select{by aggregate initialization using default member initializer|"
+  "within conditional expression}0 "
   "is not supported; lifetime of backing array will end at the end of the "
   "full-expression">, InGroup<DanglingInitializerList>;
 

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=337744&r1=337743&r2=337744&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Jul 23 14:21:24 2018
@@ -6362,6 +6362,7 @@ using Local = Expr*;
 struct IndirectLocalPathEntry {
   enum EntryKind {
     DefaultInit,
+    Conditional,
     AddressOf,
     VarInit,
     LValToRVal,
@@ -6497,6 +6498,7 @@ static void visitLocalsRetainedByReferen
 
   case Stmt::ConditionalOperatorClass:
   case Stmt::BinaryConditionalOperatorClass: {
+    Path.push_back({IndirectLocalPathEntry::Conditional, Init});
     auto *C = cast<AbstractConditionalOperator>(Init);
     if (!C->getTrueExpr()->getType()->isVoidType())
       visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);
@@ -6683,6 +6685,7 @@ static void visitLocalsRetainedByInitial
 
   case Stmt::ConditionalOperatorClass:
   case Stmt::BinaryConditionalOperatorClass: {
+    Path.push_back({IndirectLocalPathEntry::Conditional, Init});
     auto *C = cast<AbstractConditionalOperator>(Init);
     // In C++, we can have a throw-expression operand, which has 'void' type
     // and isn't interesting from a lifetime perspective.
@@ -6714,12 +6717,33 @@ static void visitLocalsRetainedByInitial
 /// supposed to lifetime-extend along (but don't).
 static bool shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
   for (auto Elem : Path) {
-    if (Elem.Kind != IndirectLocalPathEntry::DefaultInit)
+    if (Elem.Kind != IndirectLocalPathEntry::DefaultInit &&
+        Elem.Kind != IndirectLocalPathEntry::Conditional)
       return false;
   }
   return true;
 }
 
+/// Find the range for the first interesting entry in the path at or after I.
+static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
+                                      Expr *E) {
+  for (unsigned N = Path.size(); I != N; ++I) {
+    switch (Path[I].Kind) {
+    case IndirectLocalPathEntry::AddressOf:
+    case IndirectLocalPathEntry::LValToRVal:
+    case IndirectLocalPathEntry::Conditional:
+      // These exist primarily to mark the path as not permitting or
+      // supporting lifetime extension.
+      break;
+
+    case IndirectLocalPathEntry::DefaultInit:
+    case IndirectLocalPathEntry::VarInit:
+      return Path[I].E->getSourceRange();
+    }
+  }
+  return E->getSourceRange();
+}
+
 void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
                                     Expr *Init) {
   LifetimeResult LR = getEntityLifetime(&Entity);
@@ -6733,9 +6757,8 @@ void Sema::checkInitializerLifetime(cons
 
   auto TemporaryVisitor = [&](IndirectLocalPath &Path, Local L,
                               ReferenceKind RK) -> bool {
-    Expr *First = Path.empty() ? L : Path.front().E;
-    SourceLocation DiagLoc = First->getLocStart();
-    SourceRange DiagRange = First->getSourceRange();
+    SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
+    SourceLocation DiagLoc = DiagRange.getBegin();
 
     switch (LK) {
     case LK_FullExpression:
@@ -6761,13 +6784,14 @@ void Sema::checkInitializerLifetime(cons
         // We're supposed to lifetime-extend the temporary along this path (per
         // the resolution of DR1815), but we don't support that yet.
         //
-        // FIXME: Properly handle this situation. Perhaps the easiest approach
+        // FIXME: Properly handle these situations.
+        // For the default member initializer case, perhaps the easiest approach
         // would be to clone the initializer expression on each use that would
         // lifetime extend its temporaries.
-        Diag(DiagLoc,
-             RK == RK_ReferenceBinding
-                 ? diag::warn_default_member_init_temporary_not_extended
-                 : diag::warn_default_member_init_init_list_not_extended)
+        Diag(DiagLoc, RK == RK_ReferenceBinding
+                          ? diag::warn_unsupported_temporary_not_extended
+                          : diag::warn_unsupported_init_list_not_extended)
+            << (Path.front().Kind == IndirectLocalPathEntry::Conditional)
             << DiagRange;
       } else {
         // FIXME: Warn on this.
@@ -6871,31 +6895,26 @@ void Sema::checkInitializerLifetime(cons
     for (unsigned I = 0; I != Path.size(); ++I) {
       auto Elem = Path[I];
 
-      // Highlight the range of the next step within this path element.
-      SourceRange Range;
-      if (I < Path.size() - 1)
-        Range = Path[I + 1].E->getSourceRange();
-      else
-        Range = L->getSourceRange();
-
       switch (Elem.Kind) {
       case IndirectLocalPathEntry::AddressOf:
       case IndirectLocalPathEntry::LValToRVal:
-        // These exist primarily to mark the path as not permitting lifetime
-        // extension.
+      case IndirectLocalPathEntry::Conditional:
+        // These exist primarily to mark the path as not permitting or
+        // supporting lifetime extension.
         break;
 
       case IndirectLocalPathEntry::DefaultInit: {
         auto *FD = cast<FieldDecl>(Elem.D);
         Diag(FD->getLocation(), diag::note_init_with_default_member_initalizer)
-            << FD << Range;
+            << FD << nextPathEntryRange(Path, I + 1, L);
         break;
       }
 
       case IndirectLocalPathEntry::VarInit:
         const VarDecl *VD = cast<VarDecl>(Elem.D);
         Diag(VD->getLocation(), diag::note_local_var_initializer)
-            << VD->getType()->isReferenceType() << VD->getDeclName() << Range;
+            << VD->getType()->isReferenceType() << VD->getDeclName()
+            << nextPathEntryRange(Path, I + 1, L);
         break;
       }
     }

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=337744&r1=337743&r2=337744&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Mon Jul 23 14:21:24 2018
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++11 -Wsign-conversion %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -fsyntax-only -verify -std=c++17 -Wsign-conversion %s
 
 // C++ rules for ?: are a lot stricter than C rules, and have to take into
 // account more conversion options.
@@ -228,7 +229,7 @@ void test()
   // be properly tested at runtime, though.
 
   const Abstract &abstract1 = true ? static_cast<const Abstract&>(Derived1()) : Derived2(); // expected-error {{allocating an object of abstract class type 'const Abstract'}}
-  const Abstract &abstract2 = true ? static_cast<const Abstract&>(Derived1()) : throw 3; // ok
+  const Abstract &abstract2 = true ? static_cast<const Abstract&>(Derived1()) : throw 3; // expected-warning-re {{sorry, lifetime extension {{.*}} not supported}}
 }
 
 namespace PR6595 {
@@ -393,3 +394,22 @@ Derived d;
 typedef decltype(true ? static_cast<Base&&>(b) : static_cast<Derived&&>(d)) x;
 typedef Base &&x;
 }
+
+namespace lifetime_extension {
+  struct A {};
+  struct B : A { B(); ~B(); };
+  struct C : A { C(); ~C(); };
+
+  void f(bool b) {
+    // expected-warning at +1 2{{sorry, lifetime extension of temporary created within conditional expression is not supported}}
+    A &&r = b ? static_cast<A&&>(B()) : static_cast<A&&>(C());
+  }
+
+  struct D { A &&a; };
+  void f_indirect(bool b) {
+#if __cplusplus >= 201702L
+    // expected-warning at +2 2{{sorry, lifetime extension of temporary created within conditional expression is not supported}}
+#endif
+    D d = b ? D{B()} : D{C()};
+  }
+}




More information about the cfe-commits mailing list