Revert "[Sema] Implement C++14's DR1579: Prefer returning by converting move constructor"
This reverts commit 1b983cb0af73b792c5cdc14bed5394082709a8fe.
This causes miscompile with __block shared_ptr.
<rdar://problem/28171437>
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index b26bd7c..09f24cc 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -959,9 +959,6 @@
step_iterator step_begin() const { return Steps.begin(); }
step_iterator step_end() const { return Steps.end(); }
- typedef llvm::iterator_range<step_iterator> step_range;
- step_range steps() const { return {step_begin(), step_end()}; }
-
/// \brief Determine whether this initialization is a direct reference
/// binding (C++ [dcl.init.ref]).
bool isDirectReferenceBinding() const;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index e55ac72..4943d40 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3520,9 +3520,9 @@
SourceLocation Loc,
unsigned NumParams);
VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
- bool AllowParamOrMoveConstructible);
+ bool AllowFunctionParameters);
bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
- bool AllowParamOrMoveConstructible);
+ bool AllowFunctionParameters);
StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 977d744..0ba1e6b 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2694,16 +2694,16 @@
/// \param E The expression being returned from the function or block, or
/// being thrown.
///
-/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
-/// id-expressions that could be moved out of the function to be considered NRVO
-/// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to
-/// determine whether we should try to move as part of a return or throw (which
-/// does allow function parameters).
+/// \param AllowFunctionParameter Whether we allow function parameters to
+/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but
+/// we re-use this logic to determine whether we should try to move as part of
+/// a return or throw (which does allow function parameters).
///
/// \returns The NRVO candidate variable, if the return statement may use the
/// NRVO, or NULL if there is no such candidate.
-VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E,
- bool AllowParamOrMoveConstructible) {
+VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
+ Expr *E,
+ bool AllowFunctionParameter) {
if (!getLangOpts().CPlusPlus)
return nullptr;
@@ -2716,13 +2716,13 @@
if (!VD)
return nullptr;
- if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
+ if (isCopyElisionCandidate(ReturnType, VD, AllowFunctionParameter))
return VD;
return nullptr;
}
bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
- bool AllowParamOrMoveConstructible) {
+ bool AllowFunctionParameter) {
QualType VDType = VD->getType();
// - in a return statement in a function with ...
// ... a class return type ...
@@ -2730,24 +2730,20 @@
if (!ReturnType->isRecordType())
return false;
// ... the same cv-unqualified type as the function return type ...
- // When considering moving this expression out, allow dissimilar types.
- if (!AllowParamOrMoveConstructible && !VDType->isDependentType() &&
+ if (!VDType->isDependentType() &&
!Context.hasSameUnqualifiedType(ReturnType, VDType))
return false;
}
// ...object (other than a function or catch-clause parameter)...
if (VD->getKind() != Decl::Var &&
- !(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar))
+ !(AllowFunctionParameter && VD->getKind() == Decl::ParmVar))
return false;
if (VD->isExceptionVariable()) return false;
// ...automatic...
if (!VD->hasLocalStorage()) return false;
- if (AllowParamOrMoveConstructible)
- return true;
-
// ...non-volatile...
if (VD->getType().isVolatileQualified()) return false;
@@ -2766,7 +2762,7 @@
/// \brief Perform the initialization of a potentially-movable value, which
/// is the result of return value.
///
-/// This routine implements C++14 [class.copy]p32, which attempts to treat
+/// This routine implements C++0x [class.copy]p33, which attempts to treat
/// returned lvalues as rvalues in certain cases (to prefer move construction),
/// then falls back to treating them as lvalues if that failed.
ExprResult
@@ -2775,59 +2771,52 @@
QualType ResultType,
Expr *Value,
bool AllowNRVO) {
- // C++14 [class.copy]p32:
- // When the criteria for elision of a copy/move operation are met, but not for
- // an exception-declaration, and the object to be copied is designated by an
- // lvalue, or when the expression in a return statement is a (possibly
- // parenthesized) id-expression that names an object with automatic storage
- // duration declared in the body or parameter-declaration-clause of the
- // innermost enclosing function or lambda-expression, overload resolution to
- // select the constructor for the copy is first performed as if the object
- // were designated by an rvalue.
+ // C++0x [class.copy]p33:
+ // When the criteria for elision of a copy operation are met or would
+ // be met save for the fact that the source object is a function
+ // parameter, and the object to be copied is designated by an lvalue,
+ // overload resolution to select the constructor for the copy is first
+ // performed as if the object were designated by an rvalue.
ExprResult Res = ExprError();
-
- if (AllowNRVO && !NRVOCandidate)
- NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true);
-
- if (AllowNRVO && NRVOCandidate) {
- ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
- CK_NoOp, Value, VK_XValue);
+ if (AllowNRVO &&
+ (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
+ ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
+ Value->getType(), CK_NoOp, Value, VK_XValue);
Expr *InitExpr = &AsRvalue;
-
- InitializationKind Kind = InitializationKind::CreateCopy(
- Value->getLocStart(), Value->getLocStart());
-
+ InitializationKind Kind
+ = InitializationKind::CreateCopy(Value->getLocStart(),
+ Value->getLocStart());
InitializationSequence Seq(*this, Entity, Kind, InitExpr);
+
+ // [...] If overload resolution fails, or if the type of the first
+ // parameter of the selected constructor is not an rvalue reference
+ // to the object's type (possibly cv-qualified), overload resolution
+ // is performed again, considering the object as an lvalue.
if (Seq) {
- for (const InitializationSequence::Step &Step : Seq.steps()) {
- if (!(Step.Kind ==
- InitializationSequence::SK_ConstructorInitialization ||
- (Step.Kind == InitializationSequence::SK_UserConversion &&
- isa<CXXConstructorDecl>(Step.Function.Function))))
+ for (InitializationSequence::step_iterator Step = Seq.step_begin(),
+ StepEnd = Seq.step_end();
+ Step != StepEnd; ++Step) {
+ if (Step->Kind != InitializationSequence::SK_ConstructorInitialization)
continue;
- CXXConstructorDecl *Constructor =
- cast<CXXConstructorDecl>(Step.Function.Function);
+ CXXConstructorDecl *Constructor
+ = cast<CXXConstructorDecl>(Step->Function.Function);
const RValueReferenceType *RRefType
= Constructor->getParamDecl(0)->getType()
->getAs<RValueReferenceType>();
- // [...] If the first overload resolution fails or was not performed, or
- // if the type of the first parameter of the selected constructor is not
- // an rvalue reference to the object’s type (possibly cv-qualified),
- // overload resolution is performed again, considering the object as an
- // lvalue.
+ // If we don't meet the criteria, break out now.
if (!RRefType ||
!Context.hasSameUnqualifiedType(RRefType->getPointeeType(),
- NRVOCandidate->getType()))
+ Context.getTypeDeclType(Constructor->getParent())))
break;
// Promote "AsRvalue" to the heap, since we now need this
// expression node to persist.
- Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp,
- Value, nullptr, VK_XValue);
+ Value = ImplicitCastExpr::Create(Context, Value->getType(),
+ CK_NoOp, Value, nullptr, VK_XValue);
// Complete type-checking the initialization of the return type
// using the constructor we found.
diff --git a/test/CXX/drs/dr15xx.cpp b/test/CXX/drs/dr15xx.cpp
index 5f85a19..4398234 100644
--- a/test/CXX/drs/dr15xx.cpp
+++ b/test/CXX/drs/dr15xx.cpp
@@ -87,62 +87,6 @@
} // std
-namespace dr1579 { // dr1579: 3.9
-template<class T>
-struct GenericMoveOnly {
- GenericMoveOnly();
- template<class U> GenericMoveOnly(const GenericMoveOnly<U> &) = delete; // expected-note 5 {{marked deleted here}}
- GenericMoveOnly(const int &) = delete; // expected-note 2 {{marked deleted here}}
- template<class U> GenericMoveOnly(GenericMoveOnly<U> &&);
- GenericMoveOnly(int &&);
-};
-
-GenericMoveOnly<float> DR1579_Eligible(GenericMoveOnly<char> CharMO) {
- int i;
- GenericMoveOnly<char> GMO;
-
- if (0)
- return i;
- else if (0)
- return GMO;
- else if (0)
- return ((GMO));
- else
- return CharMO;
-}
-
-GenericMoveOnly<char> GlobalMO;
-
-GenericMoveOnly<float> DR1579_Ineligible(int &AnInt,
- GenericMoveOnly<char> &CharMO) {
- static GenericMoveOnly<char> StaticMove;
- extern GenericMoveOnly<char> ExternMove;
-
- if (0)
- return AnInt; // expected-error{{invokes a deleted function}}
- else if (0)
- return GlobalMO; // expected-error{{invokes a deleted function}}
- else if (0)
- return StaticMove; // expected-error{{invokes a deleted function}}
- else if (0)
- return ExternMove; // expected-error{{invokes a deleted function}}
- else if (0)
- return AnInt; // expected-error{{invokes a deleted function}}
- else
- return CharMO; // expected-error{{invokes a deleted function}}
-}
-
-auto DR1579_lambda_valid = [](GenericMoveOnly<float> mo) ->
- GenericMoveOnly<char> {
- return mo;
-};
-
-auto DR1579_lambda_invalid = []() -> GenericMoveOnly<char> {
- static GenericMoveOnly<float> mo;
- return mo; // expected-error{{invokes a deleted function}}
-};
-} // end namespace dr1579
-
namespace dr1589 { // dr1589: 3.7 c++11
// Ambiguous ranking of list-initialization sequences
diff --git a/test/SemaCXX/rval-references.cpp b/test/SemaCXX/rval-references.cpp
index 4c20504..9c79ad7 100644
--- a/test/SemaCXX/rval-references.cpp
+++ b/test/SemaCXX/rval-references.cpp
@@ -72,17 +72,23 @@
// Test the return dance. This also tests IsReturnCopyElidable.
struct MoveOnly {
MoveOnly();
- MoveOnly(const MoveOnly&) = delete; // expected-note 3{{explicitly marked deleted here}}
+ MoveOnly(const MoveOnly&) = delete; // expected-note {{candidate constructor}} \
+ // expected-note 3{{explicitly marked deleted here}}
+ MoveOnly(MoveOnly&&); // expected-note {{candidate constructor}}
+ MoveOnly(int&&); // expected-note {{candidate constructor}}
};
MoveOnly gmo;
MoveOnly returningNonEligible() {
+ int i;
static MoveOnly mo;
MoveOnly &r = mo;
if (0) // Copy from global can't be elided
return gmo; // expected-error {{call to deleted constructor}}
else if (0) // Copy from local static can't be elided
return mo; // expected-error {{call to deleted constructor}}
- else // Copy from reference can't be elided
+ else if (0) // Copy from reference can't be elided
return r; // expected-error {{call to deleted constructor}}
+ else // Construction from different type can't be elided
+ return i; // expected-error {{no viable conversion from returned value of type 'int' to function return type 'MoveOnly'}}
}