[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-14 Thread Richard Trieu via Phabricator via cfe-commits
This revision was not accepted when it landed; it landed in state "Needs 
Review".
This revision was automatically updated to reflect the committed changes.
Closed by commit rL327598: Refactoring code around move/copy initialization.  
NFC. (authored by rtrieu, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D43898?vs=137920=138488#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D43898

Files:
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/Sema/SemaExprCXX.cpp
  cfe/trunk/lib/Sema/SemaStmt.cpp
  cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

Index: cfe/trunk/include/clang/Sema/Sema.h
===
--- cfe/trunk/include/clang/Sema/Sema.h
+++ cfe/trunk/include/clang/Sema/Sema.h
@@ -3795,10 +3795,18 @@
   RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *,
SourceLocation Loc,
unsigned NumParams);
+
+  enum CopyElisionSemanticsKind {
+CES_Strict = 0,
+CES_AllowParameters = 1,
+CES_AllowDifferentTypes = 2,
+CES_Default = (CES_AllowParameters | CES_AllowDifferentTypes),
+  };
+
   VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
-   bool AllowParamOrMoveConstructible);
+   CopyElisionSemanticsKind CESK);
   bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
-  bool AllowParamOrMoveConstructible);
+  CopyElisionSemanticsKind CESK);
 
   StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
  Scope *CurScope);
Index: cfe/trunk/lib/Sema/SemaStmt.cpp
===
--- cfe/trunk/lib/Sema/SemaStmt.cpp
+++ cfe/trunk/lib/Sema/SemaStmt.cpp
@@ -2862,16 +2862,16 @@
 /// \param E The expression being returned from the function or block, or
 /// being thrown.
 ///
-/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
+/// \param CESK 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).
 ///
 /// \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) {
+   CopyElisionSemanticsKind CESK) {
   if (!getLangOpts().CPlusPlus)
 return nullptr;
 
@@ -2884,29 +2884,29 @@
   if (!VD)
 return nullptr;
 
-  if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
+  if (isCopyElisionCandidate(ReturnType, VD, CESK))
 return VD;
   return nullptr;
 }
 
 bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
-  bool AllowParamOrMoveConstructible) {
+  CopyElisionSemanticsKind CESK) {
   QualType VDType = VD->getType();
   // - in a return statement in a function with ...
   // ... a class return type ...
   if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
 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 (!(CESK & CES_AllowDifferentTypes) && !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))
+  !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar))
 return false;
   if (VD->isExceptionVariable()) return false;
 
@@ -2918,7 +2918,7 @@
   // variable will no longer be used.
   if (VD->hasAttr()) return false;
 
-  if (AllowParamOrMoveConstructible)
+  if (CESK & CES_AllowDifferentTypes)
 return true;
 
   // ...non-volatile...
@@ -2933,6 +2933,71 @@
   return true;
 }
 
+/// \brief Try to perform the initialization of a potentially-movable value,
+/// which is the operand to a return or throw statement.
+///
+/// This routine implements C++14 [class.copy]p32, 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.
+///
+/// \param Res We will fill this in if move-initialization was 

[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-13 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added a comment.

@rtrieu thanks!  I don't have commit privileges; could I ask you to commit this 
on my behalf?  (Or if not, please say no, and I'll know to go looking for 
someone else to ask.)

Once/if https://reviews.llvm.org/D43898 hits master, I'll rebase 
https://reviews.llvm.org/D43322 and await a LGTM there, at which point I'll 
again ask for help committing it. :)


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-13 Thread Richard Trieu via Phabricator via cfe-commits
rtrieu added a comment.

Everything looks good and ready for commit.


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-10 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone updated this revision to Diff 137920.
Quuxplusone marked an inline comment as done.
Quuxplusone added a comment.

Addressed @rtrieu's comments.

@rtrieu, please take another look at this and https://reviews.llvm.org/D43322? 
Thanks!


Repository:
  rC Clang

