r328731 - [ObjC++] Make parameter passing and function return compatible with ObjC

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 28 14:13:14 PDT 2018


Author: ahatanak
Date: Wed Mar 28 14:13:14 2018
New Revision: 328731

URL: http://llvm.org/viewvc/llvm-project?rev=328731&view=rev
Log:
[ObjC++] Make parameter passing and function return compatible with ObjC
    
ObjC and ObjC++ pass non-trivial structs in a way that is incompatible
with each other. For example:
    
typedef struct {
  id f0;
  __weak id f1;
} S;
    
// this code is compiled in c++.
extern "C" {
  void foo(S s);
}
    
void caller() {
  // the caller passes the parameter indirectly and destructs it.
  foo(S());
}
    
// this function is compiled in c.
// 'a' is passed directly and is destructed in the callee.
void foo(S a) {
}
    
This patch fixes the incompatibility by passing and returning structs
with __strong or weak fields using the C ABI in C++ mode. __strong and
__weak fields in a struct do not cause the struct to be destructed in
the caller and __strong fields do not cause the struct to be passed
indirectly.
    
Also, this patch fixes the microsoft ABI bug mentioned here:
    
https://reviews.llvm.org/D41039?id=128767#inline-364710
    
rdar://problem/38887866
    
Differential Revision: https://reviews.llvm.org/D44908

Added:
    cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm
      - copied, changed from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm
Removed:
    cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/LangOptions.def
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Basic/TargetInfo.h
    cfe/trunk/include/clang/Frontend/CodeGenOptions.def
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Basic/TargetInfo.cpp
    cfe/trunk/lib/Basic/Targets/X86.h
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
    cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
    cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 28 14:13:14 2018
@@ -3559,6 +3559,11 @@ class RecordDecl : public TagDecl {
   /// pass an object of this class.
   bool CanPassInRegisters : 1;
 
+  /// Indicates whether this struct is destroyed in the callee. This flag is
+  /// meaningless when Microsoft ABI is used since parameters are always
+  /// destroyed in the callee.
+  bool ParamDestroyedInCallee : 1;
+
 protected:
   RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC,
              SourceLocation StartLoc, SourceLocation IdLoc,
@@ -3654,6 +3659,14 @@ public:
     CanPassInRegisters = CanPass;
   }
 
+  bool isParamDestroyedInCallee() const {
+    return ParamDestroyedInCallee;
+  }
+
+  void setParamDestroyedInCallee(bool V) {
+    ParamDestroyedInCallee = V;
+  }
+
   /// \brief Determines whether this declaration represents the
   /// injected class name.
   ///

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Mar 28 14:13:14 2018
@@ -1468,13 +1468,6 @@ public:
     return data().HasIrrelevantDestructor;
   }
 
-  /// Determine whether the triviality for the purpose of calls for this class
-  /// is overridden to be trivial because this class or the type of one of its
-  /// subobjects has attribute "trivial_abi".
-  bool hasTrivialABIOverride() const {
-    return canPassInRegisters() && hasNonTrivialDestructor();
-  }
-
   /// \brief Determine whether this class has a non-literal or/ volatile type
   /// non-static data member or base class.
   bool hasNonLiteralTypeFieldsOrBases() const {

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Mar 28 14:13:14 2018
@@ -808,11 +808,6 @@ public:
   /// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
   bool isTriviallyCopyableType(const ASTContext &Context) const;
 
-  /// Determine whether this is a class whose triviality for the purpose of
-  /// calls is overridden to be trivial because the class or the type of one of
-  /// its subobjects has attribute "trivial_abi".
-  bool hasTrivialABIOverride() const;
-
   // Don't promise in the API that anything besides 'const' can be
   // easily added.
 

Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Wed Mar 28 14:13:14 2018
@@ -284,6 +284,10 @@ LANGOPT(XRayAlwaysEmitCustomEvents, 1, 0
 BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0,
                "allow editor placeholders in source")
 
+ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest,
+             "version of Clang that we should attempt to be ABI-compatible "
+             "with")
+
 #undef LANGOPT
 #undef COMPATIBLE_LANGOPT
 #undef BENIGN_LANGOPT

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Wed Mar 28 14:13:14 2018
@@ -102,6 +102,23 @@ public:
     MSVC2015 = 19
   };
 
+  /// Clang versions with different platform ABI conformance.
+  enum class ClangABI {
+    /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
+    /// (SVN r257626). This causes <1 x long long> to be passed in an
+    /// integer register instead of an SSE register on x64_64.
+    Ver3_8,
+
+    /// Attempt to be ABI-compatible with code generated by Clang 4.0.x
+    /// (SVN r291814). This causes move operations to be ignored when
+    /// determining whether a class type can be passed or returned directly.
+    Ver4,
+
+    /// Conform to the underlying platform's C and C++ ABIs as closely
+    /// as we can.
+    Latest
+  };
+
   enum FPContractModeKind {
     // Form fused FP ops only where result will not be affected.
     FPC_Off,

Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Wed Mar 28 14:13:14 2018
@@ -1053,6 +1053,14 @@ public:
     }
   }
 
+  enum CallingConvKind {
+    CCK_Default,
+    CCK_ClangABI4OrPS4,
+    CCK_MicrosoftX86_64
+  };
+
+  virtual CallingConvKind getCallingConvKind(bool ClangABICompat4) const;
+
   /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to
   /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp.
   virtual bool hasSjLjLowering() const {

Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original)
+++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Wed Mar 28 14:13:14 2018
@@ -138,9 +138,6 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjC
 CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
                                         ///< enabled.
 
-/// A version of Clang that we should attempt to be ABI-compatible with.
-ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest)
-
 VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
 VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
 

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Mar 28 14:13:14 2018
@@ -2643,9 +2643,11 @@ void ASTContext::adjustExceptionSpec(
 }
 
 bool ASTContext::isParamDestroyedInCallee(QualType T) const {
-  return getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee() ||
-         T.hasTrivialABIOverride() ||
-         T.isDestructedType() == QualType::DK_nontrivial_c_struct;
+  if (getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee())
+    return true;
+  if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
+    return RT->getDecl()->isParamDestroyedInCallee();
+  return false;
 }
 
 /// getComplexType - Return the uniqued reference to the type for a complex

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Mar 28 14:13:14 2018
@@ -3951,7 +3951,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind
       LoadedFieldsFromExternalStorage(false),
       NonTrivialToPrimitiveDefaultInitialize(false),
       NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false),
-      CanPassInRegisters(true) {
+      CanPassInRegisters(true), ParamDestroyedInCallee(false) {
   assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
 }
 

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Mar 28 14:13:14 2018
@@ -801,7 +801,17 @@ void CXXRecordDecl::addedMember(Decl *D)
         struct DefinitionData &Data = data();
         Data.PlainOldData = false;
         Data.HasTrivialSpecialMembers = 0;
-        Data.HasTrivialSpecialMembersForCall = 0;
+
+        // __strong or __weak fields do not make special functions non-trivial
+        // for the purpose of calls.
+        Qualifiers::ObjCLifetime LT = T.getQualifiers().getObjCLifetime();
+        if (LT != Qualifiers::OCL_Strong && LT != Qualifiers::OCL_Weak)
+          data().HasTrivialSpecialMembersForCall = 0;
+
+        // Structs with __weak fields should never be passed directly.
+        if (LT == Qualifiers::OCL_Weak)
+          setCanPassInRegisters(false);
+
         Data.HasIrrelevantDestructor = false;
       } else if (!Context.getLangOpts().ObjCAutoRefCount) {
         setHasObjectMember(true);

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Wed Mar 28 14:13:14 2018
@@ -2195,12 +2195,6 @@ bool QualType::isTriviallyCopyableType(c
   return false;
 }
 
-bool QualType::hasTrivialABIOverride() const {
-  if (const auto *RD = getTypePtr()->getAsCXXRecordDecl())
-    return RD->hasTrivialABIOverride();
-  return false;
-}
-
 bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
   return !Context.getLangOpts().ObjCAutoRefCount &&
          Context.getLangOpts().ObjCWeak &&

Modified: cfe/trunk/lib/Basic/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/TargetInfo.cpp (original)
+++ cfe/trunk/lib/Basic/TargetInfo.cpp Wed Mar 28 14:13:14 2018
@@ -357,6 +357,14 @@ bool TargetInfo::initFeatureMap(
   return true;
 }
 
+TargetInfo::CallingConvKind
+TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
+  if (getCXXABI() != TargetCXXABI::Microsoft &&
+      (ClangABICompat4 || getTriple().getOS() == llvm::Triple::PS4))
+    return CCK_ClangABI4OrPS4;
+  return CCK_Default;
+}
+
 LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const {
   switch (TK) {
   case OCLTK_Image:

Modified: cfe/trunk/lib/Basic/Targets/X86.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.h?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Targets/X86.h (original)
+++ cfe/trunk/lib/Basic/Targets/X86.h Wed Mar 28 14:13:14 2018
@@ -728,6 +728,11 @@ public:
     Builder.defineMacro("_M_X64", "100");
     Builder.defineMacro("_M_AMD64", "100");
   }
+
+  TargetInfo::CallingConvKind
+  getCallingConvKind(bool ClangABICompat4) const override {
+    return CCK_MicrosoftX86_64;
+  }
 };
 
 // x86-64 MinGW target

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Mar 28 14:13:14 2018
@@ -3540,24 +3540,13 @@ void CodeGenFunction::EmitCallArg(CallAr
     else
       Slot = CreateAggTemp(type, "agg.tmp");
 
-    bool DestroyedInCallee = true, NeedsEHCleanup = true;
-    if (const auto *RD = type->getAsCXXRecordDecl()) {
-      DestroyedInCallee =
-          RD && RD->hasNonTrivialDestructor() &&
-          (CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default ||
-           RD->hasTrivialABIOverride());
-    } else {
-      NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
-    }
-
-    if (DestroyedInCallee)
-      Slot.setExternallyDestructed();
+    Slot.setExternallyDestructed();
 
     EmitAggExpr(E, Slot);
     RValue RV = Slot.asRValue();
     args.add(RV, type);
 
-    if (DestroyedInCallee && NeedsEHCleanup) {
+    if (type->getAsCXXRecordDecl() || needsEHCleanup(type.isDestructedType())) {
       // Create a no-op GEP between the placeholder and the cleanup so we can
       // RAUW it successfully.  It also serves as a marker of the first
       // instruction where the cleanup is active.

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Mar 28 14:13:14 2018
@@ -63,13 +63,6 @@ public:
   bool classifyReturnType(CGFunctionInfo &FI) const override;
 
   bool passClassIndirect(const CXXRecordDecl *RD) const {
-    // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
-    // The PS4 platform ABI follows the behavior of Clang 3.2.
-    if (CGM.getCodeGenOpts().getClangABICompat() <=
-            CodeGenOptions::ClangABI::Ver4 ||
-        CGM.getTriple().getOS() == llvm::Triple::PS4)
-      return RD->hasNonTrivialDestructorForCall() ||
-             RD->hasNonTrivialCopyConstructorForCall();
     return !canCopyArgument(RD);
   }
 

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Mar 28 14:13:14 2018
@@ -829,60 +829,7 @@ MicrosoftCXXABI::getRecordArgABI(const C
     return RAA_Default;
 
   case llvm::Triple::x86_64:
-    bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
-    bool DtorIsTrivialForCall = false;
-
-    // If a class has at least one non-deleted, trivial copy constructor, it
-    // is passed according to the C ABI. Otherwise, it is passed indirectly.
-    //
-    // Note: This permits classes with non-trivial copy or move ctors to be
-    // passed in registers, so long as they *also* have a trivial copy ctor,
-    // which is non-conforming.
-    if (RD->needsImplicitCopyConstructor()) {
-      if (!RD->defaultedCopyConstructorIsDeleted()) {
-        if (RD->hasTrivialCopyConstructor())
-          CopyCtorIsTrivial = true;
-        if (RD->hasTrivialCopyConstructorForCall())
-          CopyCtorIsTrivialForCall = true;
-      }
-    } else {
-      for (const CXXConstructorDecl *CD : RD->ctors()) {
-        if (CD->isCopyConstructor() && !CD->isDeleted()) {
-          if (CD->isTrivial())
-            CopyCtorIsTrivial = true;
-          if (CD->isTrivialForCall())
-            CopyCtorIsTrivialForCall = true;
-        }
-      }
-    }
-
-    if (RD->needsImplicitDestructor()) {
-      if (!RD->defaultedDestructorIsDeleted() &&
-          RD->hasTrivialDestructorForCall())
-        DtorIsTrivialForCall = true;
-    } else if (const auto *D = RD->getDestructor()) {
-      if (!D->isDeleted() && D->isTrivialForCall())
-        DtorIsTrivialForCall = true;
-    }
-
-    // If the copy ctor and dtor are both trivial-for-calls, pass direct.
-    if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall)
-      return RAA_Default;
-
-    // If a class has a destructor, we'd really like to pass it indirectly
-    // because it allows us to elide copies.  Unfortunately, MSVC makes that
-    // impossible for small types, which it will pass in a single register or
-    // stack slot. Most objects with dtors are large-ish, so handle that early.
-    // We can't call out all large objects as being indirect because there are
-    // multiple x64 calling conventions and the C++ ABI code shouldn't dictate
-    // how we pass large POD types.
-
-    // Note: This permits small classes with nontrivial destructors to be
-    // passed in registers, which is non-conforming.
-    if (CopyCtorIsTrivial &&
-        getContext().getTypeSize(RD->getTypeForDecl()) <= 64)
-      return RAA_Default;
-    return RAA_Indirect;
+    return !canCopyArgument(RD) ? RAA_Indirect : RAA_Default;
   }
 
   llvm_unreachable("invalid enum");

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Mar 28 14:13:14 2018
@@ -2131,8 +2131,8 @@ class X86_64ABIInfo : public SwiftABIInf
   /// classify it as INTEGER (for compatibility with older clang compilers).
   bool classifyIntegerMMXAsSSE() const {
     // Clang <= 3.8 did not do this.
-    if (getCodeGenOpts().getClangABICompat() <=
-        CodeGenOptions::ClangABI::Ver3_8)
+    if (getContext().getLangOpts().getClangABICompat() <=
+        LangOptions::ClangABI::Ver3_8)
       return false;
 
     const llvm::Triple &Triple = getTarget().getTriple();

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Wed Mar 28 14:13:14 2018
@@ -633,33 +633,6 @@ static bool ParseCodeGenArgs(CodeGenOpti
   if (!Opts.ProfileInstrumentUsePath.empty())
     setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
 
-  if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
-    Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
-
-    StringRef Ver = A->getValue();
-    std::pair<StringRef, StringRef> VerParts = Ver.split('.');
-    unsigned Major, Minor = 0;
-
-    // Check the version number is valid: either 3.x (0 <= x <= 9) or
-    // y or y.0 (4 <= y <= current version).
-    if (!VerParts.first.startswith("0") &&
-        !VerParts.first.getAsInteger(10, Major) &&
-        3 <= Major && Major <= CLANG_VERSION_MAJOR &&
-        (Major == 3 ? VerParts.second.size() == 1 &&
-                      !VerParts.second.getAsInteger(10, Minor)
-                    : VerParts.first.size() == Ver.size() ||
-                      VerParts.second == "0")) {
-      // Got a valid version number.
-      if (Major == 3 && Minor <= 8)
-        Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8);
-      else if (Major <= 4)
-        Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
-    } else if (Ver != "latest") {
-      Diags.Report(diag::err_drv_invalid_value)
-          << A->getAsString(Args) << A->getValue();
-    }
-  }
-
   Opts.CoverageMapping =
       Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
   Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
@@ -2670,6 +2643,33 @@ static void ParseLangArgs(LangOptions &O
 
   // -fallow-editor-placeholders
   Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
+
+  if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
+    Opts.setClangABICompat(LangOptions::ClangABI::Latest);
+
+    StringRef Ver = A->getValue();
+    std::pair<StringRef, StringRef> VerParts = Ver.split('.');
+    unsigned Major, Minor = 0;
+
+    // Check the version number is valid: either 3.x (0 <= x <= 9) or
+    // y or y.0 (4 <= y <= current version).
+    if (!VerParts.first.startswith("0") &&
+        !VerParts.first.getAsInteger(10, Major) &&
+        3 <= Major && Major <= CLANG_VERSION_MAJOR &&
+        (Major == 3 ? VerParts.second.size() == 1 &&
+                      !VerParts.second.getAsInteger(10, Minor)
+                    : VerParts.first.size() == Ver.size() ||
+                      VerParts.second == "0")) {
+      // Got a valid version number.
+      if (Major == 3 && Minor <= 8)
+        Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
+      else if (Major <= 4)
+        Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
+    } else if (Ver != "latest") {
+      Diags.Report(diag::err_drv_invalid_value)
+          << A->getAsString(Args) << A->getValue();
+    }
+  }
 }
 
 static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 28 14:13:14 2018
@@ -15461,8 +15461,10 @@ void Sema::ActOnFields(Scope *S, SourceL
       QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy();
       if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial)
         Record->setNonTrivialToPrimitiveCopy(true);
-      if (FT.isDestructedType())
+      if (FT.isDestructedType()) {
         Record->setNonTrivialToPrimitiveDestroy(true);
+        Record->setParamDestroyedInCallee(true);
+      }
       if (!FT.canPassInRegisters())
         Record->setCanPassInRegisters(false);
     }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Mar 28 14:13:14 2018
@@ -5791,12 +5791,21 @@ static void DefineImplicitSpecialMember(
   }
 }
 
-/// Determine whether a type is permitted to be passed or returned in
-/// registers, per C++ [class.temporary]p3.
-static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) {
+/// Determine whether a type would be destructed in the callee if it had a
+/// non-trivial destructor. The rules here are based on C++ [class.temporary]p3,
+/// which determines whether a struct can be passed to or returned from
+/// functions in registers.
+static bool paramCanBeDestroyedInCallee(Sema &S, CXXRecordDecl *D,
+                                        TargetInfo::CallingConvKind CCK) {
   if (D->isDependentType() || D->isInvalidDecl())
     return false;
 
+  // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
+  // The PS4 platform ABI follows the behavior of Clang 3.2.
+  if (CCK == TargetInfo::CCK_ClangABI4OrPS4)
+    return !D->hasNonTrivialDestructorForCall() &&
+           !D->hasNonTrivialCopyConstructorForCall();
+
   // Per C++ [class.temporary]p3, the relevant condition is:
   //   each copy constructor, move constructor, and destructor of X is
   //   either trivial or deleted, and X has at least one non-deleted copy
@@ -5838,6 +5847,77 @@ static bool computeCanPassInRegisters(Se
   return HasNonDeletedCopyOrMove;
 }
 
+static bool computeCanPassInRegister(bool DestroyedInCallee,
+                                     const CXXRecordDecl *RD,
+                                     TargetInfo::CallingConvKind CCK,
+                                     Sema &S) {
+  if (RD->isDependentType() || RD->isInvalidDecl())
+    return true;
+
+  // The param cannot be passed in registers if CanPassInRegisters is already
+  // set to false.
+  if (!RD->canPassInRegisters())
+    return false;
+
+  if (CCK != TargetInfo::CCK_MicrosoftX86_64)
+    return DestroyedInCallee;
+
+  bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
+  bool DtorIsTrivialForCall = false;
+
+  // If a class has at least one non-deleted, trivial copy constructor, it
+  // is passed according to the C ABI. Otherwise, it is passed indirectly.
+  //
+  // Note: This permits classes with non-trivial copy or move ctors to be
+  // passed in registers, so long as they *also* have a trivial copy ctor,
+  // which is non-conforming.
+  if (RD->needsImplicitCopyConstructor()) {
+    if (!RD->defaultedCopyConstructorIsDeleted()) {
+      if (RD->hasTrivialCopyConstructor())
+        CopyCtorIsTrivial = true;
+      if (RD->hasTrivialCopyConstructorForCall())
+        CopyCtorIsTrivialForCall = true;
+    }
+  } else {
+    for (const CXXConstructorDecl *CD : RD->ctors()) {
+      if (CD->isCopyConstructor() && !CD->isDeleted()) {
+        if (CD->isTrivial())
+          CopyCtorIsTrivial = true;
+        if (CD->isTrivialForCall())
+          CopyCtorIsTrivialForCall = true;
+      }
+    }
+  }
+
+  if (RD->needsImplicitDestructor()) {
+    if (!RD->defaultedDestructorIsDeleted() &&
+        RD->hasTrivialDestructorForCall())
+      DtorIsTrivialForCall = true;
+  } else if (const auto *D = RD->getDestructor()) {
+    if (!D->isDeleted() && D->isTrivialForCall())
+      DtorIsTrivialForCall = true;
+  }
+
+  // If the copy ctor and dtor are both trivial-for-calls, pass direct.
+  if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall)
+    return true;
+
+  // If a class has a destructor, we'd really like to pass it indirectly
+  // because it allows us to elide copies.  Unfortunately, MSVC makes that
+  // impossible for small types, which it will pass in a single register or
+  // stack slot. Most objects with dtors are large-ish, so handle that early.
+  // We can't call out all large objects as being indirect because there are
+  // multiple x64 calling conventions and the C++ ABI code shouldn't dictate
+  // how we pass large POD types.
+
+  // Note: This permits small classes with nontrivial destructors to be
+  // passed in registers, which is non-conforming.
+  if (CopyCtorIsTrivial &&
+      S.getASTContext().getTypeSize(RD->getTypeForDecl()) <= 64)
+    return true;
+  return false;
+}
+
 /// \brief Perform semantic checks on a class definition that has been
 /// completing, introducing implicitly-declared members, checking for
 /// abstract types, etc.
@@ -6001,7 +6081,17 @@ void Sema::CheckCompletedCXXClass(CXXRec
 
   checkClassLevelDLLAttribute(Record);
 
-  Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record));
+  bool ClangABICompat4 =
+      Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
+  TargetInfo::CallingConvKind CCK =
+      Context.getTargetInfo().getCallingConvKind(ClangABICompat4);
+  bool DestroyedInCallee = paramCanBeDestroyedInCallee(*this, Record, CCK);
+
+  if (Record->hasNonTrivialDestructor())
+    Record->setParamDestroyedInCallee(DestroyedInCallee);
+
+  Record->setCanPassInRegisters(
+      computeCanPassInRegister(DestroyedInCallee, Record, CCK, *this));
 }
 
 /// Look up the special member function that would be called by a special

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Mar 28 14:13:14 2018
@@ -743,6 +743,7 @@ ASTDeclReader::VisitRecordDeclImpl(Recor
   RD->setNonTrivialToPrimitiveCopy(Record.readInt());
   RD->setNonTrivialToPrimitiveDestroy(Record.readInt());
   RD->setCanPassInRegisters(Record.readInt());
+  RD->setParamDestroyedInCallee(Record.readInt());
   return Redecl;
 }
 
