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@+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@+2 2{{sorry, lifetime extension of temporary created within conditional expression is not supported}} +#endif + D d = b ? D{B()} : D{C()}; + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits