[PATCH] D99517: Implemented [[clang::musttail]] attribute for guaranteed tail calls.
Richard Smith - zygoloid via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 13 15:54:13 PDT 2021
rsmith added a comment.
Functionally this looks good to me. I've suggested some minor cleanups and I understand you're doing some wordsmithing on the diagnostics; I think once those are complete this will be ready to land. Thank you!
================
Comment at: clang/lib/CodeGen/CGExpr.cpp:4828
ReturnValueSlot ReturnValue) {
+ SaveAndRestore<bool> SaveMustTail(InMustTailCallExpr, E == MustTailCall);
+
----------------
haberman wrote:
> rsmith wrote:
> > The more I think about this, the more it makes me nervous: if any of the `Emit*CallExpr` functions below incidentally emit a call on the way to producing their results via the CGCall machinery, and do so without recursing through this function, that incidental call will be emitted as a tail call instead of the intended one. Specifically:
> >
> > -- I could imagine a block call involving multiple function calls, depending on the blocks ABI.
> > -- I could imagine a member call performing a function call to convert from derived to virtual base in some ABIs.
> > -- A CUDA kernel call in general involves calling a setup function before the actual function call happens (and it doesn't make sense for a CUDA kernel call to be a tail call anyway...)
> > -- A call to a builtin can result in any number of function calls.
> > -- If any expression in the function arguments emits a call without calling back into this function, we'll emit that call as a tail call instead of this one. Eg, `[[clang::musttail]] return f(dynamic_cast<T*>(p));` might emit the call to `__cxa_dynamic_cast` as the tail call instead of emitting the call to `f` as the tail call, depending on whether the CGCall machinery is used when emitting the `__cxa_dynamic_cast` call.
> >
> > Is it feasible to sink this check into the `CodeGenFunction::EmitCall` overload that takes a `CallExpr`, `CodeGenFunction::EmitCXXMemberOrOperatorCall`, and `CodeGenFunction::EmitCXXMemberPointerCallExpr`, after we've emitted the callee and call args? It looks like we might be able to check this immediately before calling the CGCall overload of `EmitCall`, so we could pass in the 'musttail' information as a flag or similar instead of using global state in the `CodeGenFunction` object; if so, it'd be much easier to be confident that we're applying the attribute to the right call.
> Done. It's feeling like `IsMustTail`, `callOrInvoke`, and `Loc` might want to get collapsed into an options struct, especially given the default parameters on the first two. Maybe could do as a follow up?
I agree, that sounds like a nice cleanup. Delaying this to a future change makes sense to me.
================
Comment at: clang/lib/Sema/SemaStmt.cpp:616
+
+ const auto *R = cast<const ReturnStmt>(St);
+ const Expr *Ex = R->getRetValue();
----------------
You shouldn't need the `const` in the argument to `cast`, and we generally omit it; `cast` copies the pointer/referenceness and qualifiers from its argument anyway, and the explicit `const` in the type of `R` seems sufficient for readers. (I'm not even sure if `cast` intends to permit explicit qualfiiers here.)
================
Comment at: clang/lib/Sema/SemaStmt.cpp:664
+ // Find caller function signature.
+ if (!CallerDecl || isa<CapturedDecl>(CurContext)) {
+ int ContextType;
----------------
I think this `isa<CapturedDecl>` check is redundant, because a `CapturedDecl` is not a `FunctionDecl`, so `CallerDecl` will always be null when `CurContext` is a `CapturedDecl`.
================
Comment at: clang/lib/Sema/SemaStmt.cpp:711
+ if (CalleeQualType.isNull()) {
+ // The function callee is invalid and already triggered an error.
+ // Avoid compounding errors.
----------------
Even in invalid code we should never see a `CallExpr` whose callee has a null type; if `Sema` can't form an `Expr` that meets the normal expression invariants during error recovery, it doesn't build one at all. I think you can remove this `if`.
================
Comment at: clang/lib/Sema/SemaStmt.cpp:771
+ if (!Context.hasSimilarType(A, B)) {
+ PD << Select << A << B;
+ return false;
----------------
Given that we don't care about differences in qualifiers, it might be clearer to not include them in the diagnostics.
================
Comment at: clang/test/CodeGenCXX/attr-musttail.cpp:212
+int TestNonCapturingLambda() {
+ auto lambda = []() { return 12; }; // expected-note {{target function is a member function of class 'const (lambda at /usr/local/google/home/haberman/code/llvm-project/clang/test/SemaCXX/attr-musttail.cpp:142:17)'}}
+ [[clang::musttail]] return (+lambda)();
----------------
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D99517/new/
https://reviews.llvm.org/D99517
More information about the cfe-commits
mailing list