@@ -4109,6 +4110,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
           OldDD && (OldDD->Definition != RD ||
                     !Reader.PendingFakeDefinitionData.count(OldDD));
       RD->setCanPassInRegisters(Record.readInt());
+      RD->setParamDestroyedInCallee(Record.readInt());
       ReadCXXRecordDefinition(RD, /*Update*/true);
 
       // Visible update is handled separately.

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Mar 28 14:13:14 2018
@@ -5194,6 +5194,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(R
         auto *RD = cast<CXXRecordDecl>(D);
         UpdatedDeclContexts.insert(RD->getPrimaryContext());
         Record.push_back(RD->canPassInRegisters());
+        Record.push_back(RD->isParamDestroyedInCallee());
         Record.AddCXXDefinitionData(RD);
         Record.AddOffset(WriteDeclContextLexicalBlock(
             *Context, const_cast<CXXRecordDecl *>(RD)));

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Mar 28 14:13:14 2018
@@ -470,6 +470,7 @@ void ASTDeclWriter::VisitRecordDecl(Reco
   Record.push_back(D->isNonTrivialToPrimitiveCopy());
   Record.push_back(D->isNonTrivialToPrimitiveDestroy());
   Record.push_back(D->canPassInRegisters());
+  Record.push_back(D->isParamDestroyedInCallee());
 
   if (D->getDeclContext() == D->getLexicalDeclContext() &&
       !D->hasAttrs() &&
@@ -1912,6 +1913,8 @@ void ASTWriter::WriteDeclAbbrevs() {
   // isNonTrivialToPrimitiveDestroy
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // canPassInRegisters
+  // isParamDestroyedInCallee
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
 
   // DC
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // LexicalOffset

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp Wed Mar 28 14:13:14 2018
@@ -172,12 +172,9 @@ void small_arg_with_dtor(SmallWithDtor s
 void call_small_arg_with_dtor() {
   small_arg_with_dtor(SmallWithDtor());
 }
-// The temporary is copied, so it's destroyed in the caller as well as the
-// callee.
 // WIN64-LABEL: define dso_local void @"?call_small_arg_with_dtor@@YAXXZ"()
 // WIN64:   call %struct.SmallWithDtor* @"??0SmallWithDtor@@QEAA at XZ"
 // WIN64:   call void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %{{.*}})
-// WIN64:   call void @"??1SmallWithDtor@@QEAA at XZ"
 // WIN64:   ret void
 
 // Test that references aren't destroyed in the callee.

Modified: cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm Wed Mar 28 14:13:14 2018
@@ -31,6 +31,8 @@ void test_ObjCMember_copy_construct_dest
 void test_ObjCMember_copy_assign(ObjCMember m1, ObjCMember m2) {
   // CHECK: {{call.*_ZN10ObjCMemberaSERKS_}}
   m1 = m2;
+  // CHECK-NEXT: call void @_ZN10ObjCMemberD1Ev(
+  // CHECK-NEXT: call void @_ZN10ObjCMemberD1Ev(
   // CHECK-NEXT: ret void
 }
 
@@ -58,6 +60,8 @@ void test_ObjCArrayMember_copy_construct
 void test_ObjCArrayMember_copy_assign(ObjCArrayMember m1, ObjCArrayMember m2) {
   // CHECK: {{call.*@_ZN15ObjCArrayMemberaSERKS_}}
   m1 = m2;
+  // CHECK-NEXT: call void @_ZN15ObjCArrayMemberD1Ev(
+  // CHECK-NEXT: call void @_ZN15ObjCArrayMemberD1Ev(
   // CHECK-NEXT: ret void
 }
 
@@ -79,7 +83,8 @@ void test_ObjCBlockMember_default_constr
 void test_ObjCBlockMember_copy_construct_destruct(ObjCBlockMember m1) {
   // CHECK: call void @_ZN15ObjCBlockMemberC1ERKS_
   ObjCBlockMember m2 = m1;
-  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev(
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev(
   // CHECK-NEXT: ret void
 }
 
@@ -87,6 +92,8 @@ void test_ObjCBlockMember_copy_construct
 void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
   // CHECK: {{call.*_ZN15ObjCBlockMemberaSERKS_}}
   m1 = m2;
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev(
+  // CHECK-NEXT: call void @_ZN15ObjCBlockMemberD1Ev(
   // CHECK-NEXT: ret void
 }
 

Copied: cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm (from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm?p2=cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm&p1=cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm&r1=328730&r2=328731&rev=328731&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm Wed Mar 28 14:13:14 2018
@@ -1,27 +1,60 @@
 // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
+
+// Check that structs consisting solely of __strong or __weak pointer fields are
+// destructed in the callee function and structs consisting solely of __strong
+// pointer fields are passed directly.
 
 // CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
 // CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
 // CHECK: %[[STRUCT_S:.*]] = type { i8* }
+// CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* }
 
+#ifdef TRIVIALABI
 struct __attribute__((trivial_abi)) StrongWeak {
+#else
+struct StrongWeak {
+#endif
   id fstrong;
   __weak id fweak;
 };
 
+#ifdef TRIVIALABI
 struct __attribute__((trivial_abi)) Strong {
+#else
+struct Strong {
+#endif
   id fstrong;
 };
 
 template<class T>
+#ifdef TRIVIALABI
 struct __attribute__((trivial_abi)) S {
+#else
+struct S {
+#endif
   T a;
 };
 
+struct NonTrivial {
+  NonTrivial();
+  NonTrivial(const NonTrivial &);
+  ~NonTrivial();
+  int *a;
+};
+
+// This struct is not passed directly nor destructed in the callee because f0
+// has type NonTrivial.
+struct ContainsNonTrivial {
+  NonTrivial f0;
+  id f1;
+};
+
 // CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
-// CHECK-NOT: call
-// CHECK: ret void
+// CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev(
+// CHECK-NEXT: ret void
 
 void testParamStrongWeak(StrongWeak a) {
 }
@@ -33,7 +66,7 @@ void testParamStrongWeak(StrongWeak a) {
 // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
 // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
 // CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
-// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
+// CHECK-NOT: call
 // CHECK: ret void
 
 void testCallStrongWeak(StrongWeak *a) {
@@ -96,8 +129,23 @@ Strong testReturnStrong(Strong *a) {
 }
 
 // CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
+// CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev(
+// CHECK-NEXT: ret void
+
+void testParamWeakTemplate(S<__weak id> a) {
+}
+
+// CHECK: define void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
 // CHECK-NOT: call
 // CHECK: ret void
 
-void testParamWeakTemplate(S<__weak id> a) {
+void testParamContainsNonTrivial(ContainsNonTrivial a) {
+}
+
+// CHECK: define void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial(
+// CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
+// CHECK: call %struct.ContainsNonTrivial* @_ZN18ContainsNonTrivialD1Ev(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
+
+void testCallContainsNonTrivial(ContainsNonTrivial *a) {
+  testParamContainsNonTrivial(*a);
 }

Modified: cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm?rev=328731&r1=328730&r2=328731&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm Wed Mar 28 14:13:14 2018
@@ -1,11 +1,13 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++1z -fobjc-arc -o - %s | FileCheck %s
 
 struct S0 {
+  ~S0();
   id f;
 };
 
 struct S1 {
   S1();
+  ~S1();
   S1(S0);
   id f;
 };

Removed: cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm?rev=328730&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm (removed)
@@ -1,103 +0,0 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
-
-// CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
-// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
-// CHECK: %[[STRUCT_S:.*]] = type { i8* }
-
-struct __attribute__((trivial_abi)) StrongWeak {
-  id fstrong;
-  __weak id fweak;
-};
-
-struct __attribute__((trivial_abi)) Strong {
-  id fstrong;
-};
-
-template<class T>
-struct __attribute__((trivial_abi)) S {
-  T a;
-};
-
-// CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
-// CHECK-NOT: call
-// CHECK: ret void
-
-void testParamStrongWeak(StrongWeak a) {
-}
-
-// CHECK: define void @_Z18testCallStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[A:.*]])
-// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
-// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
-// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
-// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
-// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
-// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
-// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
-// CHECK: ret void
-
-void testCallStrongWeak(StrongWeak *a) {
-  testParamStrongWeak(*a);
-}
-
-// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]])
-// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
-// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
-// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
-// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_RESULT]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
-// CHECK: ret void
-
-StrongWeak testReturnStrongWeak(StrongWeak *a) {
-  return *a;
-}
-
-// CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]])
-// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8
-// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0
-// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i8*
-// CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8
-// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* %[[A]])
-// CHECK: ret void
-
-// CHECK: define linkonce_odr %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(
-
-void testParamStrong(Strong a) {
-}
-
-// CHECK: define void @_Z14testCallStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
-// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
-// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
-// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
-// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
-// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[AGG_TMP]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
-// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
-// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
-// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
-// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]])
-// CHECK: ret void
-
-void testCallStrong(Strong *a) {
-  testParamStrong(*a);
-}
-
-// CHECK: define i64 @_Z16testReturnStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
-// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
-// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
-// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
-// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
-// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[RETVAL]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
-// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
-// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
-// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
-// CHECK: ret i64 %[[COERCE_VAL_PI]]
-
-Strong testReturnStrong(Strong *a) {
-  return *a;
-}
-
-// CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
-// CHECK-NOT: call
-// CHECK: ret void
-
-void testParamWeakTemplate(S<__weak id> a) {
-}




More information about the cfe-commits mailing list