[C++20] [Coroutines] Disable to take the address of labels in coroutines

Closing https://github.com/llvm/llvm-project/issues/56436

We can't support the GNU address of label extension in coroutines well
in current architecture. Since the coroutines are going to split into
pieces in the middle end so the address of labels are ambiguous that
time.

To avoid any further misunderstanding, we try to emit an error here.

Differential Revision: https://reviews.llvm.org/D131938
This commit is contained in:
Chuanqi Xu 2023-01-17 11:31:24 +08:00
parent ae53c7f4a2
commit cc526e346d
7 changed files with 92 additions and 2 deletions

View File

@ -452,6 +452,8 @@ Improvements to Clang's diagnostics
- Add ``-Wreturn-local-addr``, a GCC alias for ``-Wreturn-stack-address``.
- Clang now suppresses ``-Wlogical-op-parentheses`` on ``(x && a || b)`` and ``(a || b && x)``
only when ``x`` is a string literal.
- Clang will now reject the GNU extension address of label in coroutines explicitly.
This fixes `Issue 56436 <https://github.com/llvm/llvm-project/issues/56436>`_.
Non-comprehensive list of changes in this release
-------------------------------------------------

View File

@ -11360,6 +11360,9 @@ def warn_non_aligned_allocation_function : Warning <
def err_conflicting_aligned_options : Error <
"conflicting option '-fcoro-aligned-allocation' and '-fno-aligned-allocation'"
>;
def err_coro_invalid_addr_of_label : Error<
"the GNU address of label extension is not allowed in coroutines."
>;
} // end of coroutines issue category
let CategoryName = "Documentation Issue" in {

View File

@ -233,6 +233,9 @@ public:
/// modified in the function.
llvm::SmallPtrSet<const ParmVarDecl *, 8> ModifiedNonNullParams;
/// The set of GNU address of label extension "&&label".
llvm::SmallVector<AddrLabelExpr *, 4> AddrLabels;
public:
/// Represents a simple identification of a weak object.
///

View File

@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() {
ModifiedNonNullParams.clear();
Blocks.clear();
ByrefBlockVars.clear();
AddrLabels.clear();
}
static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {

View File

@ -1125,6 +1125,12 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) {
Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
<< Fn->getFirstCoroutineStmtKeyword();
}
// Coroutines will get splitted into pieces. The GNU address of label
// extension wouldn't be meaningful in coroutines.
for (AddrLabelExpr *ALE : Fn->AddrLabels)
Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label);
CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body);
if (Builder.isInvalid() || !Builder.buildStatements())
return FD->setInvalidDecl();

View File

@ -16105,8 +16105,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
LabelDecl *TheDecl) {
TheDecl->markUsed(Context);
// Create the AST node. The address of a label always has type 'void*'.
return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
Context.getPointerType(Context.VoidTy));
auto *Res = new (Context) AddrLabelExpr(
OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy));
if (getCurFunction())
getCurFunction()->AddrLabels.push_back(Res);
return Res;
}
void Sema::ActOnStartStmtExpr() {

View File

@ -0,0 +1,70 @@
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
#include "Inputs/std-coroutine.h"
struct resumable {
struct promise_type {
resumable get_return_object() { return {}; }
auto initial_suspend() { return std::suspend_always(); }
auto final_suspend() noexcept { return std::suspend_always(); }
void unhandled_exception() {}
void return_void(){};
};
};
resumable f1(int &out, int *inst) {
static void* dispatch_table[] = {&&inc, // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
&&suspend, // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
&&stop}; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
#define DISPATCH() goto *dispatch_table[*inst++]
inc:
out++;
DISPATCH();
suspend:
co_await std::suspend_always{};
DISPATCH();
stop:
co_return;
}
resumable f2(int &out, int *inst) {
void* dispatch_table[] = {nullptr, nullptr, nullptr};
dispatch_table[0] = &&inc; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
dispatch_table[1] = &&suspend; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
dispatch_table[2] = &&stop; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
#define DISPATCH() goto *dispatch_table[*inst++]
inc:
out++;
DISPATCH();
suspend:
co_await std::suspend_always{};
DISPATCH();
stop:
co_return;
}
resumable f3(int &out, int *inst) {
void* dispatch_table[] = {nullptr, nullptr, nullptr};
[&]() -> resumable {
dispatch_table[0] = &&inc; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
dispatch_table[1] = &&suspend; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
dispatch_table[2] = &&stop; // expected-error {{the GNU address of label extension is not allowed in coroutines.}}
#define DISPATCH() goto *dispatch_table[*inst++]
inc:
out++;
DISPATCH();
suspend:
co_await std::suspend_always{};
DISPATCH();
stop:
co_return;
}();
co_return;
}