[clang] 8344675 - Implemented [[clang::musttail]] attribute for guaranteed tail calls.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 15 17:13:39 PDT 2021


Author: Joshua Haberman
Date: 2021-04-15T17:12:21-07:00
New Revision: 8344675908424ee532d4ae30e5043c5a5834e02c

URL: https://github.com/llvm/llvm-project/commit/8344675908424ee532d4ae30e5043c5a5834e02c
DIFF: https://github.com/llvm/llvm-project/commit/8344675908424ee532d4ae30e5043c5a5834e02c.diff

LOG: Implemented [[clang::musttail]] attribute for guaranteed tail calls.

This is a Clang-only change and depends on the existing "musttail"
support already implemented in LLVM.

The [[clang::musttail]] attribute goes on a return statement, not
a function definition. There are several constraints that the user
must follow when using [[clang::musttail]], and these constraints
are verified by Sema.

Tail calls are supported on regular function calls, calls through a
function pointer, member function calls, and even pointer to member.

Future work would be to throw a warning if a users tries to pass
a pointer or reference to a local variable through a musttail call.

Reviewed By: rsmith

Differential Revision: https://reviews.llvm.org/D99517

Added: 
    clang/test/CodeGenCXX/attr-musttail.cpp
    clang/test/Sema/attr-musttail.c
    clang/test/Sema/attr-musttail.m
    clang/test/SemaCXX/attr-musttail.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/AST/IgnoreExpr.h
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/ScopeInfo.h
    clang/include/clang/Sema/Sema.h
    clang/lib/CodeGen/CGCall.cpp
    clang/lib/CodeGen/CGClass.cpp
    clang/lib/CodeGen/CGDecl.cpp
    clang/lib/CodeGen/CGExpr.cpp
    clang/lib/CodeGen/CGExprCXX.cpp
    clang/lib/CodeGen/CGStmt.cpp
    clang/lib/CodeGen/CodeGenFunction.h
    clang/lib/CodeGen/EHScopeStack.h
    clang/lib/Sema/JumpDiagnostics.cpp
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaStmt.cpp
    clang/lib/Sema/SemaStmtAttr.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9d7333660290..ddf048c2dd33 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -46,7 +46,13 @@ sections with improvements to Clang's support for those languages.
 Major New Features
 ------------------
 
-- ...
+- Guaranteed tail calls are now supported with statement attributes
+  ``[[clang::musttail]]`` in C++ and ``__attribute__((musttail))`` in C. The
+  attribute is applied to a return statement (not a function declaration),
+  and an error is emitted if a tail call cannot be guaranteed, for example if
+  the function signatures of caller and callee are not compatible. Guaranteed
+  tail calls enable a class of algorithms that would otherwise use an
+  arbitrary amount of stack space.
 
 Improvements to Clang's diagnostics
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h
index b2f53d1d2a79..a7e9b07bef6c 100644
--- a/clang/include/clang/AST/IgnoreExpr.h
+++ b/clang/include/clang/AST/IgnoreExpr.h
@@ -121,6 +121,18 @@ inline Expr *IgnoreImplicitSingleStep(Expr *E) {
   return E;
 }
 
+inline Expr *IgnoreElidableImplicitConstructorSingleStep(Expr *E) {
+  auto *CCE = dyn_cast<CXXConstructExpr>(E);
+  if (CCE && CCE->isElidable() && !isa<CXXTemporaryObjectExpr>(CCE)) {
+    unsigned NumArgs = CCE->getNumArgs();
+    if ((NumArgs == 1 ||
+         (NumArgs > 1 && CCE->getArg(1)->isDefaultArgument())) &&
+        !CCE->getArg(0)->isDefaultArgument() && !CCE->isListInitialization())
+      return CCE->getArg(0);
+  }
+  return E;
+}
+
 inline Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
   if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
     return ICE->getSubExprAsWritten();

diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 400dfe84b7d9..fcad24b83a05 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1370,6 +1370,12 @@ def NoMerge : DeclOrStmtAttr {
   let SimpleHandler = 1;
 }
 
+def MustTail : StmtAttr {
+  let Spellings = [Clang<"musttail">];
+  let Documentation = [MustTailDocs];
+  let Subjects = SubjectList<[ReturnStmt], ErrorDiag, "return statements">;
+}
+
 def FastCall : DeclOrTypeAttr {
   let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
                    Keyword<"_fastcall">];

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index eabf30eda8cc..867865e91056 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -443,6 +443,32 @@ calls.
   }];
 }
 
+def MustTailDocs : Documentation {
+  let Category = DocCatStmt;
+  let Content = [{
+If a ``return`` statement is marked ``musttail``, this indicates that the
+compiler must generate a tail call for the program to be correct, even when
+optimizations are disabled. This guarantees that the call will not cause
+unbounded stack growth if it is part of a recursive cycle in the call graph.
+
+If the callee is a virtual function that is implemented by a thunk, there is
+no guarantee in general that the thunk tail-calls the implementation of the
+virtual function, so such a call in a recursive cycle can still result in
+unbounded stack growth.
+
+``clang::musttail`` can only be applied to a ``return`` statement whose value
+is the result of a function call (even functions returning void must use
+``return``, although no value is returned). The target function must have the
+same number of arguments as the caller. The types of the return value and all
+arguments must be similar according to C++ rules (
diff ering only in cv
+qualifiers or array size), including the implicit "this" argument, if any.
+Any variables in scope, including all arguments to the function and the
+return value must be trivially destructible. The calling convention of the
+caller and callee must match, and they must not be variadic functions or have
+old style K&R C function declarations.
+  }];
+}
+
 def AssertCapabilityDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "assert_capability, assert_shared_capability";

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c84fd4da0fd4..aeeed560b514 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2824,6 +2824,53 @@ def warn_nomerge_attribute_ignored_in_stmt: Warning<
   "%0 attribute is ignored because there exists no call expression inside the "
   "statement">,
   InGroup<IgnoredAttributes>;
+
+def err_musttail_needs_trivial_args : Error<
+  "tail call requires that the return value, all parameters, and any "
+  "temporaries created by the expression are trivially destructible">;
+def err_musttail_needs_call : Error<
+  "%0 attribute requires that the return value is the result of a function call"
+  >;
+def err_musttail_needs_prototype : Error<
+  "%0 attribute requires that both caller and callee functions have a "
+  "prototype">;
+def note_musttail_fix_non_prototype : Note<
+  "add 'void' to the parameter list to turn an old-style K&R function "
+  "declaration into a prototype">;
+def err_musttail_structors_forbidden : Error<"cannot perform a tail call "
+  "%select{from|to}0 a %select{constructor|destructor}1">;
+def note_musttail_structors_forbidden : Note<"target "
+  "%select{constructor|destructor}0 is declared here">;
+def err_musttail_forbidden_from_this_context : Error<
+  "%0 attribute cannot be used from "
+  "%select{a block|an Objective-C function|this context}1">;
+def err_musttail_member_mismatch : Error<
+  "%select{non-member|static member|non-static member}0 "
+  "function cannot perform a tail call to "
+  "%select{non-member|static member|non-static member|pointer-to-member}1 "
+  "function%select{| %3}2">;
+def note_musttail_callee_defined_here : Note<"%0 declared here">;
+def note_tail_call_required : Note<"tail call required by %0 attribute here">;
+def err_musttail_mismatch : Error<
+  "cannot perform a tail call to function%select{| %1}0 because its signature "
+  "is incompatible with the calling function">;
+def note_musttail_mismatch : Note<
+    "target function "
+    "%select{is a member of 
diff erent class%
diff { (expected $ but has $)|}1,2"
+    "|has 
diff erent number of parameters (expected %1 but has %2)"
+    "|has type mismatch at %ordinal3 parameter"
+    "%
diff { (expected $ but has $)|}1,2"
+    "|has 
diff erent return type%
diff { ($ expected but has $)|}1,2}0">;
+def err_musttail_callconv_mismatch : Error<
+  "cannot perform a tail call to function%select{| %1}0 because it uses an "
+  "incompatible calling convention">;
+def note_musttail_callconv_mismatch : Note<
+  "target function has calling convention %1 (expected %0)">;
+def err_musttail_scope : Error<
+  "cannot perform a tail call from this return statement">;
+def err_musttail_no_variadic : Error<
+  "%0 attribute may not be used with variadic functions">;
+
 def err_nsobject_attribute : Error<
   "'NSObject' attribute is for pointer types only">;
 def err_attributes_are_not_compatible : Error<

diff  --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 8ec74cafeeca..98ed75acd9d2 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -118,6 +118,10 @@ class FunctionScopeInfo {
   /// Whether this function contains any indirect gotos.
   bool HasIndirectGoto : 1;
 
+  /// Whether this function contains any statement marked with
+  /// \c [[clang::musttail]].
+  bool HasMustTail : 1;
+
   /// Whether a statement was dropped because it was invalid.
   bool HasDroppedStmt : 1;
 
@@ -370,14 +374,13 @@ class FunctionScopeInfo {
 public:
   FunctionScopeInfo(DiagnosticsEngine &Diag)
       : Kind(SK_Function), HasBranchProtectedScope(false),
-        HasBranchIntoScope(false), HasIndirectGoto(false),
+        HasBranchIntoScope(false), HasIndirectGoto(false), HasMustTail(false),
         HasDroppedStmt(false), HasOMPDeclareReductionCombiner(false),
         HasFallthroughStmt(false), UsesFPIntrin(false),
-        HasPotentialAvailabilityViolations(false),
-        ObjCShouldCallSuper(false), ObjCIsDesignatedInit(false),
-        ObjCWarnForNoDesignatedInitChain(false), ObjCIsSecondaryInit(false),
-        ObjCWarnForNoInitDelegation(false), NeedsCoroutineSuspends(true),
-        ErrorTrap(Diag) {}
+        HasPotentialAvailabilityViolations(false), ObjCShouldCallSuper(false),
+        ObjCIsDesignatedInit(false), ObjCWarnForNoDesignatedInitChain(false),
+        ObjCIsSecondaryInit(false), ObjCWarnForNoInitDelegation(false),
+        NeedsCoroutineSuspends(true), ErrorTrap(Diag) {}
 
   virtual ~FunctionScopeInfo();
 
@@ -423,6 +426,8 @@ class FunctionScopeInfo {
     HasIndirectGoto = true;
   }
 
+  void setHasMustTail() { HasMustTail = true; }
+
   void setHasDroppedStmt() {
     HasDroppedStmt = true;
   }
@@ -450,9 +455,8 @@ class FunctionScopeInfo {
   }
 
   bool NeedsScopeChecking() const {
-    return !HasDroppedStmt &&
-        (HasIndirectGoto ||
-          (HasBranchProtectedScope && HasBranchIntoScope));
+    return !HasDroppedStmt && (HasIndirectGoto || HasMustTail ||
+                               (HasBranchProtectedScope && HasBranchIntoScope));
   }
 
   // Add a block introduced in this function.

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b3407639b40e..cc008e9869d2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1848,6 +1848,7 @@ class Sema final {
   void setFunctionHasBranchIntoScope();
   void setFunctionHasBranchProtectedScope();
   void setFunctionHasIndirectGoto();
+  void setFunctionHasMustTail();
 
   void PushCompoundScope(bool IsStmtExpr);
   void PopCompoundScope();
@@ -11359,6 +11360,18 @@ class Sema final {
   /// function, issuing a diagnostic if not.
   void checkVariadicArgument(const Expr *E, VariadicCallType CT);
 
+  /// Check whether the given statement can have musttail applied to it,
+  /// 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);
+
+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);
+
+public:
   /// Check to see if a given expression could have '.c_str()' called on it.
   bool hasCStrMethod(const Expr *E);
 

diff  --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 0474ddb03428..366c83eeb8e8 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -4560,7 +4560,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
                                  const CGCallee &Callee,
                                  ReturnValueSlot ReturnValue,
                                  const CallArgList &CallArgs,
-                                 llvm::CallBase **callOrInvoke,
+                                 llvm::CallBase **callOrInvoke, bool IsMustTail,
                                  SourceLocation Loc) {
   // FIXME: We no longer need the types from CallArgs; lift up and simplify.
 
@@ -5253,10 +5253,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
   if (CGM.getLangOpts().ObjCAutoRefCount)
     AddObjCARCExceptionMetadata(CI);
 
-  // Suppress tail calls if requested.
+  // Set tail call kind if necessary.
   if (llvm::CallInst *Call = dyn_cast<llvm::CallInst>(CI)) {
     if (TargetDecl && TargetDecl->hasAttr<NotTailCalledAttr>())
       Call->setTailCallKind(llvm::CallInst::TCK_NoTail);
+    else if (IsMustTail)
+      Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
   }
 
   // Add metadata for calls to MSAllocator functions
@@ -5308,6 +5310,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
     return GetUndefRValue(RetTy);
   }
 
+  // If this is a musttail call, return immediately. We do not branch to the
+  // epilogue in this case.
+  if (IsMustTail) {
+    for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
+         ++it) {
+      EHCleanupScope *Cleanup = dyn_cast<EHCleanupScope>(&*it);
+      if (!(Cleanup && Cleanup->getCleanup()->isRedundantBeforeReturn()))
+        CGM.ErrorUnsupported(MustTailCall, "tail call skipping over cleanups");
+    }
+    if (CI->getType()->isVoidTy())
+      Builder.CreateRetVoid();
+    else
+      Builder.CreateRet(CI);
+    Builder.ClearInsertionPoint();
+    EnsureInsertPoint();
+    return GetUndefRValue(RetTy);
+  }
+
   // Perform the swifterror writeback.
   if (swiftErrorTemp.isValid()) {
     llvm::Value *errorResult = Builder.CreateLoad(swiftErrorTemp);

diff  --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 7fcc84bc7a09..50681da6608d 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2182,7 +2182,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
   const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
       Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
   CGCallee Callee = CGCallee::forDirect(CalleePtr, GlobalDecl(D, Type));
-  EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, Loc);
+  EmitCall(Info, Callee, ReturnValueSlot(), Args, nullptr, false, Loc);
 
   // Generate vtable assumptions if we're constructing a complete object
   // with a vtable.  We don't do this for base subobjects for two reasons:

diff  --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index d72b9c4b6e15..fda78f8dd59c 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -550,6 +550,7 @@ namespace {
   struct CallStackRestore final : EHScopeStack::Cleanup {
     Address Stack;
     CallStackRestore(Address Stack) : Stack(Stack) {}
+    bool isRedundantBeforeReturn() override { return true; }
     void Emit(CodeGenFunction &CGF, Flags flags) override {
       llvm::Value *V = CGF.Builder.CreateLoad(Stack);
       llvm::Function *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore);

diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index b5437e497164..a35bd7dd56b7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -38,6 +38,7 @@
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Transforms/Utils/SanitizerStats.h"
 
 #include <string>
@@ -5287,7 +5288,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
   }
   llvm::CallBase *CallOrInvoke = nullptr;
   RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke,
-                         E->getExprLoc());
+                         E == MustTailCall, E->getExprLoc());
 
   // Generate function declaration DISuprogram in order to be used
   // in debug info about call sites.

diff  --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index b8608911edb2..96cf977ca290 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -87,6 +87,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
   auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
       Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
   return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr,
+                  CE && CE == MustTailCall,
                   CE ? CE->getExprLoc() : SourceLocation());
 }
 
@@ -112,7 +113,7 @@ RValue CodeGenFunction::EmitCXXDestructorCall(
   commonEmitCXXMemberOrOperatorCall(*this, DtorDecl, This, ImplicitParam,
                                     ImplicitParamTy, CE, Args, nullptr);
   return EmitCall(CGM.getTypes().arrangeCXXStructorDeclaration(Dtor), Callee,
-                  ReturnValueSlot(), Args, nullptr,
+                  ReturnValueSlot(), Args, nullptr, CE && CE == MustTailCall,
                   CE ? CE->getExprLoc() : SourceLocation{});
 }
 
@@ -472,7 +473,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
   EmitCallArgs(Args, FPT, E->arguments());
   return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
                                                       /*PrefixSize=*/0),
-                  Callee, ReturnValue, Args, nullptr, E->getExprLoc());
+                  Callee, ReturnValue, Args, nullptr, E == MustTailCall,
+                  E->getExprLoc());
 }
 
 RValue

diff  --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index c2b64c899eeb..b6f4f98fbd2e 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -16,6 +16,8 @@
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
 #include "clang/AST/Attr.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/DiagnosticSema.h"
@@ -649,12 +651,20 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
 
 void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
   bool nomerge = false;
-  for (const auto *A : S.getAttrs())
+  const CallExpr *musttail = nullptr;
+
+  for (const auto *A : S.getAttrs()) {
     if (A->getKind() == attr::NoMerge) {
       nomerge = true;
-      break;
     }
+    if (A->getKind() == attr::MustTail) {
+      const Stmt *Sub = S.getSubStmt();
+      const ReturnStmt *R = cast<ReturnStmt>(Sub);
+      musttail = cast<CallExpr>(R->getRetValue()->IgnoreParens());
+    }
+  }
   SaveAndRestore<bool> save_nomerge(InNoMergeAttributedStmt, nomerge);
+  SaveAndRestore<const CallExpr *> save_musttail(MustTailCall, musttail);
   EmitStmt(S.getSubStmt(), S.getAttrs());
 }
 

diff  --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 0b3da9e088d0..7723382c9cb4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -520,6 +520,10 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// True if the current statement has nomerge attribute.
   bool InNoMergeAttributedStmt = false;
 
+  // The CallExpr within the current statement that the musttail attribute
+  // applies to.  nullptr if there is no 'musttail' on the current statement.
+  const CallExpr *MustTailCall = nullptr;
+
   /// True if the current function should be marked mustprogress.
   bool FnIsMustProgress = false;
 
@@ -568,6 +572,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   llvm::Instruction *CurrentFuncletPad = nullptr;
 
   class CallLifetimeEnd final : public EHScopeStack::Cleanup {
+    bool isRedundantBeforeReturn() override { return true; }
+
     llvm::Value *Addr;
     llvm::Value *Size;
 
@@ -3913,12 +3919,14 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// LLVM arguments and the types they were derived from.
   RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
                   ReturnValueSlot ReturnValue, const CallArgList &Args,
-                  llvm::CallBase **callOrInvoke, SourceLocation Loc);
+                  llvm::CallBase **callOrInvoke, bool IsMustTail,
+                  SourceLocation Loc);
   RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
                   ReturnValueSlot ReturnValue, const CallArgList &Args,
-                  llvm::CallBase **callOrInvoke = nullptr) {
+                  llvm::CallBase **callOrInvoke = nullptr,
+                  bool IsMustTail = false) {
     return EmitCall(CallInfo, Callee, ReturnValue, Args, callOrInvoke,
-                    SourceLocation());
+                    IsMustTail, SourceLocation());
   }
   RValue EmitCall(QualType FnType, const CGCallee &Callee, const CallExpr *E,
                   ReturnValueSlot ReturnValue, llvm::Value *Chain = nullptr);

