r335795 - [CFG] [analyzer] Add construction contexts that explain pre-C++17 copy elision.

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 4 07:30:58 PDT 2018


We've started seeing an assertion failure after this commit:
assert.h assertion failed at llvm/tools/clang/lib/Analysis/CFG.cpp:1266 in
void (anonymous namespace)::CFGBuilder::findConstructionContexts(const
clang::ConstructionContextLayer *, clang::Stmt *): CE->getNumArgs() == 1

The stack trace is:
::CFGBuilder::findConstructionContexts
::CFGBuilder::VisitReturnStmt
::CFGBuilder::Visit
::CFGBuilder::addStmt
::CFGBuilder::VisitCompoundStmt
::CFGBuilder::Visit
::CFGBuilder::addStmt
::CFGBuilder::buildCFG
clang::CFG::buildCFG
clang::AnalysisDeclContext::getCFG
clang::ento::AnalysisManager::getCFG
::AnalysisConsumer::HandleCode
clang::RecursiveASTVisitor::TraverseDecl
clang::RecursiveASTVisitor::TraverseDeclContextHelper
clang::RecursiveASTVisitor::TraverseDecl
clang::RecursiveASTVisitor::TraverseDeclContextHelper
clang::RecursiveASTVisitor::TraverseDecl
::AnalysisConsumer::runAnalysisOnTranslationUnit
::AnalysisConsumer::HandleTranslationUnit

No test case yet.

