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

Akira Hatanaka via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 10 14:57:34 PDT 2018



> 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 <mailto:richard at metafoo.co.uk>> wrote:
>> 
>> On 4 April 2018 at 11:57, Akira Hatanaka via cfe-commits <cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>> wrote:
>>> On Apr 4, 2018, at 10:55 AM, Richard Smith <richard at metafoo.co.uk <mailto:richard at metafoo.co.uk>> wrote:
>>> 
>>> On 3 April 2018 at 21:58, Akira Hatanaka via cfe-commits <cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>> wrote:
>>>> On Apr 3, 2018, at 7:56 PM, Richard Smith <richard at metafoo.co.uk <mailto:richard at metafoo.co.uk>> wrote:
>>>> 
>>>> On 3 April 2018 at 13:07, Akira Hatanaka via cfe-commits <cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>> wrote:
>>>> 
>>>> 
>>>>> On Apr 1, 2018, at 6:00 PM, Richard Smith <richard at metafoo.co.uk <mailto:richard at metafoo.co.uk>> wrote:
>>>>> 
>>>>> On 28 March 2018 at 14:13, Akira Hatanaka via cfe-commits <cfe-commits at lists.llvm.org <mailto: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 <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 <https://reviews.llvm.org/D41039?id=128767#inline-364710>
>>>>> 
>>>>> rdar://problem/38887866 <>
>>>>> 
>>>>> Differential Revision: https://reviews.llvm.org/D44908 <https://reviews.llvm.org/D44908>
>>>>> 
>>>>> Added:
>>>>>     cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm <http://objc-struct-cxx-abi.mm/>
>>>>>       - copied, changed from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://trivial_abi.mm/>
>>>>> Removed:
>>>>>     cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://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 <http://arc-special-member-functions.mm/>
>>>>>     cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm <http://property-dot-copy-elision.mm/>
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/AST/Decl.h
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/AST/Decl.h (original)
>>>>> +++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 28 14:13:14 2018
>>>>> @@ -3559,6 +3559,11 @@ class RecordDecl : public TagDecl {
>>>>>    /// pass an object of this class.
>>>>>    bool CanPassInRegisters : 1;
>>>>> 
>>>>> +  /// Indicates whether this struct is destroyed in the callee. This flag is
>>>>> +  /// meaningless when Microsoft ABI is used since parameters are always
>>>>> +  /// destroyed in the callee.
>>>>> +  bool ParamDestroyedInCallee : 1;
>>>>> +
>>>>>  protected:
>>>>>    RecordDecl(Kind DK, TagKind TK, const ASTContext &C, DeclContext *DC,
>>>>>               SourceLocation StartLoc, SourceLocation IdLoc,
>>>>> @@ -3654,6 +3659,14 @@ public:
>>>>>      CanPassInRegisters = CanPass;
>>>>>    }
>>>>> 
>>>>> +  bool isParamDestroyedInCallee() const {
>>>>> +    return ParamDestroyedInCallee;
>>>>> +  }
>>>>> +
>>>>> +  void setParamDestroyedInCallee(bool V) {
>>>>> +    ParamDestroyedInCallee = V;
>>>>> +  }
>>>>> +
>>>>>    /// \brief Determines whether this declaration represents the
>>>>>    /// injected class name.
>>>>>    ///
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>>>>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Mar 28 14:13:14 2018
>>>>> @@ -1468,13 +1468,6 @@ public:
>>>>>      return data().HasIrrelevantDestructor;
>>>>>    }
>>>>> 
>>>>> -  /// Determine whether the triviality for the purpose of calls for this class
>>>>> -  /// is overridden to be trivial because this class or the type of one of its
>>>>> -  /// subobjects has attribute "trivial_abi".
>>>>> -  bool hasTrivialABIOverride() const {
>>>>> -    return canPassInRegisters() && hasNonTrivialDestructor();
>>>>> -  }
>>>>> -
>>>>>    /// \brief Determine whether this class has a non-literal or/ volatile type
>>>>>    /// non-static data member or base class.
>>>>>    bool hasNonLiteralTypeFieldsOrBases() const {
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/AST/Type.h
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/AST/Type.h (original)
>>>>> +++ cfe/trunk/include/clang/AST/Type.h Wed Mar 28 14:13:14 2018
>>>>> @@ -808,11 +808,6 @@ public:
>>>>>    /// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
>>>>>    bool isTriviallyCopyableType(const ASTContext &Context) const;
>>>>> 
>>>>> -  /// Determine whether this is a class whose triviality for the purpose of
>>>>> -  /// calls is overridden to be trivial because the class or the type of one of
>>>>> -  /// its subobjects has attribute "trivial_abi".
>>>>> -  bool hasTrivialABIOverride() const;
>>>>> -
>>>>>    // Don't promise in the API that anything besides 'const' can be
>>>>>    // easily added.
>>>>> 
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/Basic/LangOptions.def
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/Basic/LangOptions.def (original)
>>>>> +++ cfe/trunk/include/clang/Basic/LangOptions.def Wed Mar 28 14:13:14 2018
>>>>> @@ -284,6 +284,10 @@ LANGOPT(XRayAlwaysEmitCustomEvents, 1, 0
>>>>>  BENIGN_LANGOPT(AllowEditorPlaceholders, 1, 0,
>>>>>                 "allow editor placeholders in source")
>>>>> 
>>>>> +ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest,
>>>>> +             "version of Clang that we should attempt to be ABI-compatible "
>>>>> +             "with")
>>>>> +
>>>>>  #undef LANGOPT
>>>>>  #undef COMPATIBLE_LANGOPT
>>>>>  #undef BENIGN_LANGOPT
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/Basic/LangOptions.h
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/Basic/LangOptions.h (original)
>>>>> +++ cfe/trunk/include/clang/Basic/LangOptions.h Wed Mar 28 14:13:14 2018
>>>>> @@ -102,6 +102,23 @@ public:
>>>>>      MSVC2015 = 19
>>>>>    };
>>>>> 
>>>>> +  /// Clang versions with different platform ABI conformance.
>>>>> +  enum class ClangABI {
>>>>> +    /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
>>>>> +    /// (SVN r257626). This causes <1 x long long> to be passed in an
>>>>> +    /// integer register instead of an SSE register on x64_64.
>>>>> +    Ver3_8,
>>>>> +
>>>>> +    /// Attempt to be ABI-compatible with code generated by Clang 4.0.x
>>>>> +    /// (SVN r291814). This causes move operations to be ignored when
>>>>> +    /// determining whether a class type can be passed or returned directly.
>>>>> +    Ver4,
>>>>> +
>>>>> +    /// Conform to the underlying platform's C and C++ ABIs as closely
>>>>> +    /// as we can.
>>>>> +    Latest
>>>>> +  };
>>>>> +
>>>>>    enum FPContractModeKind {
>>>>>      // Form fused FP ops only where result will not be affected.
>>>>>      FPC_Off,
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
>>>>> +++ cfe/trunk/include/clang/Basic/TargetInfo.h Wed Mar 28 14:13:14 2018
>>>>> @@ -1053,6 +1053,14 @@ public:
>>>>>      }
>>>>>    }
>>>>> 
>>>>> +  enum CallingConvKind {
>>>>> +    CCK_Default,
>>>>> +    CCK_ClangABI4OrPS4,
>>>>> +    CCK_MicrosoftX86_64
>>>>> +  };
>>>>> +
>>>>> +  virtual CallingConvKind getCallingConvKind(bool ClangABICompat4) const;
>>>>> +
>>>>>    /// Controls if __builtin_longjmp / __builtin_setjmp can be lowered to
>>>>>    /// llvm.eh.sjlj.longjmp / llvm.eh.sjlj.setjmp.
>>>>>    virtual bool hasSjLjLowering() const {
>>>>> 
>>>>> Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original)
>>>>> +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Wed Mar 28 14:13:14 2018
>>>>> @@ -138,9 +138,6 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjC
>>>>>  CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
>>>>>                                          ///< enabled.
>>>>> 
>>>>> -/// A version of Clang that we should attempt to be ABI-compatible with.
>>>>> -ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest)
>>>>> -
>>>>>  VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
>>>>>  VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
>>>>> 
>>>>> 
>>>>> Modified: cfe/trunk/lib/AST/ASTContext.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
>>>>> +++ cfe/trunk/lib/AST/ASTContext.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -2643,9 +2643,11 @@ void ASTContext::adjustExceptionSpec(
>>>>>  }
>>>>> 
>>>>>  bool ASTContext::isParamDestroyedInCallee(QualType T) const {
>>>>> -  return getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee() ||
>>>>> -         T.hasTrivialABIOverride() ||
>>>>> -         T.isDestructedType() == QualType::DK_nontrivial_c_struct;
>>>>> +  if (getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee())
>>>>> +    return true;
>>>>> +  if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
>>>>> +    return RT->getDecl()->isParamDestroyedInCallee();
>>>>> +  return false;
>>>>>  }
>>>>> 
>>>>>  /// getComplexType - Return the uniqued reference to the type for a complex
>>>>> 
>>>>> Modified: cfe/trunk/lib/AST/Decl.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/AST/Decl.cpp (original)
>>>>> +++ cfe/trunk/lib/AST/Decl.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -3951,7 +3951,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind
>>>>>        LoadedFieldsFromExternalStorage(false),
>>>>>        NonTrivialToPrimitiveDefaultInitialize(false),
>>>>>        NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false),
>>>>> -      CanPassInRegisters(true) {
>>>>> +      CanPassInRegisters(true), ParamDestroyedInCallee(false) {
>>>>>    assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
>>>>>  }
>>>>> 
>>>>> 
>>>>> Modified: cfe/trunk/lib/AST/DeclCXX.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/AST/DeclCXX.cpp (original)
>>>>> +++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -801,7 +801,17 @@ void CXXRecordDecl::addedMember(Decl *D)
>>>>>          struct DefinitionData &Data = data();
>>>>>          Data.PlainOldData = false;
>>>>>          Data.HasTrivialSpecialMembers = 0;
>>>>> -        Data.HasTrivialSpecialMembersForCall = 0;
>>>>> +
>>>>> +        // __strong or __weak fields do not make special functions non-trivial
>>>>> +        // for the purpose of calls.
>>>>> +        Qualifiers::ObjCLifetime LT = T.getQualifiers().getObjCLifetime();
>>>>> +        if (LT != Qualifiers::OCL_Strong && LT != Qualifiers::OCL_Weak)
>>>>> +          data().HasTrivialSpecialMembersForCall = 0;
>>>>> +
>>>>> +        // Structs with __weak fields should never be passed directly.
>>>>> +        if (LT == Qualifiers::OCL_Weak)
>>>>> +          setCanPassInRegisters(false);
>>>>> +
>>>>>          Data.HasIrrelevantDestructor = false;
>>>>>        } else if (!Context.getLangOpts().ObjCAutoRefCount) {
>>>>>          setHasObjectMember(true);
>>>>> 
>>>>> Modified: cfe/trunk/lib/AST/Type.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/AST/Type.cpp (original)
>>>>> +++ cfe/trunk/lib/AST/Type.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -2195,12 +2195,6 @@ bool QualType::isTriviallyCopyableType(c
>>>>>    return false;
>>>>>  }
>>>>> 
>>>>> -bool QualType::hasTrivialABIOverride() const {
>>>>> -  if (const auto *RD = getTypePtr()->getAsCXXRecordDecl())
>>>>> -    return RD->hasTrivialABIOverride();
>>>>> -  return false;
>>>>> -}
>>>>> -
>>>>>  bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const {
>>>>>    return !Context.getLangOpts().ObjCAutoRefCount &&
>>>>>           Context.getLangOpts().ObjCWeak &&
>>>>> 
>>>>> Modified: cfe/trunk/lib/Basic/TargetInfo.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff <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 <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Targets/X86.h?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/Basic/Targets/X86.h (original)
>>>>> +++ cfe/trunk/lib/Basic/Targets/X86.h Wed Mar 28 14:13:14 2018
>>>>> @@ -728,6 +728,11 @@ public:
>>>>>      Builder.defineMacro("_M_X64", "100");
>>>>>      Builder.defineMacro("_M_AMD64", "100");
>>>>>    }
>>>>> +
>>>>> +  TargetInfo::CallingConvKind
>>>>> +  getCallingConvKind(bool ClangABICompat4) const override {
>>>>> +    return CCK_MicrosoftX86_64;
>>>>> +  }
>>>>>  };
>>>>> 
>>>>>  // x86-64 MinGW target
>>>>> 
>>>>> Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
>>>>> +++ cfe/trunk/lib/CodeGen/CGCall.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -3540,24 +3540,13 @@ void CodeGenFunction::EmitCallArg(CallAr
>>>>>      else
>>>>>        Slot = CreateAggTemp(type, "agg.tmp");
>>>>> 
>>>>> -    bool DestroyedInCallee = true, NeedsEHCleanup = true;
>>>>> -    if (const auto *RD = type->getAsCXXRecordDecl()) {
>>>>> -      DestroyedInCallee =
>>>>> -          RD && RD->hasNonTrivialDestructor() &&
>>>>> -          (CGM.getCXXABI().getRecordArgABI(RD) != CGCXXABI::RAA_Default ||
>>>>> -           RD->hasTrivialABIOverride());
>>>>> -    } else {
>>>>> -      NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
>>>>> -    }
>>>>> -
>>>>> -    if (DestroyedInCallee)
>>>>> -      Slot.setExternallyDestructed();
>>>>> +    Slot.setExternallyDestructed();
>>>>> 
>>>>>      EmitAggExpr(E, Slot);
>>>>>      RValue RV = Slot.asRValue();
>>>>>      args.add(RV, type);
>>>>> 
>>>>> -    if (DestroyedInCallee && NeedsEHCleanup) {
>>>>> +    if (type->getAsCXXRecordDecl() || needsEHCleanup(type.isDestructedType())) {
>>>>>        // Create a no-op GEP between the placeholder and the cleanup so we can
>>>>>        // RAUW it successfully.  It also serves as a marker of the first
>>>>>        // instruction where the cleanup is active.
>>>>> 
>>>>> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
>>>>> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -63,13 +63,6 @@ public:
>>>>>    bool classifyReturnType(CGFunctionInfo &FI) const override;
>>>>> 
>>>>>    bool passClassIndirect(const CXXRecordDecl *RD) const {
>>>>> -    // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
>>>>> -    // The PS4 platform ABI follows the behavior of Clang 3.2.
>>>>> -    if (CGM.getCodeGenOpts().getClangABICompat() <=
>>>>> -            CodeGenOptions::ClangABI::Ver4 ||
>>>>> -        CGM.getTriple().getOS() == llvm::Triple::PS4)
>>>>> -      return RD->hasNonTrivialDestructorForCall() ||
>>>>> -             RD->hasNonTrivialCopyConstructorForCall();
>>>>>      return !canCopyArgument(RD);
>>>>>    }
>>>>> 
>>>>> 
>>>>> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
>>>>> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -829,60 +829,7 @@ MicrosoftCXXABI::getRecordArgABI(const C
>>>>>      return RAA_Default;
>>>>> 
>>>>>    case llvm::Triple::x86_64:
>>>>> -    bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
>>>>> -    bool DtorIsTrivialForCall = false;
>>>>> -
>>>>> -    // If a class has at least one non-deleted, trivial copy constructor, it
>>>>> -    // is passed according to the C ABI. Otherwise, it is passed indirectly.
>>>>> -    //
>>>>> -    // Note: This permits classes with non-trivial copy or move ctors to be
>>>>> -    // passed in registers, so long as they *also* have a trivial copy ctor,
>>>>> -    // which is non-conforming.
>>>>> -    if (RD->needsImplicitCopyConstructor()) {
>>>>> -      if (!RD->defaultedCopyConstructorIsDeleted()) {
>>>>> -        if (RD->hasTrivialCopyConstructor())
>>>>> -          CopyCtorIsTrivial = true;
>>>>> -        if (RD->hasTrivialCopyConstructorForCall())
>>>>> -          CopyCtorIsTrivialForCall = true;
>>>>> -      }
>>>>> -    } else {
>>>>> -      for (const CXXConstructorDecl *CD : RD->ctors()) {
>>>>> -        if (CD->isCopyConstructor() && !CD->isDeleted()) {
>>>>> -          if (CD->isTrivial())
>>>>> -            CopyCtorIsTrivial = true;
>>>>> -          if (CD->isTrivialForCall())
>>>>> -            CopyCtorIsTrivialForCall = true;
>>>>> -        }
>>>>> -      }
>>>>> -    }
>>>>> -
>>>>> -    if (RD->needsImplicitDestructor()) {
>>>>> -      if (!RD->defaultedDestructorIsDeleted() &&
>>>>> -          RD->hasTrivialDestructorForCall())
>>>>> -        DtorIsTrivialForCall = true;
>>>>> -    } else if (const auto *D = RD->getDestructor()) {
>>>>> -      if (!D->isDeleted() && D->isTrivialForCall())
>>>>> -        DtorIsTrivialForCall = true;
>>>>> -    }
>>>>> -
>>>>> -    // If the copy ctor and dtor are both trivial-for-calls, pass direct.
>>>>> -    if (CopyCtorIsTrivialForCall && DtorIsTrivialForCall)
>>>>> -      return RAA_Default;
>>>>> -
>>>>> -    // If a class has a destructor, we'd really like to pass it indirectly
>>>>> -    // because it allows us to elide copies.  Unfortunately, MSVC makes that
>>>>> -    // impossible for small types, which it will pass in a single register or
>>>>> -    // stack slot. Most objects with dtors are large-ish, so handle that early.
>>>>> -    // We can't call out all large objects as being indirect because there are
>>>>> -    // multiple x64 calling conventions and the C++ ABI code shouldn't dictate
>>>>> -    // how we pass large POD types.
>>>>> -
>>>>> -    // Note: This permits small classes with nontrivial destructors to be
>>>>> -    // passed in registers, which is non-conforming.
>>>>> -    if (CopyCtorIsTrivial &&
>>>>> -        getContext().getTypeSize(RD->getTypeForDecl()) <= 64)
>>>>> -      return RAA_Default;
>>>>> -    return RAA_Indirect;
>>>>> +    return !canCopyArgument(RD) ? RAA_Indirect : RAA_Default;
>>>>>    }
>>>>> 
>>>>>    llvm_unreachable("invalid enum");
>>>>> 
>>>>> Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
>>>>> +++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -2131,8 +2131,8 @@ class X86_64ABIInfo : public SwiftABIInf
>>>>>    /// classify it as INTEGER (for compatibility with older clang compilers).
>>>>>    bool classifyIntegerMMXAsSSE() const {
>>>>>      // Clang <= 3.8 did not do this.
>>>>> -    if (getCodeGenOpts().getClangABICompat() <=
>>>>> -        CodeGenOptions::ClangABI::Ver3_8)
>>>>> +    if (getContext().getLangOpts().getClangABICompat() <=
>>>>> +        LangOptions::ClangABI::Ver3_8)
>>>>>        return false;
>>>>> 
>>>>>      const llvm::Triple &Triple = getTarget().getTriple();
>>>>> 
>>>>> Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
>>>>> +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -633,33 +633,6 @@ static bool ParseCodeGenArgs(CodeGenOpti
>>>>>    if (!Opts.ProfileInstrumentUsePath.empty())
>>>>>      setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
>>>>> 
>>>>> -  if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
>>>>> -    Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
>>>>> -
>>>>> -    StringRef Ver = A->getValue();
>>>>> -    std::pair<StringRef, StringRef> VerParts = Ver.split('.');
>>>>> -    unsigned Major, Minor = 0;
>>>>> -
>>>>> -    // Check the version number is valid: either 3.x (0 <= x <= 9) or
>>>>> -    // y or y.0 (4 <= y <= current version).
>>>>> -    if (!VerParts.first.startswith("0") &&
>>>>> -        !VerParts.first.getAsInteger(10, Major) &&
>>>>> -        3 <= Major && Major <= CLANG_VERSION_MAJOR &&
>>>>> -        (Major == 3 ? VerParts.second.size() == 1 &&
>>>>> -                      !VerParts.second.getAsInteger(10, Minor)
>>>>> -                    : VerParts.first.size() == Ver.size() ||
>>>>> -                      VerParts.second == "0")) {
>>>>> -      // Got a valid version number.
>>>>> -      if (Major == 3 && Minor <= 8)
>>>>> -        Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver3_8);
>>>>> -      else if (Major <= 4)
>>>>> -        Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
>>>>> -    } else if (Ver != "latest") {
>>>>> -      Diags.Report(diag::err_drv_invalid_value)
>>>>> -          << A->getAsString(Args) << A->getValue();
>>>>> -    }
>>>>> -  }
>>>>> -
>>>>>    Opts.CoverageMapping =
>>>>>        Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
>>>>>    Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
>>>>> @@ -2670,6 +2643,33 @@ static void ParseLangArgs(LangOptions &O
>>>>> 
>>>>>    // -fallow-editor-placeholders
>>>>>    Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders);
>>>>> +
>>>>> +  if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
>>>>> +    Opts.setClangABICompat(LangOptions::ClangABI::Latest);
>>>>> +
>>>>> +    StringRef Ver = A->getValue();
>>>>> +    std::pair<StringRef, StringRef> VerParts = Ver.split('.');
>>>>> +    unsigned Major, Minor = 0;
>>>>> +
>>>>> +    // Check the version number is valid: either 3.x (0 <= x <= 9) or
>>>>> +    // y or y.0 (4 <= y <= current version).
>>>>> +    if (!VerParts.first.startswith("0") &&
>>>>> +        !VerParts.first.getAsInteger(10, Major) &&
>>>>> +        3 <= Major && Major <= CLANG_VERSION_MAJOR &&
>>>>> +        (Major == 3 ? VerParts.second.size() == 1 &&
>>>>> +                      !VerParts.second.getAsInteger(10, Minor)
>>>>> +                    : VerParts.first.size() == Ver.size() ||
>>>>> +                      VerParts.second == "0")) {
>>>>> +      // Got a valid version number.
>>>>> +      if (Major == 3 && Minor <= 8)
>>>>> +        Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
>>>>> +      else if (Major <= 4)
>>>>> +        Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
>>>>> +    } else if (Ver != "latest") {
>>>>> +      Diags.Report(diag::err_drv_invalid_value)
>>>>> +          << A->getAsString(Args) << A->getValue();
>>>>> +    }
>>>>> +  }
>>>>>  }
>>>>> 
>>>>>  static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
>>>>> 
>>>>> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff <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 <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 <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/Serialization/ASTReaderDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
>>>>> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -743,6 +743,7 @@ ASTDeclReader::VisitRecordDeclImpl(Recor
>>>>>    RD->setNonTrivialToPrimitiveCopy(Record.readInt());
>>>>>    RD->setNonTrivialToPrimitiveDestroy(Record.readInt());
>>>>>    RD->setCanPassInRegisters(Record.readInt());
>>>>> +  RD->setParamDestroyedInCallee(Record.readInt());
>>>>>    return Redecl;
>>>>>  }
>>>>> 
>>>>> @@ -4109,6 +4110,7 @@ void ASTDeclReader::UpdateDecl(Decl *D,
>>>>>            OldDD && (OldDD->Definition != RD ||
>>>>>                      !Reader.PendingFakeDefinitionData.count(OldDD));
>>>>>        RD->setCanPassInRegisters(Record.readInt());
>>>>> +      RD->setParamDestroyedInCallee(Record.readInt());
>>>>>        ReadCXXRecordDefinition(RD, /*Update*/true);
>>>>> 
>>>>>        // Visible update is handled separately.
>>>>> 
>>>>> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>>>>> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -5194,6 +5194,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(R
>>>>>          auto *RD = cast<CXXRecordDecl>(D);
>>>>>          UpdatedDeclContexts.insert(RD->getPrimaryContext());
>>>>>          Record.push_back(RD->canPassInRegisters());
>>>>> +        Record.push_back(RD->isParamDestroyedInCallee());
>>>>>          Record.AddCXXDefinitionData(RD);
>>>>>          Record.AddOffset(WriteDeclContextLexicalBlock(
>>>>>              *Context, const_cast<CXXRecordDecl *>(RD)));
>>>>> 
>>>>> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
>>>>> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -470,6 +470,7 @@ void ASTDeclWriter::VisitRecordDecl(Reco
>>>>>    Record.push_back(D->isNonTrivialToPrimitiveCopy());
>>>>>    Record.push_back(D->isNonTrivialToPrimitiveDestroy());
>>>>>    Record.push_back(D->canPassInRegisters());
>>>>> +  Record.push_back(D->isParamDestroyedInCallee());
>>>>> 
>>>>>    if (D->getDeclContext() == D->getLexicalDeclContext() &&
>>>>>        !D->hasAttrs() &&
>>>>> @@ -1912,6 +1913,8 @@ void ASTWriter::WriteDeclAbbrevs() {
>>>>>    // isNonTrivialToPrimitiveDestroy
>>>>>    Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
>>>>>    Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // canPassInRegisters
>>>>> +  // isParamDestroyedInCallee
>>>>> +  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1));
>>>>> 
>>>>>    // DC
>>>>>    Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));   // LexicalOffset
>>>>> 
>>>>> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp (original)
>>>>> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp Wed Mar 28 14:13:14 2018
>>>>> @@ -172,12 +172,9 @@ void small_arg_with_dtor(SmallWithDtor s
>>>>>  void call_small_arg_with_dtor() {
>>>>>    small_arg_with_dtor(SmallWithDtor());
>>>>>  }
>>>>> -// The temporary is copied, so it's destroyed in the caller as well as the
>>>>> -// callee.
>>>>>  // WIN64-LABEL: define dso_local void @"?call_small_arg_with_dtor@@YAXXZ"()
>>>>>  // WIN64:   call %struct.SmallWithDtor* @"??0SmallWithDtor@@QEAA at XZ"
>>>>>  // WIN64:   call void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %{{.*}})
>>>>> -// WIN64:   call void @"??1SmallWithDtor@@QEAA at XZ"
>>>>>  // WIN64:   ret void
>>>>> 
>>>>>  // Test that references aren't destroyed in the callee.
>>>>> 
>>>>> Modified: cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm <http://arc-special-member-functions.mm/>
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm <http://arc-special-member-functions.mm/> (original)
>>>>> +++ cfe/trunk/test/CodeGenObjCXX/arc-special-member-functions.mm <http://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 <http://objc-struct-cxx-abi.mm/> (from r328730, cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://trivial_abi.mm/>)
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm?p2=cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm&p1=cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm&r1=328730&r2=328731&rev=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm?p2=cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm&p1=cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm&r1=328730&r2=328731&rev=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://trivial_abi.mm/> (original)
>>>>> +++ cfe/trunk/test/CodeGenObjCXX/objc-struct-cxx-abi.mm <http://objc-struct-cxx-abi.mm/> Wed Mar 28 14:13:14 2018
>>>>> @@ -1,27 +1,60 @@
>>>>>  // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
>>>>>  // RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
>>>>> +// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
>>>>> +// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - -DTRIVIALABI %s | FileCheck %s
>>>>> +
>>>>> +// Check that structs consisting solely of __strong or __weak pointer fields are
>>>>> +// destructed in the callee function and structs consisting solely of __strong
>>>>> +// pointer fields are passed directly.
>>>>> 
>>>>>  // CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
>>>>>  // CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
>>>>>  // CHECK: %[[STRUCT_S:.*]] = type { i8* }
>>>>> +// CHECK: %[[STRUCT_CONTAINSNONTRIVIAL:.*]] = type { %{{.*}}, i8* }
>>>>> 
>>>>> +#ifdef TRIVIALABI
>>>>>  struct __attribute__((trivial_abi)) StrongWeak {
>>>>> +#else
>>>>> +struct StrongWeak {
>>>>> +#endif
>>>>>    id fstrong;
>>>>>    __weak id fweak;
>>>>>  };
>>>>> 
>>>>> +#ifdef TRIVIALABI
>>>>>  struct __attribute__((trivial_abi)) Strong {
>>>>> +#else
>>>>> +struct Strong {
>>>>> +#endif
>>>>>    id fstrong;
>>>>>  };
>>>>> 
>>>>>  template<class T>
>>>>> +#ifdef TRIVIALABI
>>>>>  struct __attribute__((trivial_abi)) S {
>>>>> +#else
>>>>> +struct S {
>>>>> +#endif
>>>>>    T a;
>>>>>  };
>>>>> 
>>>>> +struct NonTrivial {
>>>>> +  NonTrivial();
>>>>> +  NonTrivial(const NonTrivial &);
>>>>> +  ~NonTrivial();
>>>>> +  int *a;
>>>>> +};
>>>>> +
>>>>> +// This struct is not passed directly nor destructed in the callee because f0
>>>>> +// has type NonTrivial.
>>>>> +struct ContainsNonTrivial {
>>>>> +  NonTrivial f0;
>>>>> +  id f1;
>>>>> +};
>>>>> +
>>>>>  // CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
>>>>> -// CHECK-NOT: call
>>>>> -// CHECK: ret void
>>>>> +// CHECK: call %struct.StrongWeak* @_ZN10StrongWeakD1Ev(
>>>>> +// CHECK-NEXT: ret void
>>>>> 
>>>>>  void testParamStrongWeak(StrongWeak a) {
>>>>>  }
>>>>> @@ -33,7 +66,7 @@ void testParamStrongWeak(StrongWeak a) {
>>>>>  // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
>>>>>  // CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
>>>>>  // CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
>>>>> -// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
>>>>> +// CHECK-NOT: call
>>>>>  // CHECK: ret void
>>>>> 
>>>>>  void testCallStrongWeak(StrongWeak *a) {
>>>>> @@ -96,8 +129,23 @@ Strong testReturnStrong(Strong *a) {
>>>>>  }
>>>>> 
>>>>>  // CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
>>>>> +// CHECK: call %struct.S* @_ZN1SIU6__weakP11objc_objectED1Ev(
>>>>> +// CHECK-NEXT: ret void
>>>>> +
>>>>> +void testParamWeakTemplate(S<__weak id> a) {
>>>>> +}
>>>>> +
>>>>> +// CHECK: define void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
>>>>>  // CHECK-NOT: call
>>>>>  // CHECK: ret void
>>>>> 
>>>>> -void testParamWeakTemplate(S<__weak id> a) {
>>>>> +void testParamContainsNonTrivial(ContainsNonTrivial a) {
>>>>> +}
>>>>> +
>>>>> +// CHECK: define void @_Z26testCallContainsNonTrivialP18ContainsNonTrivial(
>>>>> +// CHECK: call void @_Z27testParamContainsNonTrivial18ContainsNonTrivial(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
>>>>> +// CHECK: call %struct.ContainsNonTrivial* @_ZN18ContainsNonTrivialD1Ev(%[[STRUCT_CONTAINSNONTRIVIAL]]* %{{.*}})
>>>>> +
>>>>> +void testCallContainsNonTrivial(ContainsNonTrivial *a) {
>>>>> +  testParamContainsNonTrivial(*a);
>>>>>  }
>>>>> 
>>>>> Modified: cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm <http://property-dot-copy-elision.mm/>
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm?rev=328731&r1=328730&r2=328731&view=diff <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm?rev=328731&r1=328730&r2=328731&view=diff>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm <http://property-dot-copy-elision.mm/> (original)
>>>>> +++ cfe/trunk/test/CodeGenObjCXX/property-dot-copy-elision.mm <http://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 <http://trivial_abi.mm/>
>>>>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm?rev=328730&view=auto <http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm?rev=328730&view=auto>
>>>>> ==============================================================================
>>>>> --- cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://trivial_abi.mm/> (original)
>>>>> +++ cfe/trunk/test/CodeGenObjCXX/trivial_abi.mm <http://trivial_abi.mm/> (removed)
>>>>> @@ -1,103 +0,0 @@
>>>>> -// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -emit-llvm -o - %s | FileCheck %s
>>>>> -// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -fobjc-arc  -fobjc-weak -fobjc-runtime-has-weak -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s
>>>>> -
>>>>> -// CHECK: %[[STRUCT_STRONGWEAK:.*]] = type { i8*, i8* }
>>>>> -// CHECK: %[[STRUCT_STRONG:.*]] = type { i8* }
>>>>> -// CHECK: %[[STRUCT_S:.*]] = type { i8* }
>>>>> -
>>>>> -struct __attribute__((trivial_abi)) StrongWeak {
>>>>> -  id fstrong;
>>>>> -  __weak id fweak;
>>>>> -};
>>>>> -
>>>>> -struct __attribute__((trivial_abi)) Strong {
>>>>> -  id fstrong;
>>>>> -};
>>>>> -
>>>>> -template<class T>
>>>>> -struct __attribute__((trivial_abi)) S {
>>>>> -  T a;
>>>>> -};
>>>>> -
>>>>> -// CHECK: define void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %{{.*}})
>>>>> -// CHECK-NOT: call
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -void testParamStrongWeak(StrongWeak a) {
>>>>> -}
>>>>> -
>>>>> -// CHECK: define void @_Z18testCallStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[A:.*]])
>>>>> -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
>>>>> -// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONGWEAK]], align 8
>>>>> -// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
>>>>> -// CHECK: call void @_Z19testParamStrongWeak10StrongWeak(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
>>>>> -// CHECK: %[[CALL1:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakD1Ev(%[[STRUCT_STRONGWEAK]]* %[[AGG_TMP]])
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -void testCallStrongWeak(StrongWeak *a) {
>>>>> -  testParamStrongWeak(*a);
>>>>> -}
>>>>> -
>>>>> -// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]])
>>>>> -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8
>>>>> -// CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONGWEAK]]* @_ZN10StrongWeakC1ERKS_(%[[STRUCT_STRONGWEAK]]* %[[AGG_RESULT]], %[[STRUCT_STRONGWEAK]]* dereferenceable(16) %[[V0]])
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -StrongWeak testReturnStrongWeak(StrongWeak *a) {
>>>>> -  return *a;
>>>>> -}
>>>>> -
>>>>> -// CHECK: define void @_Z15testParamStrong6Strong(i64 %[[A_COERCE:.*]])
>>>>> -// CHECK: %[[A:.*]] = alloca %[[STRUCT_STRONG]], align 8
>>>>> -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[A]], i32 0, i32 0
>>>>> -// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i8*
>>>>> -// CHECK: store i8* %[[COERCE_VAL_IP]], i8** %[[COERCE_DIVE]], align 8
>>>>> -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(%[[STRUCT_STRONG]]* %[[A]])
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -// CHECK: define linkonce_odr %[[STRUCT_STRONG]]* @_ZN6StrongD1Ev(
>>>>> -
>>>>> -void testParamStrong(Strong a) {
>>>>> -}
>>>>> -
>>>>> -// CHECK: define void @_Z14testCallStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
>>>>> -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
>>>>> -// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_STRONG]], align 8
>>>>> -// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[AGG_TMP]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
>>>>> -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[AGG_TMP]], i32 0, i32 0
>>>>> -// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
>>>>> -// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
>>>>> -// CHECK: call void @_Z15testParamStrong6Strong(i64 %[[COERCE_VAL_PI]])
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -void testCallStrong(Strong *a) {
>>>>> -  testParamStrong(*a);
>>>>> -}
>>>>> -
>>>>> -// CHECK: define i64 @_Z16testReturnStrongP6Strong(%[[STRUCT_STRONG]]* %[[A:.*]])
>>>>> -// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_STRONG]], align 8
>>>>> -// CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONG]]*, align 8
>>>>> -// CHECK: store %[[STRUCT_STRONG]]* %[[A]], %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONG]]*, %[[STRUCT_STRONG]]** %[[A_ADDR]], align 8
>>>>> -// CHECK: %[[CALL:.*]] = call %[[STRUCT_STRONG]]* @_ZN6StrongC1ERKS_(%[[STRUCT_STRONG]]* %[[RETVAL]], %[[STRUCT_STRONG]]* dereferenceable(8) %[[V0]])
>>>>> -// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_STRONG]], %[[STRUCT_STRONG]]* %[[RETVAL]], i32 0, i32 0
>>>>> -// CHECK: %[[V1:.*]] = load i8*, i8** %[[COERCE_DIVE]], align 8
>>>>> -// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i8* %[[V1]] to i64
>>>>> -// CHECK: ret i64 %[[COERCE_VAL_PI]]
>>>>> -
>>>>> -Strong testReturnStrong(Strong *a) {
>>>>> -  return *a;
>>>>> -}
>>>>> -
>>>>> -// CHECK: define void @_Z21testParamWeakTemplate1SIU6__weakP11objc_objectE(%[[STRUCT_S]]* %{{.*}})
>>>>> -// CHECK-NOT: call
>>>>> -// CHECK: ret void
>>>>> -
>>>>> -void testParamWeakTemplate(S<__weak id> a) {
>>>>> -}
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> cfe-commits mailing list
>>>>> cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits>
>>>> 
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits>
>>> 
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits>
>> 
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org <mailto:cfe-commits at lists.llvm.org>
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits <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/20180410/a23b03f9/attachment-0002.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: canpass2.patch
Type: application/octet-stream
Size: 13056 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180410/a23b03f9/attachment-0001.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180410/a23b03f9/attachment-0003.html>


More information about the cfe-commits mailing list