Skip to content

Commit c47f921

Browse files
[Clang] C++20 Coroutines: Introduce Frontend Attribute [[clang::coro_await_elidable]]
1 parent 74ac96a commit c47f921

25 files changed

+337
-110
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ Attribute Changes in Clang
246246
instantiation by accidentally allowing it in C++ in some circumstances.
247247
(#GH106864)
248248

249+
- Introduced a new attribute ``[[clang::coro_await_elidable]]`` on coroutine return types
250+
to express elideability at call sites where the coroutine is co_awaited as a prvalue.
251+
249252
Improvements to Clang's diagnostics
250253
-----------------------------------
251254

clang/include/clang/AST/Expr.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2991,6 +2991,9 @@ class CallExpr : public Expr {
29912991

29922992
bool hasStoredFPFeatures() const { return CallExprBits.HasFPFeatures; }
29932993

2994+
bool isCoroElideSafe() const { return CallExprBits.IsCoroElideSafe; }
2995+
void setCoroElideSafe(bool V = true) { CallExprBits.IsCoroElideSafe = V; }
2996+
29942997
Decl *getCalleeDecl() { return getCallee()->getReferencedDeclOfCallee(); }
29952998
const Decl *getCalleeDecl() const {
29962999
return getCallee()->getReferencedDeclOfCallee();

clang/include/clang/AST/Stmt.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,11 @@ class alignas(void *) Stmt {
561561
LLVM_PREFERRED_TYPE(bool)
562562
unsigned HasFPFeatures : 1;
563563

564+
/// True if the call expression is a must-elide call to a coroutine.
565+
unsigned IsCoroElideSafe : 1;
566+
564567
/// Padding used to align OffsetToTrailingObjects to a byte multiple.
565-
unsigned : 24 - 3 - NumExprBits;
568+
unsigned : 24 - 4 - NumExprBits;
566569

567570
/// The offset in bytes from the this pointer to the start of the
568571
/// trailing objects belonging to CallExpr. Intentionally byte sized

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,14 @@ def CoroDisableLifetimeBound : InheritableAttr {
12501250
let SimpleHandler = 1;
12511251
}
12521252

1253+
def CoroAwaitElidable : InheritableAttr {
1254+
let Spellings = [Clang<"coro_await_elidable">];
1255+
let Subjects = SubjectList<[CXXRecord]>;
1256+
let LangOpts = [CPlusPlus];
1257+
let Documentation = [CoroAwaitElidableDoc];
1258+
let SimpleHandler = 1;
1259+
}
1260+
12531261
// OSObject-based attributes.
12541262
def OSConsumed : InheritableParamAttr {
12551263
let Spellings = [Clang<"os_consumed">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8255,6 +8255,38 @@ but do not pass them to the underlying coroutine or pass them by value.
82558255
}];
82568256
}
82578257

8258+
def CoroAwaitElidableDoc : Documentation {
8259+
let Category = DocCatDecl;
8260+
let Content = [{
8261+
The ``[[clang::coro_await_elidable]]`` is a class attribute which can be applied
8262+
to a coroutine return type.
8263+
8264+
When a coroutine function that returns such a type calls another coroutine function,
8265+
the compiler performs heap allocation elision when the call to the coroutine function
8266+
is immediately co_awaited as a prvalue. In this case, the coroutine frame for the
8267+
callee will be a local variable within the enclosing braces in the caller's stack
8268+
frame. And the local variable, like other variables in coroutines, may be collected
8269+
into the coroutine frame, which may be allocated on the heap.
8270+
8271+
Example:
8272+
8273+
.. code-block:: c++
8274+
8275+
class [[clang::coro_await_elidable]] Task { ... };
8276+
8277+
Task foo();
8278+
Task bar() {
8279+
co_await foo(); // foo()'s coroutine frame on this line is elidable
8280+
auto t = foo(); // foo()'s coroutine frame on this line is NOT elidable
8281+
co_await t;
8282+
}
8283+
8284+
The behavior is undefined if the caller coroutine is destroyed earlier than the
8285+
callee coroutine.
8286+
8287+
}];
8288+
}
8289+
82588290
def CountedByDocs : Documentation {
82598291
let Category = DocCatField;
82608292
let Content = [{
@@ -8414,4 +8446,3 @@ Declares that a function potentially allocates heap memory, and prevents any pot
84148446
of ``nonallocating`` by the compiler.
84158447
}];
84168448
}
8417-

clang/lib/AST/Expr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,7 @@ CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
14751475
this->computeDependence();
14761476

14771477
CallExprBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
1478+
CallExprBits.IsCoroElideSafe = false;
14781479
if (hasStoredFPFeatures())
14791480
setStoredFPFeatures(FPFeatures);
14801481
}
@@ -1490,6 +1491,7 @@ CallExpr::CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs,
14901491
assert((CallExprBits.OffsetToTrailingObjects == OffsetToTrailingObjects) &&
14911492
"OffsetToTrailingObjects overflow!");
14921493
CallExprBits.HasFPFeatures = HasFPFeatures;
1494+
CallExprBits.IsCoroElideSafe = false;
14931495
}
14941496

14951497
CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn,

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,8 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
11631163
}
11641164