On Thu, Jun 28, 2018 at 2:09 AM Artem Dergachev via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: dergachev
> Date: Wed Jun 27 17:04:54 2018
> New Revision: 335795
>
> URL: http://llvm.org/viewvc/llvm-project?rev=335795&view=rev
> Log:
> [CFG] [analyzer] Add construction contexts that explain pre-C++17 copy
> elision.
>
> Before C++17 copy elision was optional, even if the elidable copy/move
> constructor had arbitrary side effects. The elidable constructor is present
> in the AST, but marked as elidable.
>
> In these cases CFG now contains additional information that allows its
> clients
> to figure out if a temporary object is only being constructed so that to
> pass
> it to an elidable constructor. If so, it includes a reference to the
> elidable
> constructor's construction context, so that the client could elide the
> elidable constructor and construct the object directly at its final
> destination.
>
> Differential Revision: https://reviews.llvm.org/D47616
>
> Modified:
>     cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h
>     cfe/trunk/include/clang/Analysis/CFG.h
>     cfe/trunk/include/clang/Analysis/ConstructionContext.h
>     cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
>     cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
>     cfe/trunk/lib/Analysis/CFG.cpp
>     cfe/trunk/lib/Analysis/ConstructionContext.cpp
>     cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
>     cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
>     cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
>     cfe/trunk/test/Analysis/analyzer-config.c
>     cfe/trunk/test/Analysis/analyzer-config.cpp
>     cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
>     cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
>
> Modified: cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h (original)
> +++ cfe/trunk/include/clang/Analysis/AnalysisDeclContext.h Wed Jun 27
> 17:04:54 2018
> @@ -451,6 +451,7 @@ public:
>                               bool addStaticInitBranches = false,
>                               bool addCXXNewAllocator = true,
>                               bool addRichCXXConstructors = true,
> +                             bool markElidedCXXConstructors = true,
>                               CodeInjector *injector = nullptr);
>
>    AnalysisDeclContext *getContext(const Decl *D);
>
> Modified: cfe/trunk/include/clang/Analysis/CFG.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/CFG.h?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/CFG.h (original)
> +++ cfe/trunk/include/clang/Analysis/CFG.h Wed Jun 27 17:04:54 2018
> @@ -1025,6 +1025,7 @@ public:
>      bool AddCXXNewAllocator = false;
>      bool AddCXXDefaultInitExprInCtors = false;
>      bool AddRichCXXConstructors = false;
> +    bool MarkElidedCXXConstructors = false;
>
>      BuildOptions() = default;
>
>
> Modified: cfe/trunk/include/clang/Analysis/ConstructionContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ConstructionContext.h?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Analysis/ConstructionContext.h (original)
> +++ cfe/trunk/include/clang/Analysis/ConstructionContext.h Wed Jun 27
> 17:04:54 2018
> @@ -107,7 +107,10 @@ public:
>      INITIALIZER_BEGIN = SimpleConstructorInitializerKind,
>      INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind,
>      NewAllocatedObjectKind,
> -    TemporaryObjectKind,
> +    SimpleTemporaryObjectKind,
> +    ElidedTemporaryObjectKind,
> +    TEMPORARY_BEGIN = SimpleTemporaryObjectKind,
> +    TEMPORARY_END = ElidedTemporaryObjectKind,
>      SimpleReturnedValueKind,
>      CXX17ElidedCopyReturnedValueKind,
>      RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
> @@ -305,16 +308,15 @@ class TemporaryObjectConstructionContext
>    const CXXBindTemporaryExpr *BTE;
>    const MaterializeTemporaryExpr *MTE;
>
> -  friend class ConstructionContext; // Allows to create<>() itself.
> -
> +protected:
>    explicit TemporaryObjectConstructionContext(
> -      const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr
> *MTE)
> -      : ConstructionContext(ConstructionContext::TemporaryObjectKind),
> -        BTE(BTE), MTE(MTE) {
> +      ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE,
> +      const MaterializeTemporaryExpr *MTE)
> +      : ConstructionContext(K), BTE(BTE), MTE(MTE) {
>      // Both BTE and MTE can be null here, all combinations possible.
>      // Even though for now at least one should be non-null, we simply
> haven't
> -    // implemented this case yet (this would be a temporary in the middle
> of
> -    // nowhere that doesn't have a non-trivial destructor).
> +    // implemented the other case yet (this would be a temporary in the
> middle
> +    // of nowhere that doesn't have a non-trivial destructor).
>    }
>
>  public:
> @@ -334,7 +336,67 @@ public:
>    }
>
>    static bool classof(const ConstructionContext *CC) {
> -    return CC->getKind() == TemporaryObjectKind;
> +    return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <=
> TEMPORARY_END;
> +  }
> +};
> +
> +/// Represents a temporary object that is not constructed for the purpose
> of
> +/// being immediately copied/moved by an elidable copy/move-constructor.
> +/// This includes temporary objects "in the middle of nowhere" like
> T(123) and
> +/// lifetime-extended temporaries.
> +class SimpleTemporaryObjectConstructionContext
> +    : public TemporaryObjectConstructionContext {
> +  friend class ConstructionContext; // Allows to create<>() itself.
> +
> +  explicit SimpleTemporaryObjectConstructionContext(
> +      const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr
> *MTE)
> +      : TemporaryObjectConstructionContext(
> +            ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {}
> +
> +public:
> +  static bool classof(const ConstructionContext *CC) {
> +    return CC->getKind() == SimpleTemporaryObjectKind;
> +  }
> +};
> +
> +/// Represents a temporary object that is constructed for the sole purpose
> +/// of being immediately copied by an elidable copy/move constructor.
> +/// For example, T t = T(123); includes a temporary T(123) that is
> immediately
> +/// copied to variable t. In such cases the elidable copy can (but not
> +/// necessarily should) be omitted ("elided") accodring to the rules of
> the
> +/// language; the constructor would then construct variable t directly.
> +/// This construction context contains information of the elidable
> constructor
> +/// and its respective construction context.
> +class ElidedTemporaryObjectConstructionContext
> +    : public TemporaryObjectConstructionContext {
> +  const CXXConstructExpr *ElidedCE;
> +  const ConstructionContext *ElidedCC;
> +
> +  friend class ConstructionContext; // Allows to create<>() itself.
> +
> +  explicit ElidedTemporaryObjectConstructionContext(
> +      const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr
> *MTE,
> +      const CXXConstructExpr *ElidedCE, const ConstructionContext
> *ElidedCC)
> +      : TemporaryObjectConstructionContext(
> +            ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE),
> +        ElidedCE(ElidedCE), ElidedCC(ElidedCC) {
> +    // Elided constructor and its context should be either both specified
> +    // or both unspecified. In the former case, the constructor must be
> +    // elidable.
> +    assert(ElidedCE && ElidedCE->isElidable() && ElidedCC);
> +  }
> +
> +public:
> +  const CXXConstructExpr *getConstructorAfterElision() const {
> +    return ElidedCE;
> +  }
> +
> +  const ConstructionContext *getConstructionContextAfterElision() const {
> +    return ElidedCC;
> +  }
> +
> +  static bool classof(const ConstructionContext *CC) {
> +    return CC->getKind() == ElidedTemporaryObjectKind;
>    }
>  };
>
>
> Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
> (original)
> +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Wed Jun
> 27 17:04:54 2018
> @@ -327,6 +327,9 @@ private:
>    /// \sa naiveCTUEnabled
>    Optional<bool> NaiveCTU;
>
> +  /// \sa shouldElideConstructors
> +  Optional<bool> ElideConstructors;
> +
>
>    /// A helper function that retrieves option for a given full-qualified
>    /// checker name.
> @@ -703,6 +706,13 @@ public:
>    /// This is an experimental feature to inline functions from another
>    /// translation units.
>    bool naiveCTUEnabled();
> +
> +  /// Returns true if elidable C++ copy-constructors and move-constructors
> +  /// should be actually elided during analysis. Both behaviors are
> allowed
> +  /// by the C++ standard, and the analyzer, like CodeGen, defaults to
> eliding.
> +  /// Starting with C++17 some elisions become mandatory, and in these
> cases
> +  /// the option will be ignored.
> +  bool shouldElideConstructors();
>  };
>
>  using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
>
> Modified: cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp (original)
> +++ cfe/trunk/lib/Analysis/AnalysisDeclContext.cpp Wed Jun 27 17:04:54 2018
> @@ -71,7 +71,8 @@ AnalysisDeclContextManager::AnalysisDecl
>      bool addInitializers, bool addTemporaryDtors, bool addLifetime,
>      bool addLoopExit, bool addScopes, bool synthesizeBodies,
>      bool addStaticInitBranch, bool addCXXNewAllocator,
> -    bool addRichCXXConstructors, CodeInjector *injector)
> +    bool addRichCXXConstructors, bool markElidedCXXConstructors,
> +    CodeInjector *injector)
>      : Injector(injector), FunctionBodyFarm(ASTCtx, injector),
>        SynthesizeBodies(synthesizeBodies) {
>    cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
> @@ -84,6 +85,7 @@ AnalysisDeclContextManager::AnalysisDecl
>    cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
>    cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
>    cfgBuildOptions.AddRichCXXConstructors = addRichCXXConstructors;
> +  cfgBuildOptions.MarkElidedCXXConstructors = markElidedCXXConstructors;
>  }
>
>  void AnalysisDeclContextManager::clear() { Contexts.clear(); }
>
> Modified: cfe/trunk/lib/Analysis/CFG.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CFG.cpp (original)
> +++ cfe/trunk/lib/Analysis/CFG.cpp Wed Jun 27 17:04:54 2018
> @@ -1252,10 +1252,22 @@ void CFGBuilder::findConstructionContext
>    if (!Child)
>      return;
>
> +  auto withExtraLayer = [this, Layer](Stmt *S) {
> +    return ConstructionContextLayer::create(cfg->getBumpVectorContext(),
> S,
> +                                            Layer);
> +  };
> +
>    switch(Child->getStmtClass()) {
>    case Stmt::CXXConstructExprClass:
>    case Stmt::CXXTemporaryObjectExprClass: {
> -    consumeConstructionContext(Layer, cast<CXXConstructExpr>(Child));
> +    // Support pre-C++17 copy elision AST.
> +    auto *CE = cast<CXXConstructExpr>(Child);
> +    if (BuildOpts.MarkElidedCXXConstructors && CE->isElidable()) {
> +      assert(CE->getNumArgs() == 1);
> +      findConstructionContexts(withExtraLayer(CE), CE->getArg(0));
> +    }
> +
> +    consumeConstructionContext(Layer, CE);
>      break;
>    }
>    // FIXME: This, like the main visit, doesn't support CUDAKernelCallExpr.
> @@ -1294,10 +1306,21 @@ void CFGBuilder::findConstructionContext
>    }
>    case Stmt::CXXBindTemporaryExprClass: {
>      auto *BTE = cast<CXXBindTemporaryExpr>(Child);
> -    findConstructionContexts(
> -        ConstructionContextLayer::create(cfg->getBumpVectorContext(),
> -                                         BTE, Layer),
> -        BTE->getSubExpr());
> +    findConstructionContexts(withExtraLayer(BTE), BTE->getSubExpr());
> +    break;
> +  }
> +  case Stmt::MaterializeTemporaryExprClass: {
> +    // Normally we don't want to search in MaterializeTemporaryExpr
> because
> +    // it indicates the beginning of a temporary object construction
> context,
> +    // so it shouldn't be found in the middle. However, if it is the
> beginning
> +    // of an elidable copy or move construction context, we need to
> include it.
> +    if (const auto *CE =
> +            dyn_cast_or_null<CXXConstructExpr>(Layer->getTriggerStmt())) {
> +      if (CE->isElidable()) {
> +        auto *MTE = cast<MaterializeTemporaryExpr>(Child);
> +        findConstructionContexts(withExtraLayer(MTE),
> MTE->GetTemporaryExpr());
> +      }
> +    }
>      break;
>    }
>    case Stmt::ConditionalOperatorClass: {
> @@ -4931,7 +4954,7 @@ static void print_initializer(raw_ostrea
>  static void print_construction_context(raw_ostream &OS,
>                                         StmtPrinterHelper &Helper,
>                                         const ConstructionContext *CC) {
> -  const Stmt *S1 = nullptr, *S2 = nullptr;
> +  SmallVector<const Stmt *, 3> Stmts;
>    switch (CC->getKind()) {
>    case ConstructionContext::SimpleConstructorInitializerKind: {
>      OS << ", ";
> @@ -4944,52 +4967,56 @@ static void print_construction_context(r
>      const auto *CICC =
>
>  cast<CXX17ElidedCopyConstructorInitializerConstructionContext>(CC);
>      print_initializer(OS, Helper, CICC->getCXXCtorInitializer());
> -    S2 = CICC->getCXXBindTemporaryExpr();
> +    Stmts.push_back(CICC->getCXXBindTemporaryExpr());
>      break;
>    }
>    case ConstructionContext::SimpleVariableKind: {
>      const auto *SDSCC = cast<SimpleVariableConstructionContext>(CC);
> -    S1 = SDSCC->getDeclStmt();
> +    Stmts.push_back(SDSCC->getDeclStmt());
>      break;
>    }
>    case ConstructionContext::CXX17ElidedCopyVariableKind: {
>      const auto *CDSCC =
> cast<CXX17ElidedCopyVariableConstructionContext>(CC);
> -    S1 = CDSCC->getDeclStmt();
> -    S2 = CDSCC->getCXXBindTemporaryExpr();
> +    Stmts.push_back(CDSCC->getDeclStmt());
> +    Stmts.push_back(CDSCC->getCXXBindTemporaryExpr());
>      break;
>    }
>    case ConstructionContext::NewAllocatedObjectKind: {
>      const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
> -    S1 = NECC->getCXXNewExpr();
> +    Stmts.push_back(NECC->getCXXNewExpr());
>      break;
>    }
>    case ConstructionContext::SimpleReturnedValueKind: {
>      const auto *RSCC = cast<SimpleReturnedValueConstructionContext>(CC);
> -    S1 = RSCC->getReturnStmt();
> +    Stmts.push_back(RSCC->getReturnStmt());
>      break;
>    }
>    case ConstructionContext::CXX17ElidedCopyReturnedValueKind: {
>      const auto *RSCC =
>          cast<CXX17ElidedCopyReturnedValueConstructionContext>(CC);
> -    S1 = RSCC->getReturnStmt();
> -    S2 = RSCC->getCXXBindTemporaryExpr();
> +    Stmts.push_back(RSCC->getReturnStmt());
> +    Stmts.push_back(RSCC->getCXXBindTemporaryExpr());
>      break;
>    }
> -  case ConstructionContext::TemporaryObjectKind: {
> -    const auto *TOCC = cast<TemporaryObjectConstructionContext>(CC);
> -    S1 = TOCC->getCXXBindTemporaryExpr();
> -    S2 = TOCC->getMaterializedTemporaryExpr();
> +  case ConstructionContext::SimpleTemporaryObjectKind: {
> +    const auto *TOCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
> +    Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
> +    Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
>      break;
>    }
> +  case ConstructionContext::ElidedTemporaryObjectKind: {
> +    const auto *TOCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
> +    Stmts.push_back(TOCC->getCXXBindTemporaryExpr());
> +    Stmts.push_back(TOCC->getMaterializedTemporaryExpr());
> +    Stmts.push_back(TOCC->getConstructorAfterElision());
> +    break;
>    }
> -  if (S1) {
> -    OS << ", ";
> -    Helper.handledStmt(const_cast<Stmt *>(S1), OS);
> -  }
> -  if (S2) {
> -    OS << ", ";
> -    Helper.handledStmt(const_cast<Stmt *>(S2), OS);
>    }
> +  for (auto I: Stmts)
> +    if (I) {
> +      OS << ", ";
> +      Helper.handledStmt(const_cast<Stmt *>(I), OS);
> +    }
>  }
>
>  static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
>
> Modified: cfe/trunk/lib/Analysis/ConstructionContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ConstructionContext.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ConstructionContext.cpp (original)
> +++ cfe/trunk/lib/Analysis/ConstructionContext.cpp Wed Jun 27 17:04:54 2018
> @@ -61,7 +61,6 @@ const ConstructionContext *ConstructionC
>        // For temporaries with destructors, there may or may not be
>        // lifetime extension on the parent layer.
>        if (const ConstructionContextLayer *ParentLayer =
> TopLayer->getParent()) {
> -        assert(ParentLayer->isLast());
>          // C++17 *requires* elision of the constructor at the return site
>          // and at variable/member initialization site, while previous
> standards
>          // were allowing an optional elidable constructor.
> @@ -77,8 +76,33 @@ const ConstructionContext *ConstructionC
>          // both destruction and materialization info attached to it in
> the AST.
>          if ((MTE = dyn_cast<MaterializeTemporaryExpr>(
>                   ParentLayer->getTriggerStmt()))) {
> -          return create<TemporaryObjectConstructionContext>(C, BTE, MTE);
> +          // Handle pre-C++17 copy and move elision.
> +          const CXXConstructExpr *ElidedCE = nullptr;
> +          const ConstructionContext *ElidedCC = nullptr;
> +          if (const ConstructionContextLayer *ElidedLayer =
> +                  ParentLayer->getParent()) {
> +            ElidedCE =
> cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
> +            assert(ElidedCE->isElidable());
> +            // We're creating a construction context that might have
> already
> +            // been created elsewhere. Maybe we should unique our
> construction
> +            // contexts. That's what we often do, but in this case it's
> unlikely
> +            // to bring any benefits.
> +            ElidedCC = createFromLayers(C, ElidedLayer->getParent());
> +            if (!ElidedCC) {
> +              // We may fail to create the elided construction context.
> +              // In this case, skip copy elision entirely.
> +              return create<SimpleTemporaryObjectConstructionContext>(C,
> BTE,
> +
> MTE);
> +            } else {
> +              return create<ElidedTemporaryObjectConstructionContext>(
> +                  C, BTE, MTE, ElidedCE, ElidedCC);
> +            }
> +          }
> +          assert(ParentLayer->isLast());
> +          return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
> MTE);
>          }
> +        assert(ParentLayer->isLast());
> +
>          // This is a constructor into a function argument. Not
> implemented yet.
>          if (isa<CallExpr>(ParentLayer->getTriggerStmt()))
>            return nullptr;
> @@ -99,7 +123,11 @@ const ConstructionContext *ConstructionC
>          llvm_unreachable("Unexpected construction context with
> destructor!");
>        }
>        // A temporary object that doesn't require materialization.
> -      return create<TemporaryObjectConstructionContext>(C, BTE,
> /*MTE=*/nullptr);
> +      // In particular, it shouldn't require copy elision, because
> +      // copy/move constructors take a reference, which requires
> +      // materialization to obtain the glvalue.
> +      return create<SimpleTemporaryObjectConstructionContext>(C, BTE,
> +
> /*MTE=*/nullptr);
>      }
>      if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(S)) {
>        // If the object requires destruction and is not lifetime-extended,
> @@ -110,8 +138,28 @@ const ConstructionContext *ConstructionC
>               MTE->getStorageDuration() != SD_FullExpression))
>          return nullptr;
>
> +      // Handle pre-C++17 copy and move elision.
> +      const CXXConstructExpr *ElidedCE = nullptr;
> +      const ConstructionContext *ElidedCC = nullptr;
> +      if (const ConstructionContextLayer *ElidedLayer =
> TopLayer->getParent()) {
> +        ElidedCE = cast<CXXConstructExpr>(ElidedLayer->getTriggerStmt());
> +        assert(ElidedCE->isElidable());
> +        // We're creating a construction context that might have already
> +        // been created elsewhere. Maybe we should unique our construction
> +        // contexts. That's what we often do, but in this case it's
> unlikely
> +        // to bring any benefits.
> +        ElidedCC = createFromLayers(C, ElidedLayer->getParent());
> +        if (!ElidedCC) {
> +          // We may fail to create the elided construction context.
> +          // In this case, skip copy elision entirely.
> +          return create<SimpleTemporaryObjectConstructionContext>(C,
> nullptr,
> +                                                                  MTE);
> +        }
> +        return create<ElidedTemporaryObjectConstructionContext>(
> +            C, nullptr, MTE, ElidedCE, ElidedCC);
> +      }
>        assert(TopLayer->isLast());
> -      return create<TemporaryObjectConstructionContext>(C, nullptr, MTE);
> +      return create<SimpleTemporaryObjectConstructionContext>(C, nullptr,
> MTE);
>      }
>      if (const auto *RS = dyn_cast<ReturnStmt>(S)) {
>        assert(TopLayer->isLast());
>
> Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Core/AnalysisManager.cpp Wed Jun 27
> 17:04:54 2018
> @@ -31,6 +31,7 @@ AnalysisManager::AnalysisManager(
>                  Options.shouldConditionalizeStaticInitializers(),
>                  /*addCXXNewAllocator=*/true,
>                  Options.includeRichConstructorsInCFG(),
> +                Options.shouldElideConstructors(),
>                  injector),
>        Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC),
>        CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
>
> Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Wed Jun 27
> 17:04:54 2018
> @@ -321,6 +321,12 @@ bool AnalyzerOptions::shouldSerializeSta
>                            /* Default = */ false);
>  }
>
> +bool AnalyzerOptions::shouldElideConstructors() {
> +  return getBooleanOption(ElideConstructors,
> +                          "elide-constructors",
> +                          /* Default = */ true);
> +}
> +
>  int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
>                                          const CheckerBase *C,
>                                          bool SearchInParents) {
>
> Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
> +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Wed Jun 27
> 17:04:54 2018
> @@ -209,7 +209,11 @@ std::pair<ProgramStateRef, SVal> ExprEng
>        }
>        llvm_unreachable("Unhandled return value construction context!");
>      }
> -    case ConstructionContext::TemporaryObjectKind: {
> +    case ConstructionContext::ElidedTemporaryObjectKind:
> +      assert(AMgr.getAnalyzerOptions().shouldElideConstructors());
> +      // FALL-THROUGH
> +    case ConstructionContext::SimpleTemporaryObjectKind: {
> +      // TODO: Copy elision implementation goes here.
>        const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
>        const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
>        const MaterializeTemporaryExpr *MTE =
> TCC->getMaterializedTemporaryExpr();
>
> Modified: cfe/trunk/test/Analysis/analyzer-config.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.c?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/analyzer-config.c (original)
> +++ cfe/trunk/test/Analysis/analyzer-config.c Wed Jun 27 17:04:54 2018
> @@ -18,6 +18,7 @@ void foo() {
>  // CHECK-NEXT: cfg-rich-constructors = true
>  // CHECK-NEXT: cfg-scopes = false
>  // CHECK-NEXT: cfg-temporary-dtors = true
> +// CHECK-NEXT: elide-constructors = true
>  // CHECK-NEXT: exploration_strategy = unexplored_first_queue
>  // CHECK-NEXT: faux-bodies = true
>  // CHECK-NEXT: graph-trim-interval = 1000
> @@ -35,4 +36,4 @@ void foo() {
>  // CHECK-NEXT: unroll-loops = false
>  // CHECK-NEXT: widen-loops = false
>  // CHECK-NEXT: [stats]
> -// CHECK-NEXT: num-entries = 23
> +// CHECK-NEXT: num-entries = 24
>
> Modified: cfe/trunk/test/Analysis/analyzer-config.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/analyzer-config.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/analyzer-config.cpp (original)
> +++ cfe/trunk/test/Analysis/analyzer-config.cpp Wed Jun 27 17:04:54 2018
> @@ -32,6 +32,7 @@ public:
>  // CHECK-NEXT: cfg-rich-constructors = true
>  // CHECK-NEXT: cfg-scopes = false
>  // CHECK-NEXT: cfg-temporary-dtors = true
> +// CHECK-NEXT: elide-constructors = true
>  // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false
>  // CHECK-NEXT: exploration_strategy = unexplored_first_queue
>  // CHECK-NEXT: faux-bodies = true
> @@ -50,4 +51,4 @@ public:
>  // CHECK-NEXT: unroll-loops = false
>  // CHECK-NEXT: widen-loops = false
>  // CHECK-NEXT: [stats]
> -// CHECK-NEXT: num-entries = 30
> +// CHECK-NEXT: num-entries = 31
>
> Modified: cfe/trunk/test/Analysis/cfg-rich-constructors.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg-rich-constructors.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/cfg-rich-constructors.cpp (original)
> +++ cfe/trunk/test/Analysis/cfg-rich-constructors.cpp Wed Jun 27 17:04:54
> 2018
> @@ -1,7 +1,11 @@
>  // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple
> x86_64-apple-darwin12 -std=c++11 -w %s > %t 2>&1
> -// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX11 %s
> +// RUN: FileCheck --input-file=%t
> -check-prefixes=CHECK,CXX11,ELIDE,CXX11-ELIDE %s
>  // RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple
> x86_64-apple-darwin12 -std=c++17 -w %s > %t 2>&1
> -// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,CXX17 %s
> +// RUN: FileCheck --input-file=%t
> -check-prefixes=CHECK,CXX17,ELIDE,CXX17-ELIDE %s
> +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple
> x86_64-apple-darwin12 -std=c++11 -w -analyzer-config
> elide-constructors=false %s > %t 2>&1
> +// RUN: FileCheck --input-file=%t
> -check-prefixes=CHECK,CXX11,NOELIDE,CXX11-NOELIDE %s
> +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG -triple
> x86_64-apple-darwin12 -std=c++17 -w -analyzer-config
> elide-constructors=false %s > %t 2>&1
> +// RUN: FileCheck --input-file=%t
> -check-prefixes=CHECK,CXX17,NOELIDE,CXX17-NOELIDE %s
>
>  class C {
>  public:
> @@ -99,10 +103,12 @@ void simpleVariableWithOperatorNewInBrac
>  // CHECK: void simpleVariableInitializedByValue()
>  // CHECK:          1: C::get
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
> +// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.5])
> +// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
>  // CXX11-NEXT:     4: [B1.3]
>  // CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
>  // CXX11-NEXT:     6: C c = C::get();
> +// CXX17-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
>  // CXX17-NEXT:     4: C c = C::get();
>  void simpleVariableInitializedByValue() {
>    C c = C::get();
> @@ -122,17 +128,21 @@ void simpleVariableInitializedByValue()
>  // CHECK:        [B2]
>  // CHECK-NEXT:     1: C::get
>  // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CXX11-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
> +// CXX11-ELIDE-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B2.5])
> +// CXX11-NOELIDE-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
>  // CXX11-NEXT:     4: [B2.3]
> -// CXX11-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], class C)
> +// CXX11-ELIDE-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], [B1.3],
> class C)
> +// CXX11-NOELIDE-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.2], class C)
>  // CXX17-NEXT:     3: [B2.2]()
>  // CHECK:        [B3]
>  // CHECK-NEXT:     1: 0
>  // CHECK-NEXT:     2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
> -// CXX11-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
> +// CXX11-ELIDE-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], [B3.6],
> class C)
> +// CXX11-NOELIDE-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
>  // CXX11-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CXX11-NEXT:     5: [B3.4]
> -// CXX11-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.2], class C)
> +// CXX11-ELIDE-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.2], [B1.3],
> class C)
> +// CXX11-NOELIDE-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.2], class C)
>  // CXX17-NEXT:     3: [B3.2] (CXXConstructExpr, class C)
>  // CXX17-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CHECK:        [B4]
> @@ -146,7 +156,9 @@ void simpleVariableWithTernaryOperator(b
>  // CHECK: void simpleVariableWithElidableCopy()
>  // CHECK:          1: 0
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
> -// CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
> +// CXX11-ELIDE-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], [B1.6],
> class C)
> +// CXX11-NOELIDE-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
> +// CXX17-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
>  // CHECK-NEXT:     4: C([B1.3]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CXX11-NEXT:     5: [B1.4]
>  // CXX11-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
> @@ -185,14 +197,16 @@ void referenceVariableWithInitializer()
>  // CHECK:        [B2]
>  // CHECK-NEXT:     1: C::get
>  // CHECK-NEXT:     2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CXX11-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
> +// CXX11-ELIDE-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4], [B2.5])
> +// CXX11-NOELIDE-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B2.4])
>  // CXX11-NEXT:     4: [B2.3]
>  // CXX11-NEXT:     5: [B2.4] (CXXConstructExpr, [B1.3], class C)
>  // CXX17-NEXT:     3: [B2.2]() (CXXRecordTypedCall, [B1.3])
>  // CHECK:        [B3]
>  // CHECK-NEXT:     1: 0
>  // CHECK-NEXT:     2: [B3.1] (ImplicitCastExpr, NullToPointer, class C *)
> -// CXX11-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
> +// CXX11-ELIDE-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], [B3.6],
> class C)
> +// CXX11-NOELIDE-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.5], class C)
>  // CXX11-NEXT:     4: C([B3.3]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CXX11-NEXT:     5: [B3.4]
>  // CXX11-NEXT:     6: [B3.5] (CXXConstructExpr, [B1.3], class C)
> @@ -242,7 +256,8 @@ public:
>  // CHECK-NEXT:     7: CFGNewAllocator(C *)
>  // CHECK-NEXT:     8: C::get
>  // CHECK-NEXT:     9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CXX11-NEXT:    10: [B1.9]() (CXXRecordTypedCall, [B1.11])
> +// CXX11-ELIDE-NEXT:    10: [B1.9]() (CXXRecordTypedCall, [B1.11],
> [B1.12])
> +// CXX11-NOELIDE-NEXT:    10: [B1.9]() (CXXRecordTypedCall, [B1.11])
>  // CXX11-NEXT:    11: [B1.10]
>  // CXX11-NEXT:    12: [B1.11] (CXXConstructExpr, [B1.13], class C)
>  // CXX11-NEXT:    13: new C([B1.12])
> @@ -270,7 +285,8 @@ public:
>  // CHECK: F()
>  // CHECK:          1: E::get
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class ctor_initializers::E (*)(
> -// CXX11-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6])
> +// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6],
> [B1.7])
> +// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4],
> [B1.6])
>  // CXX11-NEXT:     4: [B1.3] (BindTemporary)
>  // CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class
> ctor_initializers::E)
>  // CXX11-NEXT:     6: [B1.5]
> @@ -326,10 +342,12 @@ C returnBracesWithMultipleItems() {
>  }
>
>  // CHECK: C returnTemporary()
> -// CHECK:          1: C() (CXXConstructExpr, [B1.2], class C)
> +// CXX11-ELIDE:    1: C() (CXXConstructExpr, [B1.2], [B1.3], class C)
> +// CXX11-NOELIDE:  1: C() (CXXConstructExpr, [B1.2], class C)
>  // CXX11-NEXT:     2: [B1.1]
>  // CXX11-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.4], class C)
>  // CXX11-NEXT:     4: return [B1.3];
> +// CXX17:          1: C() (CXXConstructExpr, [B1.2], class C)
>  // CXX17-NEXT:     2: return [B1.1];
>  C returnTemporary() {
>    return C();
> @@ -338,7 +356,9 @@ C returnTemporary() {
>  // CHECK: C returnTemporaryWithArgument()
>  // CHECK:          1: nullptr
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, NullToPointer, class C *)
> -// CHECK-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
> +// CXX11-ELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], [B1.6], class C)
> +// CXX11-NOELIDE-NEXT: 3: [B1.2] (CXXConstructExpr, [B1.5], class C)
> +// CXX17-NEXT:     3: [B1.2] (CXXConstructExpr, [B1.5], class C)
>  // CHECK-NEXT:     4: C([B1.3]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CXX11-NEXT:     5: [B1.4]
>  // CXX11-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.7], class C)
> @@ -352,10 +372,12 @@ C returnTemporaryWithArgument() {
>  // CHECK: C returnTemporaryConstructedByFunction()
>  // CHECK:          1: C::get
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
> +// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.5])
> +// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
>  // CXX11-NEXT:     4: [B1.3]
>  // CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.6], class C)
>  // CXX11-NEXT:     6: return [B1.5];
> +// CXX17-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
>  // CXX17-NEXT:     4: return [B1.3];
>  C returnTemporaryConstructedByFunction() {
>    return C::get();
> @@ -364,9 +386,11 @@ C returnTemporaryConstructedByFunction()
>  // CHECK: C returnChainOfCopies()
>  // CHECK:          1: C::get
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class C (*)(void))
> -// CXX11-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
> +// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.5])
> +// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4])
>  // CXX11-NEXT:     4: [B1.3]
> -// CXX11-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], class C)
> +// CXX11-ELIDE-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], [B1.8],
> class C)
> +// CXX11-NOELIDE-NEXT:     5: [B1.4] (CXXConstructExpr, [B1.7], class C)
>  // CXX11-NEXT:     6: C([B1.5]) (CXXFunctionalCastExpr,
> ConstructorConversion, class C)
>  // CXX11-NEXT:     7: [B1.6]
>  // CXX11-NEXT:     8: [B1.7] (CXXConstructExpr, [B1.9], class C)
> @@ -390,7 +414,8 @@ public:
>
>  // FIXME: There should be no temporary destructor in C++17.
>  // CHECK:  return_stmt_with_dtor::D returnTemporary()
> -// CXX11:          1: return_stmt_with_dtor::D() (CXXConstructExpr,
> [B1.2], [B1.4], class return_stmt_with_dtor::D)
> +// CXX11-ELIDE:          1: return_stmt_with_dtor::D() (CXXConstructExpr,
> [B1.2], [B1.4], [B1.5], class return_stmt_with_dtor::D)
> +// CXX11-NOELIDE:          1: return_stmt_with_dtor::D()
> (CXXConstructExpr, [B1.2], [B1.4], class return_stmt_with_dtor::D)
>  // CXX11-NEXT:     2: [B1.1] (BindTemporary)
>  // CXX11-NEXT:     3: [B1.2] (ImplicitCastExpr, NoOp, const class
> return_stmt_with_dtor::D)
>  // CXX11-NEXT:     4: [B1.3]
> @@ -409,7 +434,8 @@ D returnTemporary() {
>  // CHECK: void returnByValueIntoVariable()
>  // CHECK:          1: returnTemporary
>  // CHECK-NEXT:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class return_stmt_with_dtor::D (*)(void))
> -// CXX11-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6])
> +// CXX11-ELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6],
> [B1.7])
> +// CXX11-NOELIDE-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.4],
> [B1.6])
>  // CXX11-NEXT:     4: [B1.3] (BindTemporary)
>  // CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, NoOp, const class
> return_stmt_with_dtor::D)
>  // CXX11-NEXT:     6: [B1.5]
> @@ -451,7 +477,8 @@ void temporaryInCondition() {
>  }
>
>  // CHECK: void temporaryInConditionVariable()
> -// CHECK:          1: C() (CXXConstructExpr, [B2.2], class C)
> +// CXX11-ELIDE:    1: C() (CXXConstructExpr, [B2.2], [B2.3], class C)
> +// CXX11-NOELIDE:  1: C() (CXXConstructExpr, [B2.2], class C)
>  // CXX11-NEXT:     2: [B2.1]
>  // CXX11-NEXT:     3: [B2.2] (CXXConstructExpr, [B2.4], class C)
>  // CXX11-NEXT:     4: C c = C();
> @@ -461,6 +488,7 @@ void temporaryInCondition() {
>  // CXX11-NEXT:     8: [B2.6]
>  // CXX11-NEXT:     9: [B2.8] (ImplicitCastExpr, UserDefinedConversion,
> _Bool)
>  // CXX11-NEXT:     T: if [B2.9]
> +// CXX17:          1: C() (CXXConstructExpr, [B2.2], class C)
>  // CXX17-NEXT:     2: C c = C();
>  // CXX17-NEXT:     3: c
>  // CXX17-NEXT:     4: [B2.3] (ImplicitCastExpr, NoOp, const class C)
> @@ -475,7 +503,8 @@ void temporaryInConditionVariable() {
>
>  // CHECK: void temporaryInForLoopConditionVariable()
>  // CHECK:        [B2]
> -// CXX11-NEXT:     1: C() (CXXConstructExpr, [B2.2], class C)
> +// CXX11-ELIDE-NEXT:     1: C() (CXXConstructExpr, [B2.2], [B2.3], class
> C)
> +// CXX11-NOELIDE-NEXT:     1: C() (CXXConstructExpr, [B2.2], class C)
>  // CXX11-NEXT:     2: [B2.1]
>  // CXX11-NEXT:     3: [B2.2] (CXXConstructExpr, [B2.4], class C)
>  // CXX11-NEXT:     4: C c2 = C();
> @@ -494,7 +523,8 @@ void temporaryInConditionVariable() {
>  // CXX17-NEXT:     7: [B2.6] (ImplicitCastExpr, UserDefinedConversion,
> _Bool)
>  // CXX17-NEXT:     T: for (...; [B2.7]; )
>  // CHECK:        [B3]
> -// CXX11-NEXT:     1: C() (CXXConstructExpr, [B3.2], class C)
> +// CXX11-ELIDE-NEXT:     1: C() (CXXConstructExpr, [B3.2], [B3.3], class
> C)
> +// CXX11-NOELIDE-NEXT:     1: C() (CXXConstructExpr, [B3.2], class C)
>  // CXX11-NEXT:     2: [B3.1]
>  // CXX11-NEXT:     3: [B3.2] (CXXConstructExpr, [B3.4], class C)
>  // CXX11-NEXT:     4: C c1 = C();
> @@ -505,9 +535,9 @@ void temporaryInForLoopConditionVariable
>  }
>
>
> -// FIXME: Find construction context for the loop condition variable.
>  // CHECK: void temporaryInWhileLoopConditionVariable()
> -// CXX11:          1: C() (CXXConstructExpr, [B2.2], class C)
> +// CXX11-ELIDE:          1: C() (CXXConstructExpr, [B2.2], [B2.3], class
> C)
> +// CXX11-NOELIDE:          1: C() (CXXConstructExpr, [B2.2], class C)
>  // CXX11-NEXT:     2: [B2.1]
>  // CXX11-NEXT:     3: [B2.2] (CXXConstructExpr, [B2.4], class C)
>  // CXX11-NEXT:     4: C c = C();
> @@ -603,7 +633,8 @@ void referenceVariableWithInitializer()
>  // CXX11:        [B5]
>  // CXX11-NEXT:     1: D::get
>  // CXX11-NEXT:     2: [B5.1] (ImplicitCastExpr, FunctionToPointerDecay,
> class temporary_object_expr_with_dtors::D (*)(void))
> -// CXX11-NEXT:     3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6])
> +// CXX11-ELIDE-NEXT:     3: [B5.2]() (CXXRecordTypedCall, [B5.4], [B5.6],
> [B5.7])
> +// CXX11-NOELIDE-NEXT:     3: [B5.2]() (CXXRecordTypedCall, [B5.4],
> [B5.6])
>  // CXX11-NEXT:     4: [B5.3] (BindTemporary)
>  // CXX11-NEXT:     5: [B5.4] (ImplicitCastExpr, NoOp, const class
> temporary_object_expr_with_dtors::D)
>  // CXX11-NEXT:     6: [B5.5]
> @@ -611,7 +642,8 @@ void referenceVariableWithInitializer()
>  // CXX11-NEXT:     8: [B5.7] (BindTemporary)
>  // CXX11:        [B6]
>  // CXX11-NEXT:     1: 0
> -// CXX11-NEXT:     2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6], class
> temporary_object_expr_with_dtors::D)
> +// CXX11-ELIDE-NEXT:     2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6],
> [B6.7], class temporary_object_expr_with_dtors::D)
> +// CXX11-NOELIDE-NEXT:     2: [B6.1] (CXXConstructExpr, [B6.3], [B6.6],
> class temporary_object_expr_with_dtors::D)
>  // CXX11-NEXT:     3: [B6.2] (BindTemporary)
>  // CXX11-NEXT:     4: temporary_object_expr_with_dtors::D([B6.3])
> (CXXFunctionalCastExpr, ConstructorConversion, class
> temporary_object_expr_with_dtors::D)
>  // CXX11-NEXT:     5: [B6.4] (ImplicitCastExpr, NoOp, const class
> temporary_object_expr_with_dtors::D)
> @@ -699,7 +731,8 @@ public:
>  // CHECK:          1: implicit_constructor_conversion::A()
> (CXXConstructExpr, [B1.3], class implicit_constructor_conversion::A)
>  // CXX11-NEXT:     2: [B1.1] (ImplicitCastExpr, NoOp, const class
> implicit_constructor_conversion::A)
>  // CXX11-NEXT:     3: [B1.2]
> -// CXX11-NEXT:     4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8], class
> implicit_constructor_conversion::B)
> +// CXX11-ELIDE-NEXT:     4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8],
> [B1.9], class implicit_constructor_conversion::B)
> +// CXX11-NOELIDE-NEXT:     4: [B1.3] (CXXConstructExpr, [B1.6], [B1.8],
> class implicit_constructor_conversion::B)
>  // CXX11-NEXT:     5: [B1.4] (ImplicitCastExpr, ConstructorConversion,
> class implicit_constructor_conversion::B)
>  // CXX11-NEXT:     6: [B1.5] (BindTemporary)
>  // CXX11-NEXT:     7: [B1.6] (ImplicitCastExpr, NoOp, const class
> implicit_constructor_conversion::B)
> @@ -724,7 +757,8 @@ void implicitConstructionConversionFromT
>  // CHECK-NEXT:     3: [B1.2]() (CXXRecordTypedCall, [B1.5])
>  // CHECK-NEXT:     4: [B1.3] (ImplicitCastExpr, NoOp, const class
> implicit_constructor_conversion::A)
>  // CHECK-NEXT:     5: [B1.4]
> -// CXX11-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10], class
> implicit_constructor_conversion::B)
> +// CXX11-ELIDE-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10],
> [B1.11], class implicit_constructor_conversion::B)
> +// CXX11-NOELIDE-NEXT:     6: [B1.5] (CXXConstructExpr, [B1.8], [B1.10],
> class implicit_constructor_conversion::B)
>  // CXX11-NEXT:     7: [B1.6] (ImplicitCastExpr, ConstructorConversion,
> class implicit_constructor_conversion::B)
>  // CXX11-NEXT:     8: [B1.7] (BindTemporary)
>  // CXX11-NEXT:     9: [B1.8] (ImplicitCastExpr, NoOp, const class
> implicit_constructor_conversion::B)
>
> Modified: cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp?rev=335795&r1=335794&r2=335795&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp (original)
> +++ cfe/trunk/test/Analysis/temp-obj-dtors-cfg-output.cpp Wed Jun 27
> 17:04:54 2018
> @@ -235,7 +235,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B1
>  // CHECK:   [B1]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class
> A)
>  // CHECK:     2: [B1.1] (BindTemporary)
>  // CHECK:     3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B1.3]
> @@ -295,7 +295,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B1
>  // CHECK:   [B1]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class
> A)
>  // CHECK:     2: [B1.1] (BindTemporary)
>  // CHECK:     3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B1.3]
> @@ -550,12 +550,12 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (2): B6 B5
>  // CHECK:   [B8]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B8.2], [B8.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B8.2], [B8.4], [B8.5], class
> A)
>  // CHECK:     2: [B8.1] (BindTemporary)
>  // CHECK:     3: [B8.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B8.3]
>  // WARNINGS:     5: [B8.4] (CXXConstructExpr, class A)
> -// ANALYZER:     5: [B8.4] (CXXConstructExpr, [B8.6], [B7.3], class A)
> +// ANALYZER:     5: [B8.4] (CXXConstructExpr, [B8.6], [B7.3], [B7.4],
> class A)
>  // CHECK:     6: [B8.5] (BindTemporary)
>  // CHECK:     Preds (1): B10
>  // CHECK:     Succs (1): B7
> @@ -570,13 +570,13 @@ const C &bar3(bool coin) {
>  // CHECK:     7: [B9.6] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     8: [B9.7]
>  // WARNINGS:     9: [B9.8] (CXXConstructExpr, class A)
> -// ANALYZER:     9: [B9.8] (CXXConstructExpr, [B9.10], [B9.13], class A)
> +// ANALYZER:     9: [B9.8] (CXXConstructExpr, [B9.10], [B9.13], [B9.14],
> class A)
>  // CHECK:    10: [B9.9] (BindTemporary)
>  // CHECK:    11: A([B9.10]) (CXXFunctionalCastExpr,
> ConstructorConversion, class A)
>  // CHECK:    12: [B9.11] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:    13: [B9.12]
>  // WARNINGS:    14: [B9.13] (CXXConstructExpr, class A)
> -// ANALYZER:    14: [B9.13] (CXXConstructExpr, [B9.15], [B7.3], class A)
> +// ANALYZER:    14: [B9.13] (CXXConstructExpr, [B9.15], [B7.3], [B7.4],
> class A)
>  // CHECK:    15: [B9.14] (BindTemporary)
>  // CHECK:     Preds (1): B10
>  // CHECK:     Succs (1): B7
> @@ -680,7 +680,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B0
>  // CHECK:   [B4]
>  // WARNINGS:     1: C() (CXXConstructExpr, struct C)
> -// ANALYZER:     1: C() (CXXConstructExpr, [B4.2], [B4.4], struct C)
> +// ANALYZER:     1: C() (CXXConstructExpr, [B4.2], [B4.4], [B4.5], struct
> C)
>  // CHECK:     2: [B4.1] (BindTemporary)
>  // CHECK:     3: [B4.2] (ImplicitCastExpr, NoOp, const struct C)
>  // CHECK:     4: [B4.3]
> @@ -733,7 +733,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B0
>  // CHECK:   [B3]
>  // CXX98-WARNINGS:     1: D() (CXXConstructExpr, struct D)
> -// CXX98-ANALYZER:     1: D() (CXXConstructExpr, [B3.3], struct D)
> +// CXX98-ANALYZER:     1: D() (CXXConstructExpr, [B3.3], [B3.4], struct D)
>  // CXX98:     2: [B3.1] (ImplicitCastExpr, NoOp, const struct D)
>  // CXX98:     3: [B3.2]
>  // CXX98-WARNINGS:     4: [B3.3] (CXXConstructExpr, struct D)
> @@ -745,7 +745,7 @@ const C &bar3(bool coin) {
>  // CXX98:     9: [B3.8] (ImplicitCastExpr, UserDefinedConversion, _Bool)
>  // CXX98:     T: if [B3.9]
>  // CXX11-WARNINGS:     1: D() (CXXConstructExpr, struct D)
> -// CXX11-ANALYZER:     1: D() (CXXConstructExpr, [B3.2], struct D)
> +// CXX11-ANALYZER:     1: D() (CXXConstructExpr, [B3.2], [B3.3], struct D)
>  // CXX11:     2: [B3.1]
>  // CXX11-WARNINGS:     3: [B3.2] (CXXConstructExpr, struct D)
>  // CXX11-ANALYZER:     3: [B3.2] (CXXConstructExpr, [B3.4], struct D)
> @@ -789,7 +789,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (2): B3 B2
>  // CHECK:   [B5]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B5.2], [B5.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B5.2], [B5.4], [B5.5], class
> A)
>  // CHECK:     2: [B5.1] (BindTemporary)
>  // CHECK:     3: [B5.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B5.3]
> @@ -809,7 +809,7 @@ const C &bar3(bool coin) {
>  // CHECK:     7: [B6.6] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     8: [B6.7]
>  // WARNINGS:     9: [B6.8] (CXXConstructExpr, class A)
> -// ANALYZER:     9: [B6.8] (CXXConstructExpr, [B6.10], [B6.13], class A)
> +// ANALYZER:     9: [B6.8] (CXXConstructExpr, [B6.10], [B6.13], [B6.14],
> class A)
>  // CHECK:    10: [B6.9] (BindTemporary)
>  // CHECK:    11: A([B6.10]) (CXXFunctionalCastExpr,
> ConstructorConversion, class A)
>  // CHECK:    12: [B6.11] (ImplicitCastExpr, NoOp, const class A)
> @@ -852,7 +852,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (2): B9 B8
>  // CHECK:   [B11]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B11.2], [B11.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B11.2], [B11.4], [B11.5],
> class A)
>  // CHECK:     2: [B11.1] (BindTemporary)
>  // CHECK:     3: [B11.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B11.3]
> @@ -872,7 +872,7 @@ const C &bar3(bool coin) {
>  // CHECK:     7: [B12.6] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     8: [B12.7]
>  // WARNINGS:     9: [B12.8] (CXXConstructExpr, class A)
> -// ANALYZER:     9: [B12.8] (CXXConstructExpr, [B12.10], [B12.13], class
> A)
> +// ANALYZER:     9: [B12.8] (CXXConstructExpr, [B12.10], [B12.13],
> [B12.14], class A)
>  // CHECK:    10: [B12.9] (BindTemporary)
>  // CHECK:    11: A([B12.10]) (CXXFunctionalCastExpr,
> ConstructorConversion, class A)
>  // CHECK:    12: [B12.11] (ImplicitCastExpr, NoOp, const class A)
> @@ -935,7 +935,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B4
>  // CHECK:   [B6]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B6.2], [B6.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B6.2], [B6.4], [B6.5], class
> A)
>  // CHECK:     2: [B6.1] (BindTemporary)
>  // CHECK:     3: [B6.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B6.3]
> @@ -1001,7 +1001,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B4
>  // CHECK:   [B6]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B6.2], [B6.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B6.2], [B6.4], [B6.5], class
> A)
>  // CHECK:     2: [B6.1] (BindTemporary)
>  // CHECK:     3: [B6.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B6.3]
> @@ -1086,7 +1086,7 @@ const C &bar3(bool coin) {
>  // CHECK:     Succs (1): B1
>  // CHECK:   [B1]
>  // WARNINGS:     1: A() (CXXConstructExpr, class A)
> -// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], class A)
> +// ANALYZER:     1: A() (CXXConstructExpr, [B1.2], [B1.4], [B1.5], class
> A)
>  // CHECK:     2: [B1.1] (BindTemporary)
>  // CHECK:     3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     4: [B1.3]
> @@ -1130,7 +1130,7 @@ const C &bar3(bool coin) {
>  // CHECK:     1: A::make
>  // CHECK:     2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, class
> A (*)(void))
>  // WARNINGS:     3: [B1.2]()
> -// ANALYZER:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6])
> +// ANALYZER:     3: [B1.2]() (CXXRecordTypedCall, [B1.4], [B1.6], [B1.7])
>  // CHECK:     4: [B1.3] (BindTemporary)
>  // CHECK:     5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
>  // CHECK:     6: [B1.5]
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180704/ef415223/attachment-0001.html>


More information about the cfe-commits mailing list