diff  --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h
index 3a640d6117d6..994d3db555aa 100644
--- a/clang/lib/CodeGen/EHScopeStack.h
+++ b/clang/lib/CodeGen/EHScopeStack.h
@@ -150,6 +150,8 @@ class EHScopeStack {
     Cleanup(Cleanup &&) {}
     Cleanup() = default;
 
+    virtual bool isRedundantBeforeReturn() { return false; }
+
     /// Generation flags.
     class Flags {
       enum {

diff  --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index d33b14a79dc1..9d73881d66d7 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -11,13 +11,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Sema/SemaInternal.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/AST/StmtOpenMP.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/BitVector.h"
 using namespace clang;
 
@@ -29,6 +30,10 @@ namespace {
 ///    int a[n];
 ///  L:
 ///
+/// We also detect jumps out of protected scopes when it's not possible to do
+/// cleanups properly. Indirect jumps and ASM jumps can't do cleanups because
+/// the target is unknown. Return statements with \c [[clang::musttail]] cannot
+/// handle any cleanups due to the nature of a tail call.
 class JumpScopeChecker {
   Sema &S;
 
@@ -68,6 +73,7 @@ class JumpScopeChecker {
 
   SmallVector<Stmt*, 4> IndirectJumps;
   SmallVector<Stmt*, 4> AsmJumps;
+  SmallVector<AttributedStmt *, 4> MustTailStmts;
   SmallVector<LabelDecl*, 4> IndirectJumpTargets;
   SmallVector<LabelDecl*, 4> AsmJumpTargets;
 public:
@@ -81,6 +87,7 @@ class JumpScopeChecker {
 
   void VerifyJumps();
   void VerifyIndirectOrAsmJumps(bool IsAsmGoto);
+  void VerifyMustTailStmts();
   void NoteJumpIntoScopes(ArrayRef<unsigned> ToScopes);
   void DiagnoseIndirectOrAsmJump(Stmt *IG, unsigned IGScope, LabelDecl *Target,
                                  unsigned TargetScope);
@@ -88,6 +95,7 @@ class JumpScopeChecker {
                  unsigned JumpDiag, unsigned JumpDiagWarning,
                  unsigned JumpDiagCXX98Compat);
   void CheckGotoStmt(GotoStmt *GS);
+  const Attr *GetMustTailAttr(AttributedStmt *AS);
 
   unsigned GetDeepestCommonScope(unsigned A, unsigned B);
 };
@@ -109,6 +117,7 @@ JumpScopeChecker::JumpScopeChecker(Stmt *Body, Sema &s)
   VerifyJumps();
   VerifyIndirectOrAsmJumps(false);
   VerifyIndirectOrAsmJumps(true);
+  VerifyMustTailStmts();
 }
 
 /// GetDeepestCommonScope - Finds the innermost scope enclosing the
@@ -580,6 +589,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
     LabelAndGotoScopes[S] = ParentScope;
     break;
 
+  case Stmt::AttributedStmtClass: {
+    AttributedStmt *AS = cast<AttributedStmt>(S);
+    if (GetMustTailAttr(AS)) {
+      LabelAndGotoScopes[AS] = ParentScope;
+      MustTailStmts.push_back(AS);
+    }
+    break;
+  }
+
   default:
     if (auto *ED = dyn_cast<OMPExecutableDirective>(S)) {
       if (!ED->isStandaloneDirective()) {
@@ -971,6 +989,24 @@ void JumpScopeChecker::CheckGotoStmt(GotoStmt *GS) {
   }
 }
 
+void JumpScopeChecker::VerifyMustTailStmts() {
+  for (AttributedStmt *AS : MustTailStmts) {
+    for (unsigned I = LabelAndGotoScopes[AS]; I; I = Scopes[I].ParentScope) {
+      if (Scopes[I].OutDiag) {
+        S.Diag(AS->getBeginLoc(), diag::err_musttail_scope);
+        S.Diag(Scopes[I].Loc, Scopes[I].OutDiag);
+      }
+    }
+  }
+}
+
+const Attr *JumpScopeChecker::GetMustTailAttr(AttributedStmt *AS) {
+  ArrayRef<const Attr *> Attrs = AS->getAttrs();
+  const auto *Iter =
+      llvm::find_if(Attrs, [](const Attr *A) { return isa<MustTailAttr>(A); });
+  return Iter != Attrs.end() ? *Iter : nullptr;
+}
+
 void Sema::DiagnoseInvalidJumps(Stmt *Body) {
   (void)JumpScopeChecker(Body, *this);
 }

diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 2c99a35e700b..40f11e40882c 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2079,6 +2079,11 @@ void Sema::setFunctionHasIndirectGoto() {
     FunctionScopes.back()->setHasIndirectGoto();
 }
 
+void Sema::setFunctionHasMustTail() {
+  if (!FunctionScopes.empty())
+    FunctionScopes.back()->setHasMustTail();
+}
+
 BlockScopeInfo *Sema::getCurBlock() {
   if (FunctionScopes.empty())
     return nullptr;

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 174679a14f24..a3b1fa4ab534 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -10,17 +10,16 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/SemaInternal.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/ASTLambda.h"
-#include "clang/AST/CharUnits.h"
 #include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/EvaluatedExprVisitor.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/IgnoreExpr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
@@ -30,8 +29,10 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
@@ -558,6 +559,17 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
 StmtResult Sema::BuildAttributedStmt(SourceLocation AttrsLoc,
                                      ArrayRef<const Attr *> Attrs,
                                      Stmt *SubStmt) {
+  // FIXME: this code should move when a planned refactoring around statement
+  // attributes lands.
+  for (const auto *A : Attrs) {
+    if (A->getKind() == attr::MustTail) {
+      if (!checkAndRewriteMustTailAttr(SubStmt, *A)) {
+        return SubStmt;
+      }
+      setFunctionHasMustTail();
+    }
+  }
+
   return AttributedStmt::Create(Context, AttrsLoc, Attrs, SubStmt);
 }
 
@@ -573,6 +585,259 @@ StmtResult Sema::ActOnAttributedStmt(const ParsedAttributesWithRange &Attrs,
   return SubStmt;
 }
 
+bool Sema::checkAndRewriteMustTailAttr(Stmt *St, const Attr &MTA) {
+  ReturnStmt *R = cast<ReturnStmt>(St);
+  Expr *E = R->getRetValue();
+
+  if (CurContext->isDependentContext() || (E && E->isInstantiationDependent()))
+    // We have to suspend our check until template instantiation time.
+    return true;
+
+  if (!checkMustTailAttr(St, MTA))
+    return false;
+
+  // FIXME: Replace Expr::IgnoreImplicitAsWritten() with this function.
+  // Currently it does not skip implicit constructors in an initialization
+  // context.
+  auto IgnoreImplicitAsWritten = [](Expr *E) -> Expr * {
+    return IgnoreExprNodes(E, IgnoreImplicitAsWrittenSingleStep,
+                           IgnoreElidableImplicitConstructorSingleStep);
+  };
+
+  // Now that we have verified that 'musttail' is valid here, rewrite the
+  // return value to remove all implicit nodes, but retain parentheses.
+  R->setRetValue(IgnoreImplicitAsWritten(E));
+  return true;
+}
+
+bool Sema::checkMustTailAttr(const Stmt *St, const Attr &MTA) {
+  assert(!CurContext->isDependentContext() &&
+         "musttail cannot be checked from a dependent context");
+
+  // FIXME: Add Expr::IgnoreParenImplicitAsWritten() with this definition.
+  auto IgnoreParenImplicitAsWritten = [](const Expr *E) -> const Expr * {
+    return IgnoreExprNodes(const_cast<Expr *>(E), IgnoreParensSingleStep,
+                           IgnoreImplicitAsWrittenSingleStep,
+                           IgnoreElidableImplicitConstructorSingleStep);
+  };
+
+  const Expr *E = cast<ReturnStmt>(St)->getRetValue();
+  const auto *CE = dyn_cast_or_null<CallExpr>(IgnoreParenImplicitAsWritten(E));
+
+  if (!CE) {
+    Diag(St->getBeginLoc(), diag::err_musttail_needs_call) << &MTA;
+    return false;
+  }
+
+  if (const auto *EWC = dyn_cast<ExprWithCleanups>(E)) {
+    if (EWC->cleanupsHaveSideEffects()) {
+      Diag(St->getBeginLoc(), diag::err_musttail_needs_trivial_args) << &MTA;
+      return false;
+    }
+  }
+
+  // We need to determine the full function type (including "this" type, if any)
+  // for both caller and callee.
+  struct FuncType {
+    enum {
+      ft_non_member,
+      ft_static_member,
+      ft_non_static_member,
+      ft_pointer_to_member,
+    } MemberType = ft_non_member;
+
+    QualType This;
+    const FunctionProtoType *Func;
+    const CXXMethodDecl *Method = nullptr;
+  } CallerType, CalleeType;
+
+  auto GetMethodType = [this, St, MTA](const CXXMethodDecl *CMD, FuncType &Type,
+                                       bool IsCallee) -> bool {
+    if (isa<CXXConstructorDecl, CXXDestructorDecl>(CMD)) {
+      Diag(St->getBeginLoc(), diag::err_musttail_structors_forbidden)
+          << IsCallee << isa<CXXDestructorDecl>(CMD);
+      if (IsCallee)
+        Diag(CMD->getBeginLoc(), diag::note_musttail_structors_forbidden)
+            << isa<CXXDestructorDecl>(CMD);
+      Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA;
+      return false;
+    }
+    if (CMD->isStatic())
+      Type.MemberType = FuncType::ft_static_member;
+    else {
+      Type.This = CMD->getThisType()->getPointeeType();
+      Type.MemberType = FuncType::ft_non_static_member;
+    }
+    Type.Func = CMD->getType()->castAs<FunctionProtoType>();
+    return true;
+  };
+
+  const auto *CallerDecl = dyn_cast<FunctionDecl>(CurContext);
+
+  // Find caller function signature.
+  if (!CallerDecl) {
+    int ContextType;
+    if (isa<BlockDecl>(CurContext))
+      ContextType = 0;
+    else if (isa<ObjCMethodDecl>(CurContext))
+      ContextType = 1;
+    else
+      ContextType = 2;
+    Diag(St->getBeginLoc(), diag::err_musttail_forbidden_from_this_context)
+        << &MTA << ContextType;
+    return false;
+  } else if (const auto *CMD = dyn_cast<CXXMethodDecl>(CurContext)) {
+    // Caller is a class/struct method.
+    if (!GetMethodType(CMD, CallerType, false))
+      return false;
+  } else {
+    // Caller is a non-method function.
+    CallerType.Func = CallerDecl->getType()->getAs<FunctionProtoType>();
+  }
+
+  const Expr *CalleeExpr = CE->getCallee()->IgnoreParens();
+  const auto *CalleeBinOp = dyn_cast<BinaryOperator>(CalleeExpr);
+  SourceLocation CalleeLoc = CE->getCalleeDecl()
+                                 ? CE->getCalleeDecl()->getBeginLoc()
+                                 : St->getBeginLoc();
+
+  // Find callee function signature.
+  if (const CXXMethodDecl *CMD =
+          dyn_cast_or_null<CXXMethodDecl>(CE->getCalleeDecl())) {
+    // Call is: obj.method(), obj->method(), functor(), etc.
+    if (!GetMethodType(CMD, CalleeType, true))
+      return false;
+  } else if (CalleeBinOp && CalleeBinOp->isPtrMemOp()) {
+    // Call is: obj->*method_ptr or obj.*method_ptr
+    const auto *MPT =
+        CalleeBinOp->getRHS()->getType()->castAs<MemberPointerType>();
+    CalleeType.This = QualType(MPT->getClass(), 0);
+    CalleeType.Func = MPT->getPointeeType()->castAs<FunctionProtoType>();
+    CalleeType.MemberType = FuncType::ft_pointer_to_member;
+  } else if (isa<CXXPseudoDestructorExpr>(CalleeExpr)) {
+    Diag(St->getBeginLoc(), diag::err_musttail_structors_forbidden)
+        << /* IsCallee = */ 1 << /* IsDestructor = */ 1;
+    Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA;
+    return false;
+  } else {
+    // Non-method function.
+    CalleeType.Func =
+        CalleeExpr->getType()->getPointeeType()->getAs<FunctionProtoType>();
+  }
+
+  // Both caller and callee must have a prototype (no K&R declarations).
+  if (!CalleeType.Func || !CallerType.Func) {
+    Diag(St->getBeginLoc(), diag::err_musttail_needs_prototype) << &MTA;
+    if (!CalleeType.Func && CE->getDirectCallee()) {
+      Diag(CE->getDirectCallee()->getBeginLoc(),
+           diag::note_musttail_fix_non_prototype);
+    }
+    if (!CallerType.Func)
+      Diag(CallerDecl->getBeginLoc(), diag::note_musttail_fix_non_prototype);
+    return false;
+  }
+
+  // Caller and callee must have matching calling conventions.
+  //
+  // Some calling conventions are physically capable of supporting tail calls
+  // even if the function types don't perfectly match. LLVM is currently too
+  // strict to allow this, but if LLVM added support for this in the future, we
+  // could exit early here and skip the remaining checks if the functions are
+  // using such a calling convention.
+  if (CallerType.Func->getCallConv() != CalleeType.Func->getCallConv()) {
+    if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl()))
+      Diag(St->getBeginLoc(), diag::err_musttail_callconv_mismatch)
+          << true << ND->getDeclName();
+    else
+      Diag(St->getBeginLoc(), diag::err_musttail_callconv_mismatch) << false;
+    Diag(CalleeLoc, diag::note_musttail_callconv_mismatch)
+        << FunctionType::getNameForCallConv(CallerType.Func->getCallConv())
+        << FunctionType::getNameForCallConv(CalleeType.Func->getCallConv());
+    Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA;
+    return false;
+  }
+
+  if (CalleeType.Func->isVariadic() || CallerType.Func->isVariadic()) {
+    Diag(St->getBeginLoc(), diag::err_musttail_no_variadic) << &MTA;
+    return false;
+  }
+
+  // Caller and callee must match in whether they have a "this" parameter.
+  if (CallerType.This.isNull() != CalleeType.This.isNull()) {
+    if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+      Diag(St->getBeginLoc(), diag::err_musttail_member_mismatch)
+          << CallerType.MemberType << CalleeType.MemberType << true
+          << ND->getDeclName();
+      Diag(CalleeLoc, diag::note_musttail_callee_defined_here)
+          << ND->getDeclName();
+    } else
+      Diag(St->getBeginLoc(), diag::err_musttail_member_mismatch)
+          << CallerType.MemberType << CalleeType.MemberType << false;
+    Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA;
+    return false;
+  }
+
+  auto CheckTypesMatch = [this](FuncType CallerType, FuncType CalleeType,
+                                PartialDiagnostic &PD) -> bool {
+    enum {
+      ft_
diff erent_class,
+      ft_parameter_arity,
+      ft_parameter_mismatch,
+      ft_return_type,
+    };
+
+    auto DoTypesMatch = [this, &PD](QualType A, QualType B,
+                                    unsigned Select) -> bool {
+      if (!Context.hasSimilarType(A, B)) {
+        PD << Select << A.getUnqualifiedType() << B.getUnqualifiedType();
+        return false;
+      }
+      return true;
+    };
+
+    if (!CallerType.This.isNull() &&
+        !DoTypesMatch(CallerType.This, CalleeType.This, ft_
diff erent_class))
+      return false;
+
+    if (!DoTypesMatch(CallerType.Func->getReturnType(),
+                      CalleeType.Func->getReturnType(), ft_return_type))
+      return false;
+
+    if (CallerType.Func->getNumParams() != CalleeType.Func->getNumParams()) {
+      PD << ft_parameter_arity << CallerType.Func->getNumParams()
+         << CalleeType.Func->getNumParams();
+      return false;
+    }
+
+    ArrayRef<QualType> CalleeParams = CalleeType.Func->getParamTypes();
+    ArrayRef<QualType> CallerParams = CallerType.Func->getParamTypes();
+    size_t N = CallerType.Func->getNumParams();
+    for (size_t I = 0; I < N; I++) {
+      if (!DoTypesMatch(CalleeParams[I], CallerParams[I],
+                        ft_parameter_mismatch)) {
+        PD << static_cast<int>(I) + 1;
+        return false;
+      }
+    }
+
+    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()))
+      Diag(St->getBeginLoc(), diag::err_musttail_mismatch)
+          << true << ND->getDeclName();
+    else
+      Diag(St->getBeginLoc(), diag::err_musttail_mismatch) << false;
+    Diag(CalleeLoc, PD);
+    Diag(MTA.getLocation(), diag::note_tail_call_required) << &MTA;
+    return false;
+  }
+
+  return true;
+}
+
 namespace {
 class CommaVisitor : public EvaluatedExprVisitor<CommaVisitor> {
   typedef EvaluatedExprVisitor<CommaVisitor> Inherited;

diff  --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index 763c6b61fbd9..4f2977f89ce1 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -209,6 +209,12 @@ static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A,
   return ::new (S.Context) NoMergeAttr(S.Context, A);
 }
 
+static Attr *handleMustTailAttr(Sema &S, Stmt *St, const ParsedAttr &A,
+                                SourceRange Range) {
+  // Validation is in Sema::ActOnAttributedStmt().
+  return ::new (S.Context) MustTailAttr(S.Context, A);
+}
+
 static Attr *handleLikely(Sema &S, Stmt *St, const ParsedAttr &A,
                           SourceRange Range) {
 
@@ -412,6 +418,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
     return handleSuppressAttr(S, St, A, Range);
   case ParsedAttr::AT_NoMerge:
     return handleNoMergeAttr(S, St, A, Range);
+  case ParsedAttr::AT_MustTail:
+    return handleMustTailAttr(S, St, A, Range);
   case ParsedAttr::AT_Likely:
     return handleLikely(S, St, A, Range);
   case ParsedAttr::AT_Unlikely:

diff  --git a/clang/test/CodeGenCXX/attr-musttail.cpp b/clang/test/CodeGenCXX/attr-musttail.cpp
new file mode 100644
index 000000000000..1d02d03ec578
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-musttail.cpp
@@ -0,0 +1,228 @@
+// RUN: %clang_cc1 -fno-elide-constructors -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -fno-elide-constructors -S -emit-llvm %s -triple x86_64-unknown-linux-gnu -o - | opt -verify
+// FIXME: remove the call to "opt" once the tests are running the Clang verifier automatically again.
+
+int Bar(int);
+int Baz(int);
+
+int Func1(int x) {
+  if (x) {
+    // CHECK: %call = musttail call i32 @_Z3Bari(i32 %1)
+    // CHECK-NEXT: ret i32 %call
+    [[clang::musttail]] return Bar(x);
+  } else {
+    [[clang::musttail]] return Baz(x); // CHECK: %call1 = musttail call i32 @_Z3Bazi(i32 %3)
+  }
+}
+
+int Func2(int x) {
+  {
+    [[clang::musttail]] return Bar(Bar(x));
+  }
+}
+
+// CHECK: %call1 = musttail call i32 @_Z3Bari(i32 %call)
+
+class Foo {
+public:
+  static int StaticMethod(int x);
+  int MemberFunction(int x);
+  int TailFrom(int x);
+  int TailFrom2(int x);
+  int TailFrom3(int x);
+};
+
+int Foo::TailFrom(int x) {
+  [[clang::musttail]] return MemberFunction(x);
+}
+
+// CHECK: %call = musttail call i32 @_ZN3Foo14MemberFunctionEi(%class.Foo* nonnull dereferenceable(1) %this1, i32 %0)
+
+int Func3(int x) {
+  [[clang::musttail]] return Foo::StaticMethod(x);
+}
+
+// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
+
+int Func4(int x) {
+  Foo foo; // Object with trivial destructor.
+  [[clang::musttail]] return foo.StaticMethod(x);
+}
+
+// CHECK: %call = musttail call i32 @_ZN3Foo12StaticMethodEi(i32 %0)
+
+int (Foo::*pmf)(int);
+
+int Foo::TailFrom2(int x) {
+  [[clang::musttail]] return ((*this).*pmf)(x);
+}
+
+// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull dereferenceable(1) %this.adjusted, i32 %9)
+
+int Foo::TailFrom3(int x) {
+  [[clang::musttail]] return (this->*pmf)(x);
+}
+
+// CHECK: %call = musttail call i32 %8(%class.Foo* nonnull dereferenceable(1) %this.adjusted, i32 %9)
+
+void ReturnsVoid();
+
+void Func5() {
+  [[clang::musttail]] return ReturnsVoid();
+}
+
+// CHECK: musttail call void @_Z11ReturnsVoidv()
+
+class HasTrivialDestructor {};
+
+int ReturnsInt(int x);
+
+int Func6(int x) {
+  HasTrivialDestructor foo;
+  [[clang::musttail]] return ReturnsInt(x);
+}
+
+// CHECK: %call = musttail call i32 @_Z10ReturnsInti(i32 %0)
+
+struct Data {
+  int (*fptr)(Data *);
+};
+
+int Func7(Data *data) {
+  [[clang::musttail]] return data->fptr(data);
+}
+
+// CHECK: %call = musttail call i32 %1(%struct.Data* %2)
+
+template <class T>
+T TemplateFunc(T) {
+  return 5;
+}
+
+int Func9(int x) {
+  [[clang::musttail]] return TemplateFunc<int>(x);
+}
+
+// CHECK: %call = musttail call i32 @_Z12TemplateFuncIiET_S0_(i32 %0)
+
+template <class T>
+int Func10(int x) {
+  T t;
+  [[clang::musttail]] return Bar(x);
+}
+
+int Func11(int x) {
+  return Func10<int>(x);
+}
+
+// CHECK: %call = musttail call i32 @_Z3Bari(i32 %0)
+
+template <class T>
+T Func12(T x) {
+  [[clang::musttail]] return ::Bar(x);
+}
+
+int Func13(int x) {
+  return Func12<int>(x);
+}
+
+// CHECK: %call = musttail call i32 @_Z3Bari(i32 %0)
+
+int Func14(int x) {
+  int vla[x];
+  [[clang::musttail]] return Bar(x);
+}
+
+// CHECK: %call = musttail call i32 @_Z3Bari(i32 %3)
+
+void TrivialDestructorParam(HasTrivialDestructor obj);
+
+void Func14(HasTrivialDestructor obj) {
+  [[clang::musttail]] return TrivialDestructorParam(obj);
+}
+
+// CHECK: musttail call void @_Z22TrivialDestructorParam20HasTrivialDestructor()
+
+struct Struct3 {
+  void ConstMemberFunction(const int *) const;
+  void NonConstMemberFunction(int *i);
+};
+void Struct3::NonConstMemberFunction(int *i) {
+  // The parameters are not identical, but they are compatible.
+  [[clang::musttail]] return ConstMemberFunction(i);
+}
+
+// CHECK: musttail call void @_ZNK7Struct319ConstMemberFunctionEPKi(%struct.Struct3* nonnull dereferenceable(1) %this1, i32* %0)
+
+struct HasNonTrivialCopyConstructor {
+  HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);
+};
+HasNonTrivialCopyConstructor ReturnsClassByValue();
+HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {
+  [[clang::musttail]] return (((ReturnsClassByValue())));
+}
+
+// CHECK: musttail call void @_Z19ReturnsClassByValuev(%struct.HasNonTrivialCopyConstructor* sret(%struct.HasNonTrivialCopyConstructor) align 1 %agg.result)
+
+struct HasNonTrivialCopyConstructor2 {
+  // Copy constructor works even if it has extra default params.
+  HasNonTrivialCopyConstructor2(const HasNonTrivialCopyConstructor &, int DefaultParam = 5);
+};
+HasNonTrivialCopyConstructor2 ReturnsClassByValue2();
+HasNonTrivialCopyConstructor2 TestNonElidableCopyConstructor2() {
+  [[clang::musttail]] return (((ReturnsClassByValue2())));
+}
+
+// CHECK: musttail call void @_Z20ReturnsClassByValue2v()
+
+void TestFunctionPointer(int x) {
+  void (*p)(int) = nullptr;
+  [[clang::musttail]] return p(x);
+}
+
+// CHECK: musttail call void %0(i32 %1)
+
+struct LargeWithCopyConstructor {
+  LargeWithCopyConstructor(const LargeWithCopyConstructor &);
+  char data[32];
+};
+LargeWithCopyConstructor ReturnsLarge();
+LargeWithCopyConstructor TestLargeWithCopyConstructor() {
+  [[clang::musttail]] return ReturnsLarge();
+}
+
+// CHECK: define dso_local void @_Z28TestLargeWithCopyConstructorv(%struct.LargeWithCopyConstructor* noalias sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
+// CHECK: musttail call void @_Z12ReturnsLargev(%struct.LargeWithCopyConstructor* sret(%struct.LargeWithCopyConstructor) align 1 %agg.result)
+
+using IntFunctionType = int();
+IntFunctionType *ReturnsIntFunction();
+int TestRValueFunctionPointer() {
+  [[clang::musttail]] return ReturnsIntFunction()();
+}
+
+// CHECK: musttail call i32 %call()
+
+void(FuncWithParens)() {
+  [[clang::musttail]] return FuncWithParens();
+}
+
+// CHECK: musttail call void @_Z14FuncWithParensv()
+
+int TestNonCapturingLambda() {
+  auto lambda = []() { return 12; };
+  [[clang::musttail]] return (+lambda)();
+}
+
+// CHECK: %call = call i32 ()* @"_ZZ22TestNonCapturingLambdavENK3$_0cvPFivEEv"(%class.anon* nonnull dereferenceable(1) %lambda)
+// CHECK: musttail call i32 %call()
+
+class TestVirtual {
+  virtual void TailTo();
+  virtual void TailFrom();
+};
+
+void TestVirtual::TailFrom() {
+  [[clang::musttail]] return TailTo();
+}
+
+// CHECK: musttail call void %1(%class.TestVirtual* nonnull dereferenceable(8) %this1)

diff  --git a/clang/test/Sema/attr-musttail.c b/clang/test/Sema/attr-musttail.c
new file mode 100644
index 000000000000..b17947c68ba9
--- /dev/null
+++ b/clang/test/Sema/attr-musttail.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+int NotAProtoType(); // expected-note{{add 'void' to the parameter list to turn an old-style K&R function declaration into a prototype}}
+int TestCalleeNotProtoType(void) {
+  __attribute__((musttail)) return NotAProtoType(); // expected-error{{'musttail' attribute requires that both caller and callee functions have a prototype}}
+}
+
+int ProtoType(void);
+int TestCallerNotProtoType() {                  // expected-note{{add 'void' to the parameter list to turn an old-style K&R function declaration into a prototype}}
+  __attribute__((musttail)) return ProtoType(); // expected-error{{'musttail' attribute requires that both caller and callee functions have a prototype}}
+}
+
+int TestProtoType(void) {
+  return ProtoType();
+}

diff  --git a/clang/test/Sema/attr-musttail.m b/clang/test/Sema/attr-musttail.m
new file mode 100644
index 000000000000..6549232d107a
--- /dev/null
+++ b/clang/test/Sema/attr-musttail.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class -verify %s
+
+void TestObjcBlock(void) {
+  void (^x)(void) = ^(void) {
+    __attribute__((musttail)) return TestObjcBlock(); // expected-error{{'musttail' attribute cannot be used from a block}}
+  };
+  __attribute__((musttail)) return x();
+}
+
+void ReturnsVoid(void);
+void TestObjcBlockVar(void) {
+  __block int i = 0;                              // expected-note{{jump exits scope of __block variable}}
+  __attribute__((musttail)) return ReturnsVoid(); // expected-error{{cannot perform a tail call from this return statement}}
+}
+
+__attribute__((objc_root_class))
+ at interface TestObjcClass
+ at end
+
+ at implementation TestObjcClass
+
+- (void)testObjCMethod {
+  __attribute__((musttail)) return ReturnsVoid(); // expected-error{{'musttail' attribute cannot be used from an Objective-C function}}
+}
+
+ at end

diff  --git a/clang/test/SemaCXX/attr-musttail.cpp b/clang/test/SemaCXX/attr-musttail.cpp
new file mode 100644
index 000000000000..55faf5a4f5ac
--- /dev/null
+++ b/clang/test/SemaCXX/attr-musttail.cpp
@@ -0,0 +1,269 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -fms-extensions -fcxx-exceptions -fopenmp %s
+
+int ReturnsInt1();
+int Func1() {
+  [[clang::musttail]] ReturnsInt1();              // expected-error {{'musttail' attribute only applies to return statements}}
+  [[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();
+}
+
+void NoFunctionCall() {
+  [[clang::musttail]] return; // expected-error {{'musttail' attribute requires that the return value is the result of a function call}}
+}
+
+[[clang::musttail]] static int int_val = ReturnsInt1(); // expected-error {{'musttail' attribute cannot be applied to a declaration}}
+
+void NoParams(); // expected-note {{target function has 
diff erent number of parameters (expected 1 but has 0)}}
+void TestParamArityMismatch(int x) {
+  [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}}
+  return NoParams();  // expected-error {{cannot perform a tail call to function 'NoParams' because its signature is incompatible with the calling function}}
+}
+
+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}}
+  return LongParam(x); // expected-error {{cannot perform a tail call to function 'LongParam' because its signature is incompatible with the calling function}}
+}
+
+long ReturnsLong(); // expected-note {{target function has 
diff erent return type ('int' expected but has 'long')}}
+int TestReturnTypeMismatch() {
+  [[clang::musttail]]   // expected-note {{tail call required by 'musttail' attribute here}}
+  return ReturnsLong(); // expected-error {{cannot perform a tail call to function 'ReturnsLong' because its signature is incompatible with the calling function}}
+}
+
+struct Struct1 {
+  void MemberFunction(); // expected-note {{'MemberFunction' declared here}}
+};
+void TestNonMemberToMember() {
+  Struct1 st;
+  [[clang::musttail]]         // expected-note {{tail call required by 'musttail' attribute here}}
+  return st.MemberFunction(); // expected-error {{non-member function cannot perform a tail call to non-static member function 'MemberFunction'}}
+}
+
+void ReturnsVoid(); // expected-note {{'ReturnsVoid' declared here}}
+struct Struct2 {
+  void TestMemberToNonMember() {
+    [[clang::musttail]]   // expected-note {{tail call required by 'musttail' attribute here}}
+    return ReturnsVoid(); // expected-error{{non-static member function cannot perform a tail call to non-member function 'ReturnsVoid'}}
+  }
+};
+
+class HasNonTrivialDestructor {
+public:
+  ~HasNonTrivialDestructor() {}
+  int ReturnsInt();
+};
+
+void ReturnsVoid2();
+void TestNonTrivialDestructorInScope() {
+  HasNonTrivialDestructor foo;              // expected-note {{jump exits scope of variable with non-trivial destructor}}
+  [[clang::musttail]] return ReturnsVoid(); // expected-error {{cannot perform a tail call from this return statement}}
+}
+
+int NonTrivialParam(HasNonTrivialDestructor x);
+int TestNonTrivialParam(HasNonTrivialDestructor x) {
+  [[clang::musttail]] return NonTrivialParam(x); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}}
+}
+
+HasNonTrivialDestructor ReturnsNonTrivialValue();
+HasNonTrivialDestructor TestReturnsNonTrivialValue() {
+  // FIXME: the diagnostic cannot currently distinguish between needing to run a
+  // destructor for the return value and needing to run a destructor for some
+  // other temporary created in the return statement.
+  [[clang::musttail]] return (ReturnsNonTrivialValue()); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}}
+}
+
+HasNonTrivialDestructor TestReturnsNonTrivialNonFunctionCall() {
+  [[clang::musttail]] return HasNonTrivialDestructor(); // expected-error {{'musttail' attribute requires that the return value is the result of a function call}}
+}
+
+struct UsesPointerToMember {
+  void (UsesPointerToMember::*p_mem)(); // expected-note {{'p_mem' declared here}}
+};
+void TestUsesPointerToMember(UsesPointerToMember *foo) {
+  // "this" pointer cannot double as first parameter.
+  [[clang::musttail]]            // expected-note {{tail call required by 'musttail' attribute here}}
+  return (foo->*(foo->p_mem))(); // expected-error {{non-member function cannot perform a tail call to pointer-to-member function 'p_mem'}}
+}
+
+void ReturnsVoid2();
+void TestNestedClass() {
+  HasNonTrivialDestructor foo;
+  class Nested {
+    __attribute__((noinline)) static void NestedMethod() {
+      // Outer non-trivial destructor does not affect nested class.
+      [[clang::musttail]] return ReturnsVoid2();
+    }
+  };
+}
+
+template <class T>
+T TemplateFunc(T x) { // expected-note{{target function has 
diff erent return type ('long' expected but has 'int')}}
+  return x ? 5 : 10;
+}
+int OkTemplateFunc(int x) {
+  [[clang::musttail]] return TemplateFunc<int>(x);
+}
+template <class T>
+T BadTemplateFunc(T x) {
+  [[clang::musttail]]          // expected-note {{tail call required by 'musttail' attribute here}}
+  return TemplateFunc<int>(x); // expected-error {{cannot perform a tail call to function 'TemplateFunc' because its signature is incompatible with the calling function}}
+}
+long TestBadTemplateFunc(long x) {
+  return BadTemplateFunc<long>(x); // expected-note {{in instantiation of}}
+}
+
+void IntParam(int x);
+void TestVLA(int x) {
+  HasNonTrivialDestructor vla[x];         // expected-note {{jump exits scope of variable with non-trivial destructor}}
+  [[clang::musttail]] return IntParam(x); // expected-error {{cannot perform a tail call from this return statement}}
+}
+
+void TestNonTrivialDestructorSubArg(int x) {
+  [[clang::musttail]] return IntParam(NonTrivialParam(HasNonTrivialDestructor())); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}}
+}
+
+void VariadicFunction(int x, ...);
+void TestVariadicFunction(int x, ...) {
+  [[clang::musttail]] return VariadicFunction(x); // expected-error {{'musttail' attribute may not be used with variadic functions}}
+}
+
+int TakesIntParam(int x);     // expected-note {{target function has type mismatch at 1st parameter (expected 'int' but has 'short')}}
+int TakesShortParam(short x); // expected-note {{target function has type mismatch at 1st parameter (expected 'short' but has 'int')}}
+int TestIntParamMismatch(int x) {
+  [[clang::musttail]]        // expected-note {{tail call required by 'musttail' attribute here}}
+  return TakesShortParam(x); // expected-error {{cannot perform a tail call to function 'TakesShortParam' because its signature is incompatible with the calling function}}
+}
+int TestIntParamMismatch2(short x) {
+  [[clang::musttail]]      // expected-note {{tail call required by 'musttail' attribute here}}
+  return TakesIntParam(x); // expected-error {{cannot perform a tail call to function 'TakesIntParam' because its signature is incompatible with the calling function}}
+}
+
+struct TestClassMismatch1 {
+  void ToFunction(); // expected-note{{target function is a member of 
diff erent class (expected 'TestClassMismatch2' but has 'TestClassMismatch1')}}
+};
+TestClassMismatch1 *tcm1;
+struct TestClassMismatch2 {
+  void FromFunction() {
+    [[clang::musttail]]        // expected-note {{tail call required by 'musttail' attribute here}}
+    return tcm1->ToFunction(); // expected-error {{cannot perform a tail call to function 'ToFunction' because its signature is incompatible with the calling function}}
+  }
+};
+
+__regcall int RegCallReturnsInt(); // expected-note {{target function has calling convention regcall (expected cdecl)}}
+int TestMismatchCallingConvention() {
+  [[clang::musttail]]         // expected-note {{tail call required by 'musttail' attribute here}}
+  return RegCallReturnsInt(); // expected-error {{cannot perform a tail call to function 'RegCallReturnsInt' because it uses an incompatible calling convention}}
+}
+
+int TestNonCapturingLambda() {
+  auto lambda = []() { return 12; }; // expected-note {{'operator()' declared here}}
+  [[clang::musttail]]                // expected-note {{tail call required by 'musttail' attribute here}}
+  return lambda();                   // expected-error {{non-member function cannot perform a tail call to non-static member function 'operator()'}}
+
+  // This works.
+  auto lambda_fptr = static_cast<int (*)()>(lambda);
+  [[clang::musttail]] return lambda_fptr();
+  [[clang::musttail]] return (+lambda)();
+}
+
+int TestCapturingLambda() {
+  int x;
+  auto lambda = [x]() { return 12; }; // expected-note {{'operator()' declared here}}
+  [[clang::musttail]]                 // expected-note {{tail call required by 'musttail' attribute here}}
+  return lambda();                    // expected-error {{non-member function cannot perform a tail call to non-static member function 'operator()'}}
+}
+
+int TestNonTrivialTemporary(int) {
+  [[clang::musttail]] return TakesIntParam(HasNonTrivialDestructor().ReturnsInt()); // expected-error {{tail call requires that the return value, all parameters, and any temporaries created by the expression are trivially destructible}}
+}
+
+void ReturnsVoid();
+struct TestDestructor {
+  ~TestDestructor() {
+    [[clang::musttail]]   // expected-note {{tail call required by 'musttail' attribute here}}
+    return ReturnsVoid(); // expected-error {{destructor '~TestDestructor' must not return void expression}}  // expected-error {{cannot perform a tail call from a destructor}}
+  }
+};
+
+struct ClassWithDestructor { // expected-note {{target destructor is declared here}}
+  void TestExplicitDestructorCall() {
+    [[clang::musttail]]                  // expected-note {{tail call required by 'musttail' attribute here}}
+    return this->~ClassWithDestructor(); // expected-error {{cannot perform a tail call to a destructor}}
+  }
+};
+
+struct HasNonTrivialCopyConstructor {
+  HasNonTrivialCopyConstructor(const HasNonTrivialCopyConstructor &);
+};
+HasNonTrivialCopyConstructor ReturnsClassByValue();
+HasNonTrivialCopyConstructor TestNonElidableCopyConstructor() {
+  // This is an elidable constructor, but when it is written explicitly
+  // we decline to elide it.
+  [[clang::musttail]] return HasNonTrivialCopyConstructor(ReturnsClassByValue()); // expected-error{{'musttail' attribute requires that the return value is the result of a function call}}
+}
+
+struct ClassWithConstructor {
+  ClassWithConstructor() = default; // expected-note {{target constructor is declared here}}
+};
+void TestExplicitConstructorCall(ClassWithConstructor a) {
+  [[clang::musttail]]                                    // expected-note {{tail call required by 'musttail' attribute here}}
+  return a.ClassWithConstructor::ClassWithConstructor(); // expected-error{{cannot perform a tail call to a constructor}}  expected-warning{{explicit constructor calls are a Microsoft extension}}
+}
+
+void TestStatementExpression() {
+  ({
+    HasNonTrivialDestructor foo;               // expected-note {{jump exits scope of variable with non-trivial destructor}}
+    [[clang::musttail]] return ReturnsVoid2(); // expected-error {{cannot perform a tail call from this return statement}}
+  });
+}
+
+struct MyException {};
+void TestTryBlock() {
+  try {                                        // expected-note {{jump exits try block}}
+    [[clang::musttail]] return ReturnsVoid2(); // expected-error {{cannot perform a tail call from this return statement}}
+  } catch (MyException &e) {
+  }
+}
+
+using IntFunctionType = int();
+IntFunctionType *ReturnsIntFunction();
+long TestRValueFunctionPointer() {
+  [[clang::musttail]]            // expected-note {{tail call required by 'musttail' attribute here}}
+  return ReturnsIntFunction()(); // expected-error{{cannot perform a tail call to function because its signature is incompatible with the calling function}}  // expected-note{{target function has 
diff erent return type ('long' expected but has 'int')}}
+}
+
+void TestPseudoDestructor() {
+  int n;
+  using T = int;
+  [[clang::musttail]] // expected-note {{tail call required by 'musttail' attribute here}}
+  return n.~T();      // expected-error{{cannot perform a tail call to a destructor}}
+}
+
+struct StructPMF {
+  typedef void (StructPMF::*PMF)();
+  static void TestReturnsPMF();
+};
+
+StructPMF *St;
+StructPMF::PMF ReturnsPMF();
+void StructPMF::TestReturnsPMF() {
+  [[clang::musttail]]           // expected-note{{tail call required by 'musttail' attribute here}}
+  return (St->*ReturnsPMF())(); // expected-error{{static member function cannot perform a tail call to pointer-to-member function}}
+}
+
+// These tests are merely verifying that we don't crash with incomplete or
+// erroneous ASTs. These cases crashed the compiler in early iterations.
+
+struct TestBadPMF {
+  int (TestBadPMF::*pmf)();
+  void BadPMF() {
+    [[clang::musttail]] return ((*this)->*pmf)(); // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'TestBadPMF'}}
+  }
+};
+
+namespace ns {}
+void TestCallNonValue() {
+  [[clang::musttail]] return ns; // expected-error {{unexpected namespace name 'ns': expected expression}}
+}


        


More information about the cfe-commits mailing list