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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 4 14:15:52 PDT 2018


On 4 April 2018 at 11:57, Akira Hatanaka via cfe-commits <
cfe-commits at 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@
> 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(f
>>>> alse),
>>>> -      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).

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.

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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180404/7328c352/attachment-0001.html>


More information about the cfe-commits mailing list