ahatanak created this revision.
ahatanak added reviewers: rjmccall, doug.gregor, rsmith.

r326307 and r327870 made changes that enable __strong and __weak fields to be 
declared in C structs. This patch changes the ObjC++ ABI so that structs with 
__strong or __weak pointers can be passed to or returned from functions 
compiled in C mode.

ObjC and ObjC++ are currently incompatible because of the differences in the 
way structs are passed and destructed.

For example:

  typedef struct {
    id f0;
    __weak id f1;
  } S;
  
  // this code is compiled in c++.
  extern ā€œCā€ {
    void foo(S s);
  }
  
  void caller(S a) {
    foo(a); // clang currently passes 'a' indirectly and the caller destructs 
'a'.
  }
  
  // this function is compiled in c.
  void foo(S a) {  // 'a' is passed directly and is destructed in the callee.
  }

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 make 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


Repository:
  rC Clang

https://reviews.llvm.org/D44908

Files:
  include/clang/AST/Decl.h
  include/clang/AST/DeclCXX.h
  include/clang/AST/Type.h
  lib/AST/ASTContext.cpp
  lib/AST/Decl.cpp
  lib/AST/DeclCXX.cpp
  lib/AST/Type.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclCXX.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  lib/Serialization/ASTWriterDecl.cpp
  test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
  test/CodeGenObjCXX/arc-special-member-functions.mm
  test/CodeGenObjCXX/objc-struct-cxx-abi.mm
  test/CodeGenObjCXX/property-dot-copy-elision.mm
  test/CodeGenObjCXX/trivial_abi.mm

Index: test/CodeGenObjCXX/property-dot-copy-elision.mm
===================================================================
--- test/CodeGenObjCXX/property-dot-copy-elision.mm
+++ test/CodeGenObjCXX/property-dot-copy-elision.mm
@@ -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;
 };
Index: test/CodeGenObjCXX/objc-struct-cxx-abi.mm
===================================================================
--- test/CodeGenObjCXX/objc-struct-cxx-abi.mm
+++ test/CodeGenObjCXX/objc-struct-cxx-abi.mm
@@ -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 @@
 // 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 @@
 }
 
 // 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);
 }
Index: test/CodeGenObjCXX/arc-special-member-functions.mm
===================================================================
--- test/CodeGenObjCXX/arc-special-member-functions.mm
+++ test/CodeGenObjCXX/arc-special-member-functions.mm
@@ -31,6 +31,8 @@
 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_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,14 +83,17 @@
 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
 }
 
 // CHECK-LABEL: define void @_Z32test_ObjCBlockMember_copy_assign15ObjCBlockMemberS_
 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
 }
 
Index: test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
+++ test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
@@ -172,12 +172,9 @@
 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@XZ"
 // WIN64:   call void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %{{.*}})
-// WIN64:   call void @"??1SmallWithDtor@@QEAA@XZ"
 // WIN64:   ret void
 
 // Test that references aren't destroyed in the callee.
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -469,6 +469,7 @@
   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() &&
@@ -1911,6 +1912,8 @@
   // 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
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5194,6 +5194,7 @@
         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)));
@@ -6021,6 +6022,7 @@
   Record->push_back(Data.HasIrrelevantDestructor);
   Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
   Record->push_back(Data.HasDefaultedDefaultConstructor);
+  Record->push_back(Data.ForcePassIndirectly);
   Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
   Record->push_back(Data.HasConstexprDefaultConstructor);
   Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -743,6 +743,7 @@
   RD->setNonTrivialToPrimitiveCopy(Record.readInt());
   RD->setNonTrivialToPrimitiveDestroy(Record.readInt());
   RD->setCanPassInRegisters(Record.readInt());
+  RD->setParamDestroyedInCallee(Record.readInt());
   return Redecl;
 }
 
@@ -1588,6 +1589,7 @@
   Data.HasIrrelevantDestructor = Record.readInt();
   Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
   Data.HasDefaultedDefaultConstructor = Record.readInt();
+  Data.ForcePassIndirectly = Record.readInt();
   Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
   Data.HasConstexprDefaultConstructor = Record.readInt();
   Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
@@ -1727,6 +1729,7 @@
   MATCH_FIELD(HasIrrelevantDestructor)
   OR_FIELD(HasConstexprNonCopyMoveConstructor)
   OR_FIELD(HasDefaultedDefaultConstructor)