https://reviews.llvm.org/D43898

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp

Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -741,7 +741,7 @@
 
   if (D->isNRVOVariable()) {
 QualType ReturnType = cast(DC)->getReturnType();
-if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false))
+if (SemaRef.isCopyElisionCandidate(ReturnType, Var, Sema::CES_Strict))
   Var->setNRVOVariable(true);
   }
 
Index: lib/Sema/SemaStmt.cpp
===
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2862,16 +2862,16 @@
 /// \param E The expression being returned from the function or block, or
 /// being thrown.
 ///
-/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
+/// \param CESK 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).
 ///
 /// \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) {
+   CopyElisionSemanticsKind CESK) {
   if (!getLangOpts().CPlusPlus)
 return nullptr;
 
@@ -2884,29 +2884,29 @@
   if (!VD)
 return nullptr;
 
-  if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
+  if (isCopyElisionCandidate(ReturnType, VD, CESK))
 return VD;
   return nullptr;
 }
 
 bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
-  bool AllowParamOrMoveConstructible) {
+  CopyElisionSemanticsKind CESK) {
   QualType VDType = VD->getType();
   // - in a return statement in a function with ...
   // ... a class return type ...
   if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
 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 (!(CESK & CES_AllowDifferentTypes) && !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))
+  !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar))
 return false;
   if (VD->isExceptionVariable()) return false;
 
@@ -2918,7 +2918,7 @@
   // variable will no longer be used.
   if (VD->hasAttr()) return false;
 
-  if (AllowParamOrMoveConstructible)
+  if (CESK & CES_AllowDifferentTypes)
 return true;
 
   // ...non-volatile...
@@ -2933,6 +2933,71 @@
   return true;
 }
 
+/// \brief Try to perform the initialization of a potentially-movable value,
+/// which is the operand to a return or throw statement.
+///
+/// This routine implements C++14 [class.copy]p32, 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.
+///
+/// \param Res We will fill this in if move-initialization was possible.
+/// If move-initialization is not possible, such that we must fall back to
+/// treating the operand as an lvalue, we will leave Res in its original
+/// invalid state.
+static void TryMoveInitialization(Sema& S,
+  const InitializedEntity ,
+  const VarDecl *NRVOCandidate,
+  QualType ResultType,
+  Expr *,
+  ExprResult ) {
+  ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
+CK_NoOp, Value, VK_XValue);
+
+  Expr *InitExpr = 
+
+  InitializationKind Kind = InitializationKind::CreateCopy(
+  Value->getLocStart(), Value->getLocStart());
+
+  InitializationSequence Seq(S, Entity, Kind, InitExpr);
+
+  if (!Seq)
+return;
+
+  

[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-10 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone marked 4 inline comments as done.
Quuxplusone added inline comments.



Comment at: lib/Sema/SemaStmt.cpp:2970
+  FunctionDecl *FD = Step.Function.Function;
+  if (isa(FD)) {
+// C++14 [class.copy]p32:

rtrieu wrote:
> Use early exit here:
> 
> 
> ```
> if (!isa(FD)
>   continue;
> 
> // old if-block code
> ```
I'd prefer not to do this, since D43322 is going to change this code into "if 
isa-red-fish... else if isa-blue-fish...". Therefore I think it makes sense to 
keep this intermediate stage as "if isa-red-fish...", rather than changing it 
into "if not-isa-red-fish continue... otherwise..."

If you really want this, I can change it; but it's just going to change back in 
D43322, and the goal of this patch was to make D43322 smaller.



Comment at: lib/Sema/SemaStmt.cpp:2999-3000
-// expression node to persist.
-Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp,
- Value, nullptr, VK_XValue);
 

rtrieu wrote:
> At this point, the variable Value is updated.  Value is scoped to this 
> function, and used again after this code.  In your change, there is a new 
> Value variable in the static function.  Only that variable is updated and not 
> this one, making this a change in behavior.
Good catch! I've addressed this now by making the parameter `Expr *`; but 
I'd be open to better approaches. Particularly because I still don't know what 
to do about the "unnecessary promoting `Value` to the heap" that will happen in 
D43322.


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-09 Thread Richard Trieu via Phabricator via cfe-commits
rtrieu added inline comments.



Comment at: lib/Sema/SemaStmt.cpp:2953
+  ExprResult )
+{
+  ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),

