xbolva00 created this revision.
xbolva00 added reviewers: aaron.ballman, efriedma, haberman.
Herald added a project: All.
xbolva00 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

As noted in https://github.com/llvm/llvm-project/issues/54964 , musttail 
provide assurances that the tail call can be optimized on all targets.

But some users could care only one specific target and if they use musttail 
attribute, they may see an Clang error about signatures mismatch. This mismatch 
is often a not a real problem in practice and LLVM can still emit tail call.

So... Introduce [[clang::nonportable_musttail]] which is a less strict version 
of [[clang::musttail]] (no checking if signatures fully match).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D147714

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaStmt.cpp
  clang/test/SemaCXX/attr-musttail.cpp

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: 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<MustTailAttr>(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<ReturnStmt>(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<NamedDecl>(CE->getCalleeDecl()))
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/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">;
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to