@@ -3332,7 +3332,7 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, bool ForceCXX2b) {
3332
3332
const auto *VD = dyn_cast<VarDecl>(DR->getDecl ());
3333
3333
if (!VD)
3334
3334
return NamedReturnInfo ();
3335
- NamedReturnInfo Res = getNamedReturnInfo (VD, /* ForceCXX20= */ ForceCXX2b );
3335
+ NamedReturnInfo Res = getNamedReturnInfo (VD);
3336
3336
if (Res.Candidate && !E->isXValue () &&
3337
3337
(ForceCXX2b || getLangOpts ().CPlusPlus2b )) {
3338
3338
E = ImplicitCastExpr::Create (Context, VD->getType ().getNonReferenceType (),
@@ -3342,46 +3342,28 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, bool ForceCXX2b) {
3342
3342
return Res;
3343
3343
}
3344
3344
3345
- // / Updates the status in the given NamedReturnInfo object to disallow
3346
- // / copy elision, and optionally also implicit move.
3347
- // /
3348
- // / \param Info The NamedReturnInfo object to update.
3349
- // /
3350
- // / \param CanMove If true, disallow only copy elision.
3351
- // / If false, also disallow implcit move.
3352
- static void disallowNRVO (Sema::NamedReturnInfo &Info, bool CanMove) {
3353
- Info.S = std::min (Info.S , CanMove ? Sema::NamedReturnInfo::MoveEligible
3354
- : Sema::NamedReturnInfo::None);
3355
- }
3356
-
3357
3345
// / Determine whether the given NRVO candidate variable is move-eligible or
3358
3346
// / copy-elidable, without considering function return type.
3359
3347
// /
3360
3348
// / \param VD The NRVO candidate variable.
3361
3349
// /
3362
- // / \param ForceCXX20 Overrides detection of current language mode
3363
- // / and uses the rules for C++20.
3364
- // /
3365
3350
// / \returns An aggregate which contains the Candidate and isMoveEligible
3366
3351
// / and isCopyElidable methods. If Candidate is non-null, it means
3367
3352
// / isMoveEligible() would be true under the most permissive language standard.
3368
- Sema::NamedReturnInfo Sema::getNamedReturnInfo (const VarDecl *VD,
3369
- bool ForceCXX20) {
3370
- bool hasCXX11 = getLangOpts ().CPlusPlus11 || ForceCXX20;
3371
- bool hasCXX20 = getLangOpts ().CPlusPlus20 || ForceCXX20;
3353
+ Sema::NamedReturnInfo Sema::getNamedReturnInfo (const VarDecl *VD) {
3372
3354
NamedReturnInfo Info{VD, NamedReturnInfo::MoveEligibleAndCopyElidable};
3373
3355
3374
3356
// C++20 [class.copy.elision]p3:
3375
3357
// - in a return statement in a function with ...
3376
3358
// (other than a function ... parameter)
3377
3359
if (VD->getKind () == Decl::ParmVar)
3378
- disallowNRVO ( Info, hasCXX11) ;
3360
+ Info. S = NamedReturnInfo::MoveEligible ;
3379
3361
else if (VD->getKind () != Decl::Var)
3380
3362
return NamedReturnInfo ();
3381
3363
3382
3364
// (other than ... a catch-clause parameter)
3383
3365
if (VD->isExceptionVariable ())
3384
- disallowNRVO ( Info, hasCXX20) ;
3366
+ Info. S = NamedReturnInfo::MoveEligible ;
3385
3367
3386
3368
// ...automatic...
3387
3369
if (!VD->hasLocalStorage ())
@@ -3406,7 +3388,7 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(const VarDecl *VD,
3406
3388
if (VDReferencedType.isVolatileQualified () ||
3407
3389
!VDReferencedType->isObjectType ())
3408
3390
return NamedReturnInfo ();
3409
- disallowNRVO ( Info, hasCXX20) ;
3391
+ Info. S = NamedReturnInfo::MoveEligible ;
3410
3392
} else {
3411
3393
return NamedReturnInfo ();
3412
3394
}
@@ -3415,7 +3397,7 @@ Sema::NamedReturnInfo Sema::getNamedReturnInfo(const VarDecl *VD,
3415
3397
// alignment cannot use NRVO.
3416
3398
if (!VDType->isDependentType () && VD->hasAttr <AlignedAttr>() &&
3417
3399
Context.getDeclAlign (VD) > Context.getTypeAlignInChars (VDType))
3418
- disallowNRVO ( Info, hasCXX11) ;
3400
+ Info. S = NamedReturnInfo::MoveEligible ;
3419
3401
3420
3402
return Info;
3421
3403
}
@@ -3459,110 +3441,11 @@ const VarDecl *Sema::getCopyElisionCandidate(NamedReturnInfo &Info,
3459
3441
// When considering moving this expression out, allow dissimilar types.
3460
3442
if (!VDType->isDependentType () &&
3461
3443
!Context.hasSameUnqualifiedType (ReturnType, VDType))
3462
- disallowNRVO ( Info, getLangOpts (). CPlusPlus11 ) ;
3444
+ Info. S = NamedReturnInfo::MoveEligible ;
3463
3445
}
3464
3446
return Info.isCopyElidable () ? Info.Candidate : nullptr ;
3465
3447
}
3466
3448
3467
- // / Try to perform the initialization of a potentially-movable value,
3468
- // / which is the operand to a return or throw statement.
3469
- // /
3470
- // / This routine implements C++20 [class.copy.elision]p3, which attempts to
3471
- // / treat returned lvalues as rvalues in certain cases (to prefer move
3472
- // / construction), then falls back to treating them as lvalues if that failed.
3473
- // /
3474
- // / \param ConvertingConstructorsOnly If true, follow [class.copy.elision]p3 and
3475
- // / reject resolutions that find non-constructors, such as derived-to-base
3476
- // / conversions or `operator T()&&` member functions. If false, do consider such
3477
- // / conversion sequences.
3478
- // /
3479
- // / \param Res We will fill this in if move-initialization was possible.
3480
- // / If move-initialization is not possible, such that we must fall back to
3481
- // / treating the operand as an lvalue, we will leave Res in its original
3482
- // / invalid state.
3483
- // /
3484
- // / \returns Whether we need to do the second overload resolution. If the first
3485
- // / overload resolution fails, or if the first overload resolution succeeds but
3486
- // / the selected constructor/operator doesn't match the additional criteria, we
3487
- // / need to do the second overload resolution.
3488
- static bool TryMoveInitialization (Sema &S, const InitializedEntity &Entity,
3489
- const VarDecl *NRVOCandidate, Expr *&Value,
3490
- bool ConvertingConstructorsOnly,
3491
- bool IsDiagnosticsCheck, ExprResult &Res) {
3492
- ImplicitCastExpr AsRvalue (ImplicitCastExpr::OnStack, Value->getType (),
3493
- CK_NoOp, Value, VK_XValue, FPOptionsOverride ());
3494
-
3495
- Expr *InitExpr = &AsRvalue;
3496
-
3497
- InitializationKind Kind = InitializationKind::CreateCopy (
3498
- Value->getBeginLoc (), Value->getBeginLoc ());
3499
-
3500
- InitializationSequence Seq (S, Entity, Kind, InitExpr);
3501
-
3502
- bool NeedSecondOverloadResolution = true ;
3503
- if (!Seq &&
3504
- (IsDiagnosticsCheck || Seq.getFailedOverloadResult () != OR_Deleted)) {
3505
- return NeedSecondOverloadResolution;
3506
- }
3507
-
3508
- for (const InitializationSequence::Step &Step : Seq.steps ()) {
3509
- if (Step.Kind != InitializationSequence::SK_ConstructorInitialization &&
3510
- Step.Kind != InitializationSequence::SK_UserConversion)
3511
- continue ;
3512
-
3513
- FunctionDecl *FD = Step.Function .Function ;
3514
- if (ConvertingConstructorsOnly) {
3515
- if (isa<CXXConstructorDecl>(FD)) {
3516
- // C++11 [class.copy]p32:
3517
- // C++14 [class.copy]p32:
3518
- // C++17 [class.copy.elision]p3:
3519
- // [...] if the type of the first parameter of the selected constructor
3520
- // is not an rvalue reference to the object's type (possibly
3521
- // cv-qualified), overload resolution is performed again, considering
3522
- // the object as an lvalue.
3523
- const RValueReferenceType *RRefType =
3524
- FD->getParamDecl (0 )->getType ()->getAs <RValueReferenceType>();
3525
- if (!RRefType)
3526
- break ;
3527
- if (!S.Context .hasSameUnqualifiedType (RRefType->getPointeeType (),
3528
- NRVOCandidate->getType ()))
3529
- break ;
3530
- } else {
3531
- continue ;
3532
- }
3533
- } else {
3534
- if (isa<CXXConstructorDecl>(FD)) {
3535
- // Check that overload resolution selected a constructor taking an
3536
- // rvalue reference. If it selected an lvalue reference, then we
3537
- // didn't need to cast this thing to an rvalue in the first place.
3538
- if (IsDiagnosticsCheck &&
3539
- !isa<RValueReferenceType>(FD->getParamDecl (0 )->getType ()))
3540
- break ;
3541
- } else if (isa<CXXMethodDecl>(FD)) {
3542
- // Check that overload resolution selected a conversion operator
3543
- // taking an rvalue reference.
3544
- if (cast<CXXMethodDecl>(FD)->getRefQualifier () != RQ_RValue)
3545
- break ;
3546
- } else {
3547
- continue ;
3548
- }
3549
- }
3550
-
3551
- NeedSecondOverloadResolution = false ;
3552
- // Promote "AsRvalue" to the heap, since we now need this
3553
- // expression node to persist.
3554
- Value =
3555
- ImplicitCastExpr::Create (S.Context , Value->getType (), CK_NoOp, Value,
3556
- nullptr , VK_XValue, FPOptionsOverride ());
3557
-
3558
- // Complete type-checking the initialization of the return type
3559
- // using the constructor we found.
3560
- Res = Seq.Perform (S, Entity, Kind, Value);
3561
- }
3562
-
3563
- return NeedSecondOverloadResolution;
3564
- }
3565
-
3566
3449
// / Perform the initialization of a potentially-movable value, which
3567
3450
// / is the result of return value.
3568
3451
// /
@@ -3573,42 +3456,26 @@ ExprResult
3573
3456
Sema::PerformMoveOrCopyInitialization (const InitializedEntity &Entity,
3574
3457
const NamedReturnInfo &NRInfo,
3575
3458
Expr *Value) {
3576
-
3577
- if (NRInfo.Candidate && !getLangOpts ().CPlusPlus2b ) {
3578
- if (NRInfo.isMoveEligible ()) {
3579
- ExprResult Res;
3580
- if (!TryMoveInitialization (*this , Entity, NRInfo.Candidate , Value,
3581
- !getLangOpts ().CPlusPlus20 , false , Res))
3582
- return Res;
3583
- }
3584
- if (!getDiagnostics ().isIgnored (diag::warn_return_std_move,
3585
- Value->getExprLoc ())) {
3586
- QualType QT = NRInfo.Candidate ->getType ();
3587
- if (QT.getNonReferenceType ().getUnqualifiedType ().isTriviallyCopyableType (
3588
- Context)) {
3589
- // Adding 'std::move' around a trivially copyable variable is probably
3590
- // pointless. Don't suggest it.
3591
- } else {
3592
- ExprResult FakeRes = ExprError ();
3593
- Expr *FakeValue = Value;
3594
- TryMoveInitialization (*this , Entity, NRInfo.Candidate , FakeValue, false ,
3595
- true , FakeRes);
3596
- if (!FakeRes.isInvalid ()) {
3597
- bool IsThrow = (Entity.getKind () == InitializedEntity::EK_Exception);
3598
- SmallString<32 > Str;
3599
- Str += " std::move(" ;
3600
- Str += NRInfo.Candidate ->getDeclName ().getAsString ();
3601
- Str += " )" ;
3602
- Diag (Value->getExprLoc (), diag::warn_return_std_move)
3603
- << Value->getSourceRange () << NRInfo.Candidate ->getDeclName ()
3604
- << IsThrow;
3605
- Diag (Value->getExprLoc (), diag::note_add_std_move)
3606
- << FixItHint::CreateReplacement (Value->getSourceRange (), Str);
3607
- }
3608
- }
3459
+ if (getLangOpts ().CPlusPlus11 && !getLangOpts ().CPlusPlus2b &&
3460
+ NRInfo.isMoveEligible ()) {
3461
+ ImplicitCastExpr AsRvalue (ImplicitCastExpr::OnStack, Value->getType (),
3462
+ CK_NoOp, Value, VK_XValue, FPOptionsOverride ());
3463
+ Expr *InitExpr = &AsRvalue;
3464
+ auto Kind = InitializationKind::CreateCopy (Value->getBeginLoc (),
3465
+ Value->getBeginLoc ());
3466
+ InitializationSequence Seq (*this , Entity, Kind, InitExpr);
3467
+ auto Res = Seq.getFailedOverloadResult ();
3468
+ if (Res == OR_Success || Res == OR_Deleted) {
3469
+ // Promote "AsRvalue" to the heap, since we now need this
3470
+ // expression node to persist.
3471
+ Value =
3472
+ ImplicitCastExpr::Create (Context, Value->getType (), CK_NoOp, Value,
3473
+ nullptr , VK_XValue, FPOptionsOverride ());
3474
+ // Complete type-checking the initialization of the return type
3475
+ // using the constructor we found.
3476
+ return Seq.Perform (*this , Entity, Kind, Value);
3609
3477
}
3610
3478
}
3611
-
3612
3479
// Either we didn't meet the criteria for treating an lvalue as an rvalue,
3613
3480
// above, or overload resolution failed. Either way, we need to try
3614
3481
// (again) now with the return value expression as written.
0 commit comments