]> granicus.if.org Git - clang/commitdiff
For now, disallow lifetime-extended temporaries with non-trivial (but
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 29 Sep 2019 06:22:54 +0000 (06:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 29 Sep 2019 06:22:54 +0000 (06:22 +0000)
constexpr) destructors from being used in the values of constexpr
variables.

The standard rules here are unclear at best, so rejecting the
problematic cases seems prudent. Prior to this change, we would fail to
run the destructors for these temporaries, even if they had
side-effects, which is certainly not the right behavior.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373161 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticASTKinds.td
lib/AST/ExprConstant.cpp
test/SemaCXX/constant-expression-cxx2a.cpp

index eb2a1f02fd89ad5bf70d0932f639cff055cc7c34..f4eeebd73ab674c2f471b5cac47c9594af2e67dc 100644 (file)
@@ -210,6 +210,9 @@ def note_constexpr_destroy_out_of_lifetime : Note<
   "destroying object '%0' whose lifetime has already ended">;
 def note_constexpr_unsupported_destruction : Note<
   "non-trivial destruction of type %0 in a constant expression is not supported">;
+def note_constexpr_unsupported_tempoarary_nontrivial_dtor : Note<
+  "non-trivial destruction of lifetime-extended temporary with type %0 "
+  "used in the result of a constant expression is not yet supported">;
 def note_constexpr_unsupported_unsized_array : Note<
   "array-to-pointer decay of array member without known bound is not supported">;
 def note_constexpr_unsized_array_indexed : Note<
index b0c0c2e8d98d93fd7359bf76bfb59acff1c168a0..f91e0782b89ca4dd4116024aafa2213c0ee48469 100644 (file)
@@ -1999,10 +1999,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
   } else if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(
                  Base.dyn_cast<const Expr *>())) {
     if (CheckedTemps.insert(MTE).second) {
+      QualType TempType = getType(Base);
+      if (TempType.isDestructedType()) {
+        Info.FFDiag(MTE->getExprLoc(),
+                    diag::note_constexpr_unsupported_tempoarary_nontrivial_dtor)
+            << TempType;
+        return false;
+      }
+
       APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
       assert(V && "evasluation result refers to uninitialised temporary");
       if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
-                                 Info, MTE->getExprLoc(), getType(Base), *V,
+                                 Info, MTE->getExprLoc(), TempType, *V,
                                  Usage, SourceLocation(), CheckedTemps))
         return false;
     }
index 152bfcf0a7b6468e61705d8d6c592899f8111d92..5e05c2929844c5ff69b7a71cd48fb7bb807a1e8b 100644 (file)
@@ -1250,3 +1250,22 @@ namespace dtor_call {
     as.b.~A(); // expected-note {{destruction of member 'b' of union with active member 'a'}}
   }
 }
+
+namespace temp_dtor {
+  void f();
+  struct A {
+    bool b;
+    constexpr ~A() { if (b) f(); }
+  };
+
+  // We can't accept either of these unless we start actually registering the
+  // destructors of the A temporaries to run on shutdown. It's unclear what the
+  // intended standard behavior is so we reject this for now.
+  constexpr A &&a = A{false}; // expected-error {{constant}} expected-note {{non-trivial destruction of lifetime-extended temporary}}
+  void f() { a.b = true; }
+
+  constexpr A &&b = A{true}; // expected-error {{constant}} expected-note {{non-trivial destruction of lifetime-extended temporary}}
+
+  // FIXME: We could in prinicple accept this.
+  constexpr const A &c = A{false}; // expected-error {{constant}} expected-note {{non-trivial destruction of lifetime-extended temporary}}
+}