12
12
// ===----------------------------------------------------------------------===//
13
13
14
14
#include " CoroutineStmtBuilder.h"
15
+ #include " clang/AST/ASTLambda.h"
15
16
#include " clang/AST/Decl.h"
16
17
#include " clang/AST/ExprCXX.h"
17
18
#include " clang/AST/StmtCXX.h"
@@ -506,24 +507,15 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) {
506
507
507
508
auto RefExpr = ExprEmpty ();
508
509
auto Move = Moves.find (PD);
509
- if (Move != Moves.end ()) {
510
- // If a reference to the function parameter exists in the coroutine
511
- // frame, use that reference.
512
- auto *MoveDecl =
513
- cast<VarDecl>(cast<DeclStmt>(Move->second )->getSingleDecl ());
514
- RefExpr = BuildDeclRefExpr (MoveDecl, MoveDecl->getType (),
515
- ExprValueKind::VK_LValue, FD->getLocation ());
516
- } else {
517
- // If the function parameter doesn't exist in the coroutine frame, it
518
- // must be a scalar value. Use it directly.
519
- assert (!PD->getType ()->getAsCXXRecordDecl () &&
520
- " Non-scalar types should have been moved and inserted into the "
521
- " parameter moves map" );
522
- RefExpr =
523
- BuildDeclRefExpr (PD, PD->getOriginalType ().getNonReferenceType (),
524
- ExprValueKind::VK_LValue, FD->getLocation ());
525
- }
526
-
510
+ assert (Move != Moves.end () &&
511
+ " Coroutine function parameter not inserted into move map" );
512
+ // If a reference to the function parameter exists in the coroutine
513
+ // frame, use that reference.
514
+ auto *MoveDecl =
515
+ cast<VarDecl>(cast<DeclStmt>(Move->second )->getSingleDecl ());
516
+ RefExpr =
517
+ BuildDeclRefExpr (MoveDecl, MoveDecl->getType ().getNonReferenceType (),
518
+ ExprValueKind::VK_LValue, FD->getLocation ());
527
519
if (RefExpr.isInvalid ())
528
520
return nullptr ;
529
521
CtorArgExprs.push_back (RefExpr.get ());
@@ -1050,18 +1042,75 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
1050
1042
1051
1043
const bool RequiresNoThrowAlloc = ReturnStmtOnAllocFailure != nullptr ;
1052
1044
1053
- // FIXME: Add support for stateful allocators.
1045
+ // [dcl.fct.def.coroutine]/7
1046
+ // Lookup allocation functions using a parameter list composed of the
1047
+ // requested size of the coroutine state being allocated, followed by
1048
+ // the coroutine function's arguments. If a matching allocation function
1049
+ // exists, use it. Otherwise, use an allocation function that just takes
1050
+ // the requested size.
1054
1051
1055
1052
FunctionDecl *OperatorNew = nullptr ;
1056
1053
FunctionDecl *OperatorDelete = nullptr ;
1057
1054
FunctionDecl *UnusedResult = nullptr ;
1058
1055
bool PassAlignment = false ;
1059
1056
SmallVector<Expr *, 1 > PlacementArgs;
1060
1057
1058
+ // [dcl.fct.def.coroutine]/7
1059
+ // "The allocation function’s name is looked up in the scope of P.
1060
+ // [...] If the lookup finds an allocation function in the scope of P,
1061
+ // overload resolution is performed on a function call created by assembling
1062
+ // an argument list. The first argument is the amount of space requested,
1063
+ // and has type std::size_t. The lvalues p1 ... pn are the succeeding
1064
+ // arguments."
1065
+ //
1066
+ // ...where "p1 ... pn" are defined earlier as:
1067
+ //
1068
+ // [dcl.fct.def.coroutine]/3
1069
+ // "For a coroutine f that is a non-static member function, let P1 denote the
1070
+ // type of the implicit object parameter (13.3.1) and P2 ... Pn be the types
1071
+ // of the function parameters; otherwise let P1 ... Pn be the types of the
1072
+ // function parameters. Let p1 ... pn be lvalues denoting those objects."
1073
+ if (auto *MD = dyn_cast<CXXMethodDecl>(&FD)) {
1074
+ if (MD->isInstance () && !isLambdaCallOperator (MD)) {
1075
+ ExprResult ThisExpr = S.ActOnCXXThis (Loc);
1076
+ if (ThisExpr.isInvalid ())
1077
+ return false ;
1078
+ ThisExpr = S.CreateBuiltinUnaryOp (Loc, UO_Deref, ThisExpr.get ());
1079
+ if (ThisExpr.isInvalid ())
1080
+ return false ;
1081
+ PlacementArgs.push_back (ThisExpr.get ());
1082
+ }
1083
+ }
1084
+ for (auto *PD : FD.parameters ()) {
1085
+ if (PD->getType ()->isDependentType ())
1086
+ continue ;
1087
+
1088
+ // Build a reference to the parameter.
1089
+ auto PDLoc = PD->getLocation ();
1090
+ ExprResult PDRefExpr =
1091
+ S.BuildDeclRefExpr (PD, PD->getOriginalType ().getNonReferenceType (),
1092
+ ExprValueKind::VK_LValue, PDLoc);
1093
+ if (PDRefExpr.isInvalid ())
1094
+ return false ;
1095
+
1096
+ PlacementArgs.push_back (PDRefExpr.get ());
1097
+ }
1061
1098
S.FindAllocationFunctions (Loc, SourceRange (),
1062
1099
/* UseGlobal*/ false , PromiseType,
1063
1100
/* isArray*/ false , PassAlignment, PlacementArgs,
1064
- OperatorNew, UnusedResult);
1101
+ OperatorNew, UnusedResult, /* Diagnose*/ false );
1102
+
1103
+ // [dcl.fct.def.coroutine]/7
1104
+ // "If no matching function is found, overload resolution is performed again
1105
+ // on a function call created by passing just the amount of space required as
1106
+ // an argument of type std::size_t."
1107
+ if (!OperatorNew && !PlacementArgs.empty ()) {
1108
+ PlacementArgs.clear ();
1109
+ S.FindAllocationFunctions (Loc, SourceRange (),
1110
+ /* UseGlobal*/ false , PromiseType,
1111
+ /* isArray*/ false , PassAlignment,
1112
+ PlacementArgs, OperatorNew, UnusedResult);
1113
+ }
1065
1114
1066
1115
bool IsGlobalOverload =
1067
1116
OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext ());
@@ -1080,7 +1129,8 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() {
1080
1129
OperatorNew, UnusedResult);
1081
1130
}
1082
1131
1083
- assert (OperatorNew && " expected definition of operator new to be found" );
1132
+ if (!OperatorNew)
1133
+ return false ;
1084
1134
1085
1135
if (RequiresNoThrowAlloc) {
1086
1136
const auto *FT = OperatorNew->getType ()->getAs <FunctionProtoType>();
@@ -1386,25 +1436,28 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) {
1386
1436
if (PD->getType ()->isDependentType ())
1387
1437
continue ;
1388
1438
1389
- // No need to copy scalars, LLVM will take care of them.
1390
- if (PD->getType ()->getAsCXXRecordDecl ()) {
1391
- ExprResult PDRefExpr = BuildDeclRefExpr (
1392
- PD, PD->getType (), ExprValueKind::VK_LValue, Loc); // FIXME: scope?
1393
- if (PDRefExpr.isInvalid ())
1394
- return false ;
1439
+ ExprResult PDRefExpr =
1440
+ BuildDeclRefExpr (PD, PD->getType ().getNonReferenceType (),
1441
+ ExprValueKind::VK_LValue, Loc); // FIXME: scope?
1442
+ if (PDRefExpr.isInvalid ())
1443
+ return false ;
1395
1444
1396
- Expr *CExpr = castForMoving (*this , PDRefExpr.get ());
1445
+ Expr *CExpr = nullptr ;
1446
+ if (PD->getType ()->getAsCXXRecordDecl () ||
1447
+ PD->getType ()->isRValueReferenceType ())
1448
+ CExpr = castForMoving (*this , PDRefExpr.get ());
1449
+ else
1450
+ CExpr = PDRefExpr.get ();
1397
1451
1398
- auto D = buildVarDecl (*this , Loc, PD->getType (), PD->getIdentifier ());
1399
- AddInitializerToDecl (D, CExpr, /* DirectInit=*/ true );
1452
+ auto D = buildVarDecl (*this , Loc, PD->getType (), PD->getIdentifier ());
1453
+ AddInitializerToDecl (D, CExpr, /* DirectInit=*/ true );
1400
1454
1401
- // Convert decl to a statement.
1402
- StmtResult Stmt = ActOnDeclStmt (ConvertDeclToDeclGroup (D), Loc, Loc);
1403
- if (Stmt.isInvalid ())
1404
- return false ;
1455
+ // Convert decl to a statement.
1456
+ StmtResult Stmt = ActOnDeclStmt (ConvertDeclToDeclGroup (D), Loc, Loc);
1457
+ if (Stmt.isInvalid ())
1458
+ return false ;
1405
1459
1406
- ScopeInfo->CoroutineParameterMoves .insert (std::make_pair (PD, Stmt.get ()));
1407
- }
1460
+ ScopeInfo->CoroutineParameterMoves .insert (std::make_pair (PD, Stmt.get ()));
1408
1461
}
1409
1462
return true ;
1410
1463
}
0 commit comments