Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -1470,8 +1470,9 @@ } def MustTail : StmtAttr { - let Spellings = [Clang<"musttail">]; + let Spellings = [Clang<"musttail">, Clang<"nonportable_musttail">]; let Documentation = [MustTailDocs]; + let Accessors = [Accessor<"isNonPortableMustTail", [Clang<"nonportable_musttail">]>]; let Subjects = SubjectList<[ReturnStmt], ErrorDiag, "return statements">; } Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -605,7 +605,8 @@ old style K&R C function declarations. ``clang::musttail`` provides assurances that the tail call can be optimized on -all targets, not just one. +all targets, not just one. If you care about one target and you do not need +these assurances, use ``clang::nonportable_musttail``. }]; } Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -12351,12 +12351,12 @@ /// issuing a diagnostic and returning false if not. In the success case, /// the statement is rewritten to remove implicit nodes from the return /// value. - bool checkAndRewriteMustTailAttr(Stmt *St, const Attr &MTA); + bool checkAndRewriteMustTailAttr(Stmt *St, const MustTailAttr &MTA); private: /// Check whether the given statement can have musttail applied to it, /// issuing a diagnostic and returning false if not. - bool checkMustTailAttr(const Stmt *St, const Attr &MTA); + bool checkMustTailAttr(const Stmt *St, const MustTailAttr &MTA); public: /// Check to see if a given expression could have '.c_str()' called on it. Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -586,7 +586,7 @@ // attributes lands. for (const auto *A : Attrs) { if (A->getKind() == attr::MustTail) { - if (!checkAndRewriteMustTailAttr(SubStmt, *A)) { + if (!checkAndRewriteMustTailAttr(SubStmt, *cast(A))) { return SubStmt; } setFunctionHasMustTail(); @@ -608,7 +608,7 @@ return SubStmt; } -bool Sema::checkAndRewriteMustTailAttr(Stmt *St, const Attr &MTA) { +bool Sema::checkAndRewriteMustTailAttr(Stmt *St, const MustTailAttr &MTA) { ReturnStmt *R = cast(St); Expr *E = R->getRetValue(); @@ -633,7 +633,7 @@ return true; } -bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) { +bool Sema::checkMustTailAttr(const Stmt *St, const MustTailAttr &MTA) { assert(!CurContext->isDependentContext() && "musttail cannot be checked from a dependent context"); @@ -846,6 +846,9 @@ return true; }; + if (MTA.isNonPortableMustTail()) + return true; + PartialDiagnostic PD = PDiag(diag::note_musttail_mismatch); if (!CheckTypesMatch(CallerType, CalleeType, PD)) { if (const auto *ND = dyn_cast_or_null(CE->getCalleeDecl())) Index: clang/test/SemaCXX/attr-musttail.cpp =================================================================== --- clang/test/SemaCXX/attr-musttail.cpp +++ clang/test/SemaCXX/attr-musttail.cpp @@ -6,6 +6,7 @@ [[clang::musttail(1, 2)]] return ReturnsInt1(); // expected-error {{'musttail' attribute takes no arguments}} [[clang::musttail]] return 5; // expected-error {{'musttail' attribute requires that the return value is the result of a function call}} [[clang::musttail]] return ReturnsInt1(); + [[clang::nonportable_musttail]] return ReturnsInt1(); } void NoFunctionCall() { @@ -20,6 +21,11 @@ return NoParams(); // expected-error {{cannot perform a tail call to function 'NoParams' because its signature is incompatible with the calling function}} } +void TestParamArityMismatchNonPortable(int x) { + [[clang::nonportable_musttail]] + return NoParams(); +} + void LongParam(long x); // expected-note {{target function has type mismatch at 1st parameter (expected 'long' but has 'int')}} void TestParamTypeMismatch(int x) { [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}} @@ -267,3 +273,17 @@ void TestCallNonValue() { [[clang::musttail]] return ns; // expected-error {{unexpected namespace name 'ns': expected expression}} } + +struct Foo { + int foo(int) { return 0; } +}; + +struct Bar { + Foo foo; + int bar(int); +}; + +int Bar::bar(int x) { + [[clang::nonportable_musttail]] + return foo.foo(x); +} Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -4507,7 +4507,7 @@ } if (IsMustTail && !isTailCall) - report_fatal_error("failed to perform tail call elimination on a call " + errorUnsupported(DAG, dl, "failed to perform tail call elimination on a call " "site marked musttail"); assert(!(isVarArg && canGuaranteeTCO(CallConv)) && Index: llvm/test/CodeGen/X86/tailcc-notail.ll =================================================================== --- llvm/test/CodeGen/X86/tailcc-notail.ll +++ llvm/test/CodeGen/X86/tailcc-notail.ll @@ -1,6 +1,6 @@ ; RUN: not --crash llc -mtriple=x86_64-linux-gnu %s -o - 2>&1 | FileCheck %s -; CHECK: LLVM ERROR: failed to perform tail call elimination on a call site marked musttail +; CHECK: error: {{.*}} in function caller {{.*}}: failed to perform tail call elimination on a call site marked musttail declare tailcc [16 x i64] @callee() define tailcc [16 x i64] @caller() { %res = musttail call tailcc [16 x i64] @callee()