11651165
RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
1166-
ReturnValueSlot ReturnValue) {
1166+
ReturnValueSlot ReturnValue,
1167+
llvm::CallBase **CallOrInvoke) {
11671168
const auto *BPT = E->getCallee()->getType()->castAs<BlockPointerType>();
11681169
llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee());
11691170
llvm::Type *GenBlockTy = CGM.getGenericBlockLiteralType();
@@ -1220,7 +1221,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
12201221
CGCallee Callee(CGCalleeInfo(), Func);
12211222

12221223
// And call the block.
1223-
return EmitCall(FnInfo, Callee, ReturnValue, Args);
1224+
return EmitCall(FnInfo, Callee, ReturnValue, Args, CallOrInvoke);
12241225
}
12251226

12261227
Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable) {

clang/lib/CodeGen/CGCUDARuntime.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ CGCUDARuntime::~CGCUDARuntime() {}
2525

2626
RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
2727
const CUDAKernelCallExpr *E,
28-
ReturnValueSlot ReturnValue) {
28+
ReturnValueSlot ReturnValue,
29+
llvm::CallBase **CallOrInvoke) {
2930
llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock("kcall.configok");
3031
llvm::BasicBlock *ContBlock = CGF.createBasicBlock("kcall.end");
3132

@@ -35,7 +36,7 @@ RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
3536

3637
eval.begin(CGF);
3738
CGF.EmitBlock(ConfigOKBlock);
38-
CGF.EmitSimpleCallExpr(E, ReturnValue);
39+
CGF.EmitSimpleCallExpr(E, ReturnValue, CallOrInvoke);
3940
CGF.EmitBranch(ContBlock);
4041

4142
CGF.EmitBlock(ContBlock);

clang/lib/CodeGen/CGCUDARuntime.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/IR/GlobalValue.h"
2222

2323
namespace llvm {
24+
class CallBase;
2425
class Function;
2526
class GlobalVariable;
2627
}
@@ -82,9 +83,10 @@ class CGCUDARuntime {
8283
CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {}
8384
virtual ~CGCUDARuntime();
8485

85-
virtual RValue EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
86-
const CUDAKernelCallExpr *E,
87-
ReturnValueSlot ReturnValue);
86+
virtual RValue
87+
EmitCUDAKernelCallExpr(CodeGenFunction &CGF, const CUDAKernelCallExpr *E,
88+
ReturnValueSlot ReturnValue,
89+
llvm::CallBase **CallOrInvoke = nullptr);
8890

8991
/// Emits a kernel launch stub.
9092
virtual void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) = 0;

clang/lib/CodeGen/CGCXXABI.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,11 @@ class CGCXXABI {
485485
llvm::PointerUnion<const CXXDeleteExpr *, const CXXMemberCallExpr *>;
486486

487487
/// Emit the ABI-specific virtual destructor call.
488-
virtual llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF,
489-
const CXXDestructorDecl *Dtor,
490-
CXXDtorType DtorType,
491-
Address This,
492-
DeleteOrMemberCallExpr E) = 0;
488+
virtual llvm::Value *
489+
EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor,
490+
CXXDtorType DtorType, Address This,
491+
DeleteOrMemberCallExpr E,
492+
llvm::CallBase **CallOrInvoke) = 0;
493493

494494
virtual void adjustCallArgsForDestructorThunk(CodeGenFunction &CGF,
495495
GlobalDecl GD,

0 commit comments

Comments
 (0)