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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 25 14:39:03 PDT 2018


Thanks, this looks good to me.

--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -1955,8 +1955,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D,
ParamValue Arg,
     // Push a destructor cleanup for this parameter if the ABI requires it.
     // Don't push a cleanup in a thunk for a method that will also emit a
     // cleanup.
-    if (!IsScalar && !CurFuncIsThunk &&
-        getContext().isParamDestroyedInCallee(Ty)) {
+    if (hasAggregateEvaluationKind(Ty) && !CurFuncIsThunk &&
+        Ty->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {

Is there a guarantee that "aggregate evaluation kind" implies that the type
is a record type?

--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -3596,9 +3596,7 @@ private:
   bool NonTrivialToPrimitiveCopy : 1;
   bool NonTrivialToPrimitiveDestroy : 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.
+  /// Indicates whether this struct is destroyed in the callee.
   ///
   /// Please note that MSVC won't merge adjacent bitfields if they don't
have
   /// the same type.

Unrelated to this change, but please note that MSVC won't merge adjacent
bitfields if they don't have the same type. You should change all the
bit-fields in this run of bit-fields to have the same type (maybe unsigned)
so they actually get packed together when compiling with MSVC.

On 10 April 2018 at 14:57, Akira Hatanaka via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

>
>
> On Apr 6, 2018, at 9:34 AM, Akira Hatanaka <ahatanaka at apple.com> wrote:
>
>
>
> On Apr 4, 2018, at 2:15 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>
> On 4 April 2018 at 11:57, Akira Hatanaka via cfe-commits <cfe-commits@
> lists.llvm.org> wrote:
>
>> On Apr 4, 2018, at 10:55 AM, Richard Smith <richard at metafoo.co.uk> wrote:
>>
>> On 3 April 2018 at 21:58, Akira Hatanaka via cfe-commits <
>> cfe-commits at lists.llvm.org> wrote:
>>
>>> On Apr 3, 2018, at 7:56 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>>>
>>> On 3 April 2018 at 13:07, Akira Hatanaka via cfe-commits <
>>> cfe-commits at lists.llvm.org> wrote:
>>>
>>>>
>>>>
>>>> On Apr 1, 2018, at 6:00 PM, Richard Smith <richard at metafoo.co.uk>
>>>> wrote:
>>>>
>>>> On 28 March 2018 at 14:13, Akira Hatanaka via cfe-commits <
>>>> cfe-commits at lists.llvm.org> wrote:
>>>>
>>>>> 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/t
>>>>> rivial_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/c
>>>>> lang/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/c
>>>>> lang/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/c
>>>>> lang/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/c
>>>>> lang/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/c
>>>>> lang/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/c
>>>>> lang/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/c
>>>>> lang/Frontend/CodeGenOptions.def?rev=328731&r1=328730&r2=328
>>>>> 731&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/A
>>>>> STContext.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().areArgsDestroyedLeftToRightInCa
>>>>> llee())
>>>>> +    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/D
>>>>> ecl.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/D
>>>>> eclCXX.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().getObjCLifet
>>>>> ime();
>>>>> +        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/T
>>>>> ype.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/CodeG
>>>>> en/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/CodeG
>>>>> en/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/CodeG
>>>>> en/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/CodeG
>>>>> en/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/Front
>>>>> end/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));
>>>>>  }
>>>>>
>>>>
>>>> The naming you're using here doesn't make any sense to me.
>>>>
>>>> "paramCanBeDestroyedInCallee" is computing whether the class is allowed
>>>> to be passed in registers (per the language rules), not whether it's
>>>> destroyed in callee (which is based on whether we're using the MS ABI,
>>>> which sometimes destroys parameters in the callee).
>>>> "computeCanPassInRegister" appears to be computing whether the
>>>> parameter *should* be passed in registers (per the quirks of the ABI), not
>>>> whether it can be passed in registers. (Also I'm not sure why you converted
>>>> the name from plural to singular -- we really do mean zero or more
>>>> registers here, not exactly one.)
>>>>
>>>>
>>>> Does this patch make more sense to you?
>>>>
>>>
>>> Yes, thanks, but canPassInRegisters is still documented as computing the
>>> standard notion of "can be passed in registers" but is actually now
>>> computing an ABI-specific notion of "should be passed in registers" (which
>>> is the same except in the MSABI case where we pass some things in registers
>>> even when we're not actually allowed to); please update the comments to
>>> match, and consider renaming it to just "passInRegisters".
>>>
>>>
>> On reflection, I think the current name is better, since this doesn't
>> govern whether the type is actually passed in registers, merely whether
>> it's passable in registers (per the ABI rules), where we assume that types
>> that are passable in registers but not actually passed in registers still
>> behave as if they were passed in registers (in particular, the cleanups
>> happen in the callee, and they may be subject to memcpy along the way).
>>
>>
>>> I'm also not clear why you need to store a bit for "param destroyed in
>>> callee", since it seems to always be equivalent to
>>> hasNonTrivialDestructor() && passInRegisters(). Are there cases where
>>> paramDestroyedInCallee() is intentionally different from that?
>>>
>>>
>>>
>>> Yes, struct ’S’ in the summary of https://reviews.llvm.org/D44908 is
>>> destructed in the callee and passed indirectly, so
>>> “hasNonTrivialDestructor() && passInRegisters()” would return false while
>>> paramDestroyedInCallee() returns true. We want to have it destructed in the
>>> callee so that the struct can be passed from C++ code to C code.
>>>
>>
>> That seems like the wrong way to model that type to me. The type from
>> D44908 should have a non-trivial destructor, because destroying an instance
>> of it needs to run code (otherwise you'll cause all sorts of havoc, for
>> instance if such a type is held in a standard library container the __weak
>> cleanups won't run).
>>
>> If we want to say that it's passed in registers *despite having a
>> non-trivial destructor* and destroy it in the callee, for compatibility
>> with C types containing __weak / __strong fields, then that seems fine to
>> me, but we should not claim that the type has a trivial destructor when it
>> does not.
>>
>>
>> I didn’t intend to claim that the type has a trivial destructor, because
>> struct ’S’ does have and need a non-trivial destructor. Just to clarify,
>> 'hasNonTrivialDestructor() && canPassInRegisters()' returns false for
>> struct ’S’ because canPassInRegisters() returns false, not because
>> hasNonTrivialDestructor() returns false (it doesn’t).
>>
>> Does that clarify what I said?
>>
>
> Ah, yes, my apologies for the misunderstanding. That makes sense.
>
> I like your suggested patch, but I'd still like to see the comments
> updated to match (particularly RecordDecl::CanPassInRegisters and the
> canPassInRegisters function).
>
>
> I’ll send a new patch with updated comments.
>
>
> Here is the new patch.
>
>
>
> Have you considered taking the target's "destroyed right to left in
> callee" flag into account when computing ParamDestroyedInCallee, rather
> than deferring that until ASTContext::isParamDestroyedInCallee? If this
> is going to be an ABI-dependent flag anyway (because it depends on
> CanPassInRegisters, which is ABI-dependent), it would make some sense for
> it to always reflect the ABI's rule.
>
>
> I think I ran into problems when I tried to take into account what
> 'TargetCXXABI::areArgsDestroyedLeftToRightInCallee()’  returns to set
> ParamDestroyedInCallee and use the flag in IRGen instead of calling
> ASTContext::isParamDestroyedInCallee. There were a few ObjC test cases
> that started failing, if I remember correctly. But I think we should always
> set the correct value to RecordDecl::ParamDestroyedInCallee taking into
> account what TargetCXXABI::areArgsDestroyedLeftToRightInCallee() returns,
> even though we still have to call ASTContext::isParamDestroyedInCallee.
>
>
> It turns out some of the microsoft CodeGen tests were failing because I
> wasn’t setting Record::ParamDestroyedInCallee when the RecordDecl didn’t
> have a non-trivial destructor. RecordDecl::ParamDestroyedInCallee has to
> be set to true when TargetCXXABI::areArgsDestroyedLeftToRightInCallee()
> returns true, regardless of whether the struct has a destructor.
>
> The static function canPassInRegisters computes whether the record can be
>>>> passed in registers depending on which of the three ABIs
>>>> (clang-abi-compat=4.0, 64-bit microsoft, and Itanium C++ ABI) we are using.
>>>> The function returns the correct answer except when ARC is enabled and the
>>>> record has a __weak field, which is why CXXRecordDecl::canPassInRegisters()
>>>> has to be called too to check the presence of __weak fields when computing
>>>> the value for flag RecordDecl::CanPassInRegisters.  I discovered there
>>>> is a bug which causes a struct containing another struct with __weak fields
>>>> to be passed directly, but I think that can be fixed in a separate patch.
>>>>
>>>> Sema::CheckCompletedCXXClass also computes the value for flag
>>>> RecordDecl::ParamDestroyedInCallee (note that this flag is meaningless
>>>> when Microsoft ABI is used). This is how it works when a struct has __weak
>>>> or __strong fields:
>>>>
>>>> 1. In CXXRecordDecl::addedMember, pretend that __weak or __strong
>>>> fields do not make special functions non-trivial for the purpose of calls.
>>>> 2. If canPassInRegisters returns true, use the C ABI to pass the
>>>> record, which destructs records in the callee and passes records with
>>>> __weak fields indirectly (records having __strong fields but no __weak
>>>> fields are not forced to be passed indirectly). If it returns false, use
>>>> the C++ ABI, which destructs the record in the caller and passes it
>>>> indirectly.
>>>> 3. Since we cannot count on canPassInRegisters to tell whether a record
>>>> can be passed directly in the presence of a __weak field,
>>>> CXXRecordDecl::addedMember calls setCanPassInRegisters(false) so that we
>>>> know the record cannot be passed directly.
>>>>
>>>> hasTrivialABIOverride (which computes "canPassInRegisters() &&
>>>> hasNonTrivialDestructor()") used to determine whether a struct is
>>>> destructed in the callee, but the function can no longer be used since
>>>> structs with __weak fields are always passed indirectly.
>>>>
>>>> Please can you fix these names?
>>>>
>>>>
>>>>>  /// 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/Seria
>>>>> lization/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/Seria
>>>>> lization/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/Seria
>>>>> lization/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/Code
>>>>> GenCXX/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@@Y
>>>>> AXXZ"()
>>>>>  // 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/Code
>>>>> GenObjCXX/arc-special-member-functions.mm?rev=328731&r1=3287
>>>>> 30&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/Code
>>>>> GenObjCXX/objc-struct-cxx-abi.mm?p2=cfe/trunk/test/CodeGenOb
>>>>> jCXX/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 @_Z21testParamWeakTemplate1SIU
>>>>> 6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
>>>>> +// CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev(
>>>>> +// CHECK-NEXT: ret void
>>>>> +
>>>>> +void testParamWeakTemplate(S<__weak id> a) {
>>>>> +}
>>>>> +
>>>>> +// CHECK: define void @_Z27testParamContainsNonTrivi
>>>>> al18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
>>>>>  // CHECK-NOT: call
>>>>>  // CHECK: ret void
>>>>>
>>>>> -void testParamWeakTemplate(S<__weak id> a) {
>>>>> +void testParamContainsNonTrivial(ContainsNonTrivial a) {
>>>>> +}
>>>>> +
>>>>> +// CHECK: define void @_Z26testCallContainsNonTrivia
>>>>> lP18ContainsNonTrivial(
>>>>> +// CHECK: call void @_Z27testParamContainsNonTrivi
>>>>> al18ContainsNonTrivial(%[[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/Code
>>>>> GenObjCXX/property-dot-copy-elision.mm?rev=328731&r1=328730&
>>>>> r2=328731&view=diff
>>>>> ============================================================
>>>>> ==================
>>>>> --- cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm (o
>>>>> riginal)
>>>>> +++ 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/Code
>>>>> GenObjCXX/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 @_Z20testReturnStrongWeakP10St
>>>>> rongWeak(%[[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 @_Z21testParamWeakTemplate1SIU
>>>>> 6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
>>>>> -// CHECK-NOT: call
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -void testParamWeakTemplate(S<__weak id> a) {
>>>>> -}
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> cfe-commits mailing list
>>>>> cfe-commits at lists.llvm.org
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180425/705f7f96/attachment-0001.html>


More information about the cfe-commits mailing list