+  MATCH_FIELD(ForcePassIndirectly)
   MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
   OR_FIELD(HasConstexprDefaultConstructor)
   MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
@@ -4109,6 +4112,7 @@
           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.
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -5791,9 +5791,11 @@
   }
 }
 
-/// 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) {
   if (D->isDependentType() || D->isInvalidDecl())
     return false;
 
@@ -6001,7 +6003,13 @@
 
   checkClassLevelDLLAttribute(Record);
 
-  Record->setCanPassInRegisters(computeCanPassInRegisters(*this, Record));
+  bool DestroyedInCallee = paramCanBeDestroyedInCallee(*this, Record);
+
+  if (Record->hasNonTrivialDestructor())
+    Record->setParamDestroyedInCallee(DestroyedInCallee);
+
+  Record->setCanPassInRegisters(DestroyedInCallee &&
+                                !Record->forcePassIndirectly());
 }
 
 /// Look up the special member function that would be called by a special
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -15450,8 +15450,10 @@
       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);
     }
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -827,6 +827,9 @@
     return RAA_Default;
 
   case llvm::Triple::x86_64:
+    if (RD->forcePassIndirectly())
+      return RAA_Indirect;
+
     bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false;
     bool DtorIsTrivialForCall = false;
 
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -69,7 +69,8 @@
             CodeGenOptions::ClangABI::Ver4 ||
         CGM.getTriple().getOS() == llvm::Triple::PS4)
       return RD->hasNonTrivialDestructorForCall() ||
-             RD->hasNonTrivialCopyConstructorForCall();
+             RD->hasNonTrivialCopyConstructorForCall() ||
+             RD->forcePassIndirectly();
     return !canCopyArgument(RD);
   }
 
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3540,24 +3540,13 @@
     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.
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2195,12 +2195,6 @@
   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 &&
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -92,7 +92,7 @@
       DeclaredNonTrivialSpecialMembers(0),
       DeclaredNonTrivialSpecialMembersForCall(0), HasIrrelevantDestructor(true),
       HasConstexprNonCopyMoveConstructor(false),
-      HasDefaultedDefaultConstructor(false),
+      HasDefaultedDefaultConstructor(false), ForcePassIndirectly(false),
       DefaultedDefaultConstructorIsConstexpr(true),
       HasConstexprDefaultConstructor(false),
       HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -801,7 +801,17 @@
         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)
+          setForcePassIndirectly(true);
+
         Data.HasIrrelevantDestructor = false;
       } else if (!Context.getLangOpts().ObjCAutoRefCount) {
         setHasObjectMember(true);
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3932,7 +3932,7 @@
       LoadedFieldsFromExternalStorage(false),
       NonTrivialToPrimitiveDefaultInitialize(false),
       NonTrivialToPrimitiveCopy(false), NonTrivialToPrimitiveDestroy(false),
-      CanPassInRegisters(true) {
+      CanPassInRegisters(true), ParamDestroyedInCallee(false) {
   assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
 }
 
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -2643,9 +2643,11 @@
 }
 
 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
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -808,11 +808,6 @@
   /// 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.
 
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -467,6 +467,12 @@
     /// constructor.
     unsigned HasDefaultedDefaultConstructor : 1;
 
+    /// Indicates that this class has a non-trivial primitive type (e.g., ObjC
+    /// __weak pointer) that forces the class to be passed indirectly. This flag
+    /// is used in CodeGen only when Microsoft ABI is used or clang ABI version
+    /// is 4.0 or older.
+    unsigned ForcePassIndirectly : 1;
+
     /// \brief True if a defaulted default constructor for this class would
     /// be constexpr.
     unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -1468,11 +1474,12 @@
     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();
+  bool forcePassIndirectly() const {
+    return data().ForcePassIndirectly;
+  }
+
+  void setForcePassIndirectly(bool Force) {
+    data().ForcePassIndirectly = Force;
   }
 
   /// \brief Determine whether this class has a non-literal or/ volatile type
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3559,6 +3559,11 @@
   /// 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 @@
     CanPassInRegisters = CanPass;
   }
 
+  bool isParamDestroyedInCallee() const {
+    return ParamDestroyedInCallee;
+  }
+
+  void setParamDestroyedInCallee(bool V) {
+    ParamDestroyedInCallee = V;
+  }
+
   /// \brief Determines whether this declaration represents the
   /// injected class name.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to