Opening brace should follow the closing paren on previous line.



Comment at: lib/Sema/SemaStmt.cpp:2963
+  InitializationSequence Seq(S, Entity, Kind, InitExpr);
+  if (Seq) {
+for (const InitializationSequence::Step  : Seq.steps()) {

Use early exit here:


```
if (!Seq)
  return;

// rest of function
```



Comment at: lib/Sema/SemaStmt.cpp:2965-2966
+for (const InitializationSequence::Step  : Seq.steps()) {
+  if (!(Step.Kind == InitializationSequence::SK_ConstructorInitialization 
||
+Step.Kind == InitializationSequence::SK_UserConversion))
+continue;

Since you're simplifying the condition here, bring the not operator inside the 
parentheses.


```
if (Step.Kind != ...  && Step.Kind != ...)
```



Comment at: lib/Sema/SemaStmt.cpp:2970
+  FunctionDecl *FD = Step.Function.Function;
+  if (isa(FD)) {
+// C++14 [class.copy]p32:

Use early exit here:


```
if (!isa(FD)
  continue;

// old if-block code
```



Comment at: lib/Sema/SemaStmt.cpp:2999-3000
-// expression node to persist.
-Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp,
- Value, nullptr, VK_XValue);
 

At this point, the variable Value is updated.  Value is scoped to this 
function, and used again after this code.  In your change, there is a new Value 
variable in the static function.  Only that variable is updated and not this 
one, making this a change in behavior.


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-09 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added a comment.

@rtrieu ping?


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-03-02 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added a comment.

@rtrieu please take a look?

Also, I would need someone to commit this for me, as I don't have commit privs.


Repository:
  rC Clang

https://reviews.llvm.org/D43898



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-02-28 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone updated this revision to Diff 136380.
Quuxplusone added a comment.

Add a block comment for function `TryMoveInitialization`.


Repository:
  rC Clang

https://reviews.llvm.org/D43898

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp

Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -741,7 +741,7 @@
 
   if (D->isNRVOVariable()) {
 QualType ReturnType = cast(DC)->getReturnType();
-if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false))
+if (SemaRef.isCopyElisionCandidate(ReturnType, Var, Sema::CES_Strict))
   Var->setNRVOVariable(true);
   }
 
Index: lib/Sema/SemaStmt.cpp
===
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2862,16 +2862,16 @@
 /// \param E The expression being returned from the function or block, or
 /// being thrown.
 ///
-/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
+/// \param CESK 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).
 ///
 /// \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) {
+   CopyElisionSemanticsKind CESK) {
   if (!getLangOpts().CPlusPlus)
 return nullptr;
 
@@ -2884,29 +2884,29 @@
   if (!VD)
 return nullptr;
 
-  if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
+  if (isCopyElisionCandidate(ReturnType, VD, CESK))
 return VD;
   return nullptr;
 }
 
 bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
-  bool AllowParamOrMoveConstructible) {
+  CopyElisionSemanticsKind CESK) {
   QualType VDType = VD->getType();
   // - in a return statement in a function with ...
   // ... a class return type ...
   if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
 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 (!(CESK & CES_AllowDifferentTypes) && !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))
+  !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar))
 return false;
   if (VD->isExceptionVariable()) return false;
 
@@ -2918,7 +2918,7 @@
   // variable will no longer be used.
   if (VD->hasAttr()) return false;
 
-  if (AllowParamOrMoveConstructible)
+  if (CESK & CES_AllowDifferentTypes)
 return true;
 
   // ...non-volatile...
@@ -2933,6 +2933,70 @@
   return true;
 }
 
+/// \brief Try to perform the initialization of a potentially-movable value,
+/// which is the operand to a return or throw statement.
+///
+/// This routine implements C++14 [class.copy]p32, 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.
+///
+/// \param Res We will fill this in if move-initialization was possible.
+/// If move-initialization is not possible, such that we must fall back to
+/// treating the operand as an lvalue, we will leave Res in its original
+/// invalid state.
+static void TryMoveInitialization(Sema& S,
+  const InitializedEntity ,
+  const VarDecl *NRVOCandidate,
+  QualType ResultType,
+  Expr *Value,
+  ExprResult )
+{
+  ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
+CK_NoOp, Value, VK_XValue);
+
+  Expr *InitExpr = 
+
+  InitializationKind Kind = InitializationKind::CreateCopy(
+  Value->getLocStart(), Value->getLocStart());
+
+  InitializationSequence Seq(S, Entity, Kind, InitExpr);
+  if (Seq) {
+for (const InitializationSequence::Step  : Seq.steps()) {
+  if (!(Step.Kind == 

[PATCH] D43898: Preliminary refactoring in service of -Wreturn-std-move. NFC.

2018-02-28 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone created this revision.
Quuxplusone added a reviewer: rtrieu.
Herald added a subscriber: cfe-commits.

This patch is extracted from https://reviews.llvm.org/D43322, which adds a new 
diagnostic `-Wreturn-std-move`. This patch here is just the non-functional 
parts of that patch. It pulls `TryMoveInitialization` out into a separate 
function so that we can (in the next patch) try it twice — once with current 
C++ rules, and once with the rules as they would be if `return x` considered 
rvalue-ref-qualified conversion operators. This patch here does *not* add those 
new rules; it merely rearranges the existing code to make the next patch less 
bulky.


Repository:
  rC Clang

https://reviews.llvm.org/D43898

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaExprCXX.cpp
  lib/Sema/SemaStmt.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp

Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -741,7 +741,7 @@
 
   if (D->isNRVOVariable()) {
 QualType ReturnType = cast(DC)->getReturnType();
-if (SemaRef.isCopyElisionCandidate(ReturnType, Var, false))
+if (SemaRef.isCopyElisionCandidate(ReturnType, Var, Sema::CES_Strict))
   Var->setNRVOVariable(true);
   }
 
Index: lib/Sema/SemaStmt.cpp
===
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2862,16 +2862,16 @@
 /// \param E The expression being returned from the function or block, or
 /// being thrown.
 ///
-/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
+/// \param CESK 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).
 ///
 /// \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) {
+   CopyElisionSemanticsKind CESK) {
   if (!getLangOpts().CPlusPlus)
 return nullptr;
 
@@ -2884,29 +2884,29 @@
   if (!VD)
 return nullptr;
 
-  if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
+  if (isCopyElisionCandidate(ReturnType, VD, CESK))
 return VD;
   return nullptr;
 }
 
 bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
-  bool AllowParamOrMoveConstructible) {
+  CopyElisionSemanticsKind CESK) {
   QualType VDType = VD->getType();
   // - in a return statement in a function with ...
   // ... a class return type ...
   if (!ReturnType.isNull() && !ReturnType->isDependentType()) {
 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 (!(CESK & CES_AllowDifferentTypes) && !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))
+  !((CESK & CES_AllowParameters) && VD->getKind() == Decl::ParmVar))
 return false;
   if (VD->isExceptionVariable()) return false;
 
@@ -2918,7 +2918,7 @@
   // variable will no longer be used.
   if (VD->hasAttr()) return false;
 
-  if (AllowParamOrMoveConstructible)
+  if (CESK & CES_AllowDifferentTypes)
 return true;
 
   // ...non-volatile...
@@ -2933,6 +2933,58 @@
   return true;
 }
 
+static void TryMoveInitialization(Sema& S,
+  const InitializedEntity ,
+  const VarDecl *NRVOCandidate,
+  QualType ResultType,
+  Expr *Value,
+  ExprResult )
+{
+  ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
+CK_NoOp, Value, VK_XValue);
+
+  Expr *InitExpr = 
+
+  InitializationKind Kind = InitializationKind::CreateCopy(
+  Value->getLocStart(), Value->getLocStart());
+
+  InitializationSequence Seq(S, Entity, Kind, InitExpr);
+  if (Seq) {
+for (const InitializationSequence::Step  : Seq.steps()) {
+  if (!(Step.Kind == InitializationSequence::SK_ConstructorInitialization ||
+Step.Kind ==