Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -116,6 +116,10 @@ /// \brief Whether the entity being initialized may end up using the /// named return value optimization (NRVO). bool NRVO; + + /// \brief Whether the initialization is from the last expression of + /// a GNU statement expression. + bool GNUStatementExpression; }; struct C { @@ -169,11 +173,12 @@ /// function, throwing an object, performing an explicit cast, or /// initializing a parameter for which there is no declaration. InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, - bool NRVO = false) + bool NRVO = false, bool GNUStatementExpression = false) : Kind(Kind), Parent(nullptr), Type(Type), ManglingNumber(0) { LocAndNRVO.Location = Loc.getRawEncoding(); LocAndNRVO.NRVO = NRVO; + LocAndNRVO.GNUStatementExpression = GNUStatementExpression; } /// \brief Create the initialization entity for a member subobject. @@ -238,9 +243,11 @@ } /// \brief Create the initialization entity for the result of a function. - static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); + static InitializedEntity + InitializeResult(SourceLocation ReturnLoc, QualType Type, bool NRVO, + bool GNUStatementExpression = false) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO, + GNUStatementExpression); } static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, @@ -364,6 +371,10 @@ /// value optimization, which also applies to thrown objects. bool allowsNRVO() const; + /// \brief Determine whether this initializiation is from the final + /// expression of GNU statement expression. + bool isGNUStatementExpression() const; + bool isParameterKind() const { return (getKind() == EK_Parameter || getKind() == EK_Parameter_CF_Audited); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11149,11 +11149,8 @@ LastExpr = rebuiltLastStmt; } else { LastExpr = PerformCopyInitialization( - InitializedEntity::InitializeResult(LPLoc, - Ty, - false), - SourceLocation(), - LastExpr); + InitializedEntity::InitializeResult(LPLoc, Ty, false, true), + SourceLocation(), LastExpr); } if (LastExpr.isInvalid()) Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -2887,6 +2887,34 @@ return false; } +bool InitializedEntity::isGNUStatementExpression() const { + switch (getKind()) { + case EK_Result: + return LocAndNRVO.GNUStatementExpression; + + case EK_Exception: + case EK_Variable: + case EK_Parameter: + case EK_Parameter_CF_Audited: + case EK_Member: + case EK_New: + case EK_Temporary: + case EK_CompoundLiteralInit: + case EK_Base: + case EK_Delegating: + case EK_ArrayElement: + case EK_VectorElement: + case EK_ComplexElement: + case EK_BlockElement: + case EK_LambdaCapture: + case EK_RelatedResult: + break; + } + + return false; +} + + unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { assert(getParent() != this); unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0; @@ -6771,8 +6799,9 @@ // Check for std::move on construction. if (const Expr *E = CurInit.get()) { - CheckMoveOnConstruction(S, E, - Entity.getKind() == InitializedEntity::EK_Result); + if (!Entity.isGNUStatementExpression()) + CheckMoveOnConstruction(S, E, + Entity.getKind() == InitializedEntity::EK_Result); } return CurInit; Index: test/SemaCXX/warn-pessmizing-move.cpp =================================================================== --- test/SemaCXX/warn-pessmizing-move.cpp +++ test/SemaCXX/warn-pessmizing-move.cpp @@ -227,3 +227,22 @@ test2(); } } + +// Don't warn on GNU statement expressions. +namespace GNU { + class A {}; + class B { + public: + B(); + B(B &&); + private: + B(const B &); + }; + + void test() { + A a = ({auto a = A(); std::move(a); }); + B b = ({auto b = B(); std::move(b); }); + } + + auto b = std::move(B()); +}