ahatanak updated this revision to Diff 128642.
ahatanak added a comment.
I've only fixed the places where the bits to track the triviality of special
functions are set or reset, so this is still a WIP. I'll update the patch again
later today, but let me know if anyone has any feedback in the meantime.
A couple of comments and questions about this patch:
- CXXRecordDecl and FunctionDecl still have the flags that keep track of the
triviality of special functions for calls. I don't think we can avoid using
them even under the new simpler rules? I also had to add
"DeclaredNonTrivialSpecialMembersForCall" since
ItaniumCXXABI::passClassIndirect needs to know whether a struct has a
non-trivial destructor or copy constructor (I plan to make changes to
passClassIndirect later so that hasNonTrivial*ForCalls methods are called
there).
- If a struct annotated with "trivial_abi" turns out to be ill-formed (because
it has virtual bases, virtual functions, or __weak pointers), the attribute is
dropped after all the members explicitly declared in the struct are seen. The
triviality bits for user-provided special functions are set or reset only after
we know whether "trivial_abi" has to be dropped or not. Currently, a diagnostic
is printed if the struct becomes ill-formed because of the attribute, but it is
possible to make changes to suppress them or make them more user-friendly.
https://reviews.llvm.org/D41039
Files:
include/clang/AST/Decl.h
include/clang/AST/DeclCXX.h
include/clang/AST/Type.h
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/AST/DeclCXX.cpp
lib/AST/Type.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaType.cpp
test/CodeGenCXX/trivial_abi.cpp
test/Misc/pragma-attribute-supported-attributes-list.test
test/SemaObjCXX/attr-trivial-abi.mm
Index: test/SemaObjCXX/attr-trivial-abi.mm
===================================================================
--- /dev/null
+++ test/SemaObjCXX/attr-trivial-abi.mm
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c++11 -fobjc-runtime-has-weak -fobjc-weak -fobjc-arc -fsyntax-only -verify %s
+
+void __attribute__((trivial_abi)) foo(); // expected-warning {{'trivial_abi' attribute only applies to classes}}
+
+struct [[clang::trivial_abi]] S0 {
+ int a;
+};
+
+struct __attribute__((trivial_abi)) S1 {
+ int a;
+};
+
+struct __attribute__((trivial_abi)) S2 { // expected-warning {{'trivial_abi' cannot be applied to 'S2'}}
+ __weak id a;
+};
+
+struct __attribute__((trivial_abi)) S3 { // expected-warning {{'trivial_abi' cannot be applied to 'S3'}}
+ virtual void m();
+};
+
+struct S4 {
+ int a;
+};
+
+struct __attribute__((trivial_abi)) S5 : public virtual S4 { // expected-warning {{'trivial_abi' cannot be applied to 'S5'}}
+};
+
+struct __attribute__((trivial_abi)) S9 : public S4 {
+};
+
+struct S6 {
+ __weak id a;
+};
+
+struct __attribute__((trivial_abi)) S7 { // expected-warning {{'trivial_abi' cannot be applied to 'S7'}}
+ S6 a;
+};
+
+struct __attribute__((trivial_abi(1))) S8 { // expected-error {{'trivial_abi' attribute takes no arguments}}
+ int a;
+};
+
+template<class T>
+struct __attribute__((trivial_abi)) S10 {
+ T p;
+};
+
+S10<int *> p1;
+
+// Do not warn when 'trivial_abi' is used to annotate a template class.
+S10<__weak id> p2;
Index: test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- test/Misc/pragma-attribute-supported-attributes-list.test
+++ test/Misc/pragma-attribute-supported-attributes-list.test
@@ -2,7 +2,7 @@
// The number of supported attributes should never go down!
-// CHECK: #pragma clang attribute supports 66 attributes:
+// CHECK: #pragma clang attribute supports 67 attributes:
// CHECK-NEXT: AMDGPUFlatWorkGroupSize (SubjectMatchRule_function)
// CHECK-NEXT: AMDGPUNumSGPR (SubjectMatchRule_function)
// CHECK-NEXT: AMDGPUNumVGPR (SubjectMatchRule_function)
@@ -66,6 +66,7 @@
// CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
// CHECK-NEXT: Target (SubjectMatchRule_function)
// CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: TrivialABI (SubjectMatchRule_record)
// CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType)
// CHECK-NEXT: XRayInstrument (SubjectMatchRule_function, SubjectMatchRule_objc_method)
// CHECK-NEXT: XRayLogArgs (SubjectMatchRule_function, SubjectMatchRule_objc_method)
Index: test/CodeGenCXX/trivial_abi.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/trivial_abi.cpp
@@ -0,0 +1,196 @@
+// RUN: %clang_cc1 -triple arm64-apple-ios11 -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+// CHECK: %[[STRUCT_SMALL:.*]] = type { i32* }
+// CHECK: %[[STRUCT_LARGE:.*]] = type { i32*, [128 x i32] }
+// CHECK: %[[STRUCT_TRIVIAL:.*]] = type { i32 }
+// CHECK: %[[STRUCT_NONTRIVIAL:.*]] = type { i32 }
+
+struct __attribute__((trivial_abi)) Small {
+ int *p;
+ Small();
+ ~Small();
+ Small(const Small &);
+ Small &operator=(const Small &);
+};
+
+struct __attribute__((trivial_abi)) Large {
+ int *p;
+ int a[128];
+ Large();
+ ~Large();
+ Large(const Large &);
+ Large &operator=(const Large &);
+};
+
+struct Trivial {
+ int a;
+};
+
+struct NonTrivial {
+ NonTrivial();
+ ~NonTrivial();
+ int a;
+};
+
+struct HasTrivial {
+ Small s;
+ Trivial m;
+};
+
+struct HasNonTrivial {
+ Small s;
+ NonTrivial m;
+};
+
+// CHECK: define void @_Z14testParamSmall5Small(i64 %[[A_COERCE:.*]])
+// CHECK: %[[A:.*]] = alloca %[[STRUCT_SMALL]], align 8
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[A]], i32 0, i32 0
+// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[A_COERCE]] to i32*
+// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[A]])
+// CHECK: ret void
+// CHECK: }
+
+void testParamSmall(Small a) {
+}
+
+// CHECK: define i64 @_Z15testReturnSmallv()
+// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[RETVAL]])
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[RETVAL]], i32 0, i32 0
+// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8
+// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
+// CHECK: ret i64 %[[COERCE_VAL_PI]]
+// CHECK: }
+
+Small testReturnSmall() {
+ Small t;
+ return t;
+}
+
+// CHECK: define void @_Z14testCallSmall0v()
+// CHECK: %[[T:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL]], align 8
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1Ev(%[[STRUCT_SMALL]]* %[[T]])
+// CHECK: %[[CALL1:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallC1ERKS_(%[[STRUCT_SMALL]]* %[[AGG_TMP]], %[[STRUCT_SMALL]]* dereferenceable(8) %[[T]])
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE]], align 8
+// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
+// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
+// CHECK: %[[CALL2:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[T]])
+// CHECK: ret void
+// CHECK: }
+
+void testCallSmall0() {
+ Small t;
+ testParamSmall(t);
+}
+
+// CHECK: define void @_Z14testCallSmall1v()
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
+// CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
+// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
+// CHECK: %[[COERCE_DIVE1:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP]], i32 0, i32 0
+// CHECK: %[[V0:.*]] = load i32*, i32** %[[COERCE_DIVE1]], align 8
+// CHECK: %[[COERCE_VAL_PI:.*]] = ptrtoint i32* %[[V0]] to i64
+// CHECK: call void @_Z14testParamSmall5Small(i64 %[[COERCE_VAL_PI]])
+// CHECK: ret void
+// CHECK: }
+
+void testCallSmall1() {
+ testParamSmall(testReturnSmall());
+}
+
+// CHECK: define void @_Z16testIgnoredSmallv()
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_SMALL:.*]], align 8
+// CHECK: %[[CALL:.*]] = call i64 @_Z15testReturnSmallv()
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_SMALL]], %[[STRUCT_SMALL]]* %[[AGG_TMP_ENSURED]], i32 0, i32 0
+// CHECK: %[[COERCE_VAL_IP:.*]] = inttoptr i64 %[[CALL]] to i32*
+// CHECK: store i32* %[[COERCE_VAL_IP]], i32** %[[COERCE_DIVE]], align 8
+// CHECK: %[[CALL1:.*]] = call %[[STRUCT_SMALL]]* @_ZN5SmallD1Ev(%[[STRUCT_SMALL]]* %[[AGG_TMP_ENSURED]])
+// CHECK: ret void
+// CHECK: }
+
+void testIgnoredSmall() {
+ testReturnSmall();
+}
+
+// CHECK: define void @_Z14testParamLarge5Large(%[[STRUCT_LARGE:.*]]* %[[A:.*]])
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[A]])
+// CHECK: ret void
+// CHECK: }
+
+void testParamLarge(Large a) {
+}
+
+// CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret %[[AGG_RESULT:.*]])
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_RESULT]])
+// CHECK: ret void
+// CHECK: }
+
+Large testReturnLarge() {
+ Large t;
+ return t;
+}
+
+// CHECK: define void @_Z14testCallLarge0v()
+// CHECK: %[[T:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE]], align 8
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[T]])
+// CHECK: %[[CALL1:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1ERKS_(%[[STRUCT_LARGE]]* %[[AGG_TMP]], %[[STRUCT_LARGE]]* dereferenceable(520) %[[T]])
+// CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]])
+// CHECK: %[[CALL2:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[T]])
+// CHECK: ret void
+// CHECK: }
+
+void testCallLarge0() {
+ Large t;
+ testParamLarge(t);
+}
+
+// CHECK: define void @_Z14testCallLarge1v()
+// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
+// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP]])
+// CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]])
+// CHECK: ret void
+// CHECK: }
+
+void testCallLarge1() {
+ testParamLarge(testReturnLarge());
+}
+
+// CHECK: define void @_Z16testIgnoredLargev()
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8
+// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP_ENSURED]])
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP_ENSURED]])
+// CHECK: ret void
+// CHECK: }
+
+void testIgnoredLarge() {
+ testReturnLarge();
+}
+
+// CHECK: define i64 @_Z20testReturnHasTrivialv()
+// CHECK: %[[RETVAL:.*]] = alloca %[[STRUCT_TRIVIAL:.*]], align 4
+// CHECK: %[[COERCE_DIVE:.*]] = getelementptr inbounds %[[STRUCT_TRIVIAL]], %[[STRUCT_TRIVIAL]]* %[[RETVAL]], i32 0, i32 0
+// CHECK: %[[V0:.*]] = load i32, i32* %[[COERCE_DIVE]], align 4
+// CHECK: %[[COERCE_VAL_II:.*]] = zext i32 %[[V0]] to i64
+// CHECK: ret i64 %[[COERCE_VAL_II]]
+// CHECK: }
+
+Trivial testReturnHasTrivial() {
+ Trivial t;
+ return t;
+}
+
+// CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret %[[AGG_RESULT:.*]])
+// CHECK: %[[CALL:.*]] = call %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialC1Ev(%[[STRUCT_NONTRIVIAL]]* %[[AGG_RESULT]])
+// CHECK: ret void
+// CHECK: }
+
+NonTrivial testReturnHasNonTrivial() {
+ NonTrivial t;
+ return t;
+}
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -7790,7 +7790,7 @@
diag::note_non_literal_user_provided_dtor :
diag::note_non_literal_nontrivial_dtor) << RD;
if (!Dtor->isUserProvided())
- SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true);
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, false, /*Diagnose*/true);
}
return true;
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -5768,20 +5768,20 @@
if (D->needsImplicitCopyConstructor() &&
!D->defaultedCopyConstructorIsDeleted()) {
- if (!D->hasTrivialCopyConstructor())
+ if (!D->hasTrivialCopyConstructorForCall())
return false;
HasNonDeletedCopyOrMove = true;
}
if (S.getLangOpts().CPlusPlus11 && D->needsImplicitMoveConstructor() &&
!D->defaultedMoveConstructorIsDeleted()) {
- if (!D->hasTrivialMoveConstructor())
+ if (!D->hasTrivialMoveConstructorForCall())
return false;
HasNonDeletedCopyOrMove = true;
}
if (D->needsImplicitDestructor() && !D->defaultedDestructorIsDeleted() &&
- !D->hasTrivialDestructor())
+ !D->hasTrivialDestructorForCall())
return false;
for (const CXXMethodDecl *MD : D->methods()) {
@@ -5794,7 +5794,7 @@
else if (!isa<CXXDestructorDecl>(MD))
continue;
- if (!MD->isTrivial())
+ if (!MD->isTrivialForCall())
return false;
}
@@ -5878,6 +5878,13 @@
}
}
+ // Set HasTrivialSpecialMemberForCall if the record has attribute
+ // "trivial_abi".
+ bool HasTrivialABI = Record->hasAttr<TrivialABIAttr>();
+
+ if (HasTrivialABI)
+ Record->setHasTrivialSpecialMemberForCall();
+
bool HasMethodWithOverrideControl = false,
HasOverridingMethodWithoutOverrideControl = false;
if (!Record->isDependentType()) {
@@ -5900,12 +5907,21 @@
if (!M->isImplicit() && !M->isUserProvided()) {
if (CSM != CXXInvalid) {
M->setTrivial(SpecialMemberIsTrivial(M, CSM));
+ M->setTrivialForCall(SpecialMemberIsTrivial(M, CSM, true));
// Inform the class that we've finished declaring this member.
Record->finishedDefaultedOrDeletedMember(M);
}
}
+ // Set triviality for the purpose of calls if this is a user-provided
+ // copy/move constructor or destructor.
+ if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor ||
+ CSM == CXXDestructor) && M->isUserProvided()) {
+ M->setTrivialForCall(HasTrivialABI);
+ Record->finishedUserProvidedMethod(M);
+ }
+
if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() &&
M->hasAttr<DLLExportAttr>()) {
if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
@@ -7017,9 +7033,13 @@
///
/// If \p Selected is not \c NULL, \c *Selected will be filled in with the
/// member that was most likely to be intended to be trivial, if any.
+///
+/// If \p ForCall is true, look at CXXRecord::HasTrivialSpecialMembersForCall to
+/// determine whether the special member is trivial.
static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
Sema::CXXSpecialMember CSM, unsigned Quals,
- bool ConstRHS, CXXMethodDecl **Selected) {
+ bool ConstRHS, bool ForCall,
+ CXXMethodDecl **Selected) {
if (Selected)
*Selected = nullptr;
@@ -7060,7 +7080,8 @@
// C++11 [class.dtor]p5:
// A destructor is trivial if:
// - all the direct [subobjects] have trivial destructors
- if (RD->hasTrivialDestructor())
+ if (RD->hasTrivialDestructor() ||
+ (ForCall && RD->hasTrivialDestructorForCall()))
return true;
if (Selected) {
@@ -7075,7 +7096,8 @@
// C++11 [class.copy]p12:
// A copy constructor is trivial if:
// - the constructor selected to copy each direct [subobject] is trivial
- if (RD->hasTrivialCopyConstructor()) {
+ if (RD->hasTrivialCopyConstructor() ||
+ (ForCall && RD->hasTrivialCopyConstructorForCall())) {
if (Quals == Qualifiers::Const)
// We must either select the trivial copy constructor or reach an
// ambiguity; no need to actually perform overload resolution.
@@ -7128,6 +7150,10 @@
// not supposed to!
if (Selected)
*Selected = SMOR.getMethod();
+
+ if (ForCall &&
+ (CSM == Sema::CXXCopyConstructor || CSM == Sema::CXXMoveConstructor))
+ return SMOR.getMethod()->isTrivialForCall();
return SMOR.getMethod()->isTrivial();
}
@@ -7165,15 +7191,16 @@
static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
QualType SubType, bool ConstRHS,
Sema::CXXSpecialMember CSM,
- TrivialSubobjectKind Kind,
+ TrivialSubobjectKind Kind, bool ForCall,
bool Diagnose) {
CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl();
if (!SubRD)
return true;
CXXMethodDecl *Selected;
if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
- ConstRHS, Diagnose ? &Selected : nullptr))
+ ConstRHS, ForCall,
+ Diagnose ? &Selected : nullptr))
return true;
if (Diagnose) {
@@ -7203,7 +7230,7 @@
<< Kind << SubType.getUnqualifiedType() << CSM;
// Explain why the defaulted or deleted special member isn't trivial.
- S.SpecialMemberIsTrivial(Selected, CSM, Diagnose);
+ S.SpecialMemberIsTrivial(Selected, CSM, false, Diagnose);
}
}
@@ -7214,7 +7241,8 @@
/// trivial.
static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
Sema::CXXSpecialMember CSM,
- bool ConstArg, bool Diagnose) {
+ bool ConstArg, bool ForCall,
+ bool Diagnose) {
for (const auto *FI : RD->fields()) {
if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
continue;
@@ -7224,7 +7252,7 @@
// Pretend anonymous struct or union members are members of this class.
if (FI->isAnonymousStructOrUnion()) {
if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(),
- CSM, ConstArg, Diagnose))
+ CSM, ConstArg, ForCall, Diagnose))
return false;
continue;
}
@@ -7252,7 +7280,7 @@
bool ConstRHS = ConstArg && !FI->isMutable();
if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, ConstRHS,
- CSM, TSK_Field, Diagnose))
+ CSM, TSK_Field, ForCall, Diagnose))
return false;
}
@@ -7266,14 +7294,14 @@
bool ConstArg = (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment);
checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, ConstArg, CSM,
- TSK_CompleteObject, /*Diagnose*/true);
+ TSK_CompleteObject, false, /*Diagnose*/true);
}
/// Determine whether a defaulted or deleted special member function is trivial,
/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12,
/// C++11 [class.copy]p25, and C++11 [class.dtor]p5.
bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
- bool Diagnose) {
+ bool ForCall, bool Diagnose) {
assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough");
CXXRecordDecl *RD = MD->getParent();
@@ -7350,7 +7378,8 @@
// destructors]
for (const auto &BI : RD->bases())
if (!checkTrivialSubobjectCall(*this, BI.getLocStart(), BI.getType(),
- ConstArg, CSM, TSK_BaseClass, Diagnose))
+ ConstArg, CSM, TSK_BaseClass, ForCall,
+ Diagnose))
return false;
// C++11 [class.ctor]p5, C++11 [class.dtor]p5:
@@ -7365,7 +7394,7 @@
// -- for all of the non-static data members of its class that are of class
// type (or array thereof), each such class has a trivial [default
// constructor or destructor]
- if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose))
+ if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, ForCall, Diagnose))
return false;
// C++11 [class.dtor]p5:
@@ -7565,12 +7594,22 @@
l->getName();
}
+ // See if trivial_abi has to be dropped.
+ auto RD = dyn_cast_or_null<CXXRecordDecl>(TagDecl);
+ if (RD && RD->dropTrivialABI())
+ if (const auto *Attr = RD->getAttr<TrivialABIAttr>()) {
+ // Do not warn if this is a template instantiation.
+ if (!RD->getTemplateInstantiationPattern())
+ Diag(Attr->getLocation(), diag::warn_cannot_use_trivial_abi) << RD;
+ RD->dropAttr<TrivialABIAttr>();
+ }
+
ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
// strict aliasing violation!
reinterpret_cast<Decl**>(FieldCollector->getCurFields()),
FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList);
- CheckCompletedCXXClass(dyn_cast_or_null<CXXRecordDecl>(TagDecl));
+ CheckCompletedCXXClass(RD);
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -10720,6 +10759,7 @@
// We don't need to use SpecialMemberIsTrivial here; triviality for
// destructors is easy to compute.
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
+ Destructor->setTrivialForCall(ClassDecl->hasTrivialDestructorForCall());
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
@@ -12025,6 +12065,11 @@
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
: ClassDecl->hasTrivialCopyConstructor());
+ CopyConstructor->setTrivialForCall(
+ ClassDecl->needsOverloadResolutionForCopyConstructor()
+ ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor, true)
+ : ClassDecl->hasTrivialCopyConstructorForCall());
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
@@ -12148,6 +12193,11 @@
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
: ClassDecl->hasTrivialMoveConstructor());
+ MoveConstructor->setTrivialForCall(
+ ClassDecl->needsOverloadResolutionForMoveConstructor()
+ ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor, true)
+ : ClassDecl->hasTrivialMoveConstructorForCall());
+
// Note that we have declared this constructor.
++ASTContext::NumImplicitMoveConstructorsDeclared;
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -6436,6 +6436,9 @@
case AttributeList::AT_LayoutVersion:
handleLayoutVersion(S, D, Attr);
break;
+ case AttributeList::AT_TrivialABI:
+ handleSimpleAttribute<TrivialABIAttr>(S, D, Attr);
+ break;
case AttributeList::AT_MSNoVTable:
handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr);
break;
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -844,7 +844,7 @@
// If the copy ctor has not yet been declared, we can read its triviality
// off the AST.
if (!RD->defaultedCopyConstructorIsDeleted() &&
- RD->hasTrivialCopyConstructor())
+ RD->hasTrivialCopyConstructorForCall())
return RAA_Default;
} else {
// Otherwise, we need to find the copy constructor(s) and ask.
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -1140,6 +1140,14 @@
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
+
+ // If this is a C++ record passed using C ABI, the callee is responsible for
+ // destructing the argument that is passed.
+ if (Ty.destructInCallee()) {
+ AutoVarEmission Emission(*VD);
+ Emission.Addr = GetAddrOfLocalVar(VD);
+ EmitAutoVarCleanups(Emission);
+ }
}
// Emit a location at the end of the prologue.
if (CGDebugInfo *DI = getDebugInfo())
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3497,6 +3497,17 @@
bool HasAggregateEvalKind = hasAggregateEvaluationKind(type);
+ if (type.destructInCallee()) {
+ AggValueSlot Slot = CreateAggTemp(type, "agg.tmp");
+ // If this is a C++ record passed using C ABI, do not destruct the argument
+ // in the caller function.
+ Slot.setExternallyDestructed();
+ EmitAggExpr(E, Slot);
+ RValue RV = Slot.asRValue();
+ args.add(RV, type);
+ return;
+ }
+
// In the Microsoft C++ ABI, aggregate arguments are destructed by the callee.
// However, we still have to push an EH-only cleanup in case we unwind before
// we make it to the call.
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2201,6 +2201,12 @@
return false;
}
+bool QualType::destructInCallee() const {
+ if (const auto *RD = getTypePtr()->getAsCXXRecordDecl())
+ return RD->destructInCallee();
+ 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
@@ -88,10 +88,12 @@
DefaultedMoveConstructorIsDeleted(false),
DefaultedMoveAssignmentIsDeleted(false),
DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
- DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),
+ HasTrivialSpecialMembersForCall(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0),
+ DeclaredNonTrivialSpecialMembersForCall(0), HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
HasDefaultedDefaultConstructor(false),
- CanPassInRegisters(true),
+ CanPassInRegisters(true), DropTrivialABI(false),
DefaultedDefaultConstructorIsConstexpr(true),
HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
@@ -200,6 +202,11 @@
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ // Drop "trivial_abi" if this class is not trivial for the purpose of calls
+ // or has a virtual base.
+ if (!BaseClassDecl->canPassInRegisters() || Base->isVirtual())
+ setDropTrivialABI();
+
if (!BaseClassDecl->isEmpty()) {
if (!data().Empty) {
// C++0x [class]p7:
@@ -281,6 +288,7 @@
// operator for a class X] is trivial [...] if:
// -- class X has [...] no virtual base classes
data().HasTrivialSpecialMembers &= SMF_Destructor;
+ data().HasTrivialSpecialMembersForCall &= SMF_Destructor;
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
@@ -314,13 +322,20 @@
// subobject is trivial, and
if (!BaseClassDecl->hasTrivialCopyConstructor())
data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+
+ if (!BaseClassDecl->hasTrivialCopyConstructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_CopyConstructor;
+
// If the base class doesn't have a simple move constructor, we'll eagerly
// declare it and perform overload resolution to determine which function
// it actually calls. If it does have a simple move constructor, this
// check is correct.
if (!BaseClassDecl->hasTrivialMoveConstructor())
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
+ if (!BaseClassDecl->hasTrivialMoveConstructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_MoveConstructor;
+
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
// [...]
@@ -357,6 +372,9 @@
if (!BaseClassDecl->hasTrivialDestructor())
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
+ if (!BaseClassDecl->hasTrivialDestructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
+
if (!BaseClassDecl->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
@@ -539,6 +557,10 @@
// assignment operator for a class X] is trivial [...] if:
// -- class X has no virtual functions [...]
data().HasTrivialSpecialMembers &= SMF_Destructor;
+ data().HasTrivialSpecialMembersForCall &= SMF_Destructor;
+
+ // "trivial_abi" has to be dropped if this is a virtual function.
+ setDropTrivialABI();
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
@@ -623,8 +645,10 @@
// C++11 [class.dtor]p5:
// A destructor is trivial if [...] the destructor is not virtual.
- if (DD->isVirtual())
+ if (DD->isVirtual()) {
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
+ data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
+ }
}
// Handle member functions.
@@ -670,16 +694,27 @@
// If this is the first declaration of a special member, we no longer have
// an implicit trivial special member.
data().HasTrivialSpecialMembers &=
- data().DeclaredSpecialMembers | ~SMKind;
+ data().DeclaredSpecialMembers | ~SMKind;
+ data().HasTrivialSpecialMembersForCall &=
+ data().DeclaredSpecialMembers | ~SMKind;
if (!Method->isImplicit() && !Method->isUserProvided()) {
// This method is user-declared but not user-provided. We can't work out
// whether it's trivial yet (not until we get to the end of the class).
// We'll handle this method in finishedDefaultedOrDeletedMember.
- } else if (Method->isTrivial())
+ } else if (Method->isTrivial()) {
data().HasTrivialSpecialMembers |= SMKind;
- else
+ data().HasTrivialSpecialMembersForCall |= SMKind;
+ } else {
data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ // If this is a user-provided function, do not set
+ // DeclaredNonTrivialSpecialMembersForCall here since we don't know
+ // yet whether the method would be considered non-trivial for the
+ // purpose of calls (attribute "trivial_abi" can be dropped from the
+ // class later, which can change the special method's triviality).
+ if (!Method->isUserProvided())
+ data().DeclaredNonTrivialSpecialMembersForCall |= SMKind;
+ }
// Note when we have declared a declared special member, and suppress the
// implicit declaration of this special member.
@@ -772,6 +807,13 @@
struct DefinitionData &Data = data();
Data.PlainOldData = false;
Data.HasTrivialSpecialMembers = 0;
+ Data.HasTrivialSpecialMembersForCall = 0;
+
+ // If a struct has Objective-C weak pointer members, it cannot have
+ // attribute "trivial_abi".
+ if (T.getObjCLifetime() == Qualifiers::OCL_Weak)
+ setDropTrivialABI();
+
Data.HasIrrelevantDestructor = false;
} else if (!Context.getLangOpts().ObjCAutoRefCount) {
setHasObjectMember(true);
@@ -883,6 +925,11 @@
FieldRec->data().NeedOverloadResolutionForDestructor;
}
+ // If this field is of a type that is non-trivial for the purpose of
+ // calls, drop "trivial_abi".
+ if (!FieldRec->canPassInRegisters())
+ setDropTrivialABI();
+
// C++0x [class.ctor]p5:
// A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
@@ -899,12 +946,19 @@
// member is trivial;
if (!FieldRec->hasTrivialCopyConstructor())
data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+
+ if (!FieldRec->hasTrivialCopyConstructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_CopyConstructor;
+
// If the field doesn't have a simple move constructor, we'll eagerly
// declare the move constructor for this class and we'll decide whether
// it's trivial then.
if (!FieldRec->hasTrivialMoveConstructor())
data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
+ if (!FieldRec->hasTrivialMoveConstructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_MoveConstructor;
+
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
// [...]
@@ -921,6 +975,8 @@
if (!FieldRec->hasTrivialDestructor())
data().HasTrivialSpecialMembers &= ~SMF_Destructor;
+ if (!FieldRec->hasTrivialDestructorForCall())
+ data().HasTrivialSpecialMembersForCall &= ~SMF_Destructor;
if (!FieldRec->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
@@ -1103,6 +1159,23 @@
data().DeclaredNonTrivialSpecialMembers |= SMKind;
}
+void CXXRecordDecl::finishedUserProvidedMethod(CXXMethodDecl *D) {
+ unsigned SMKind = 0;
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (Constructor->isCopyConstructor())
+ SMKind = SMF_CopyConstructor;
+ else if (Constructor->isMoveConstructor())
+ SMKind = SMF_MoveConstructor;
+ } else if (isa<CXXDestructorDecl>(D))
+ SMKind = SMF_Destructor;
+
+ if (D->isTrivialForCall())
+ data().HasTrivialSpecialMembersForCall |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembersForCall |= SMKind;
+}
+
bool CXXRecordDecl::isCLike() const {
if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
!TemplateOrInstantiation.isNull())
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2236,7 +2236,7 @@
bool CheckNontrivialField(FieldDecl *FD);
void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM);
bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
- bool Diagnose = false);
+ bool ForCall = false, bool Diagnose = false);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
void ActOnLastBitfield(SourceLocation DeclStart,
SmallVectorImpl<Decl *> &AllIvarDecls);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2881,6 +2881,9 @@
def err_invalid_attribute_on_virtual_function : Error<
"%0 attribute cannot be applied to virtual functions">;
+def warn_cannot_use_trivial_abi : Warning<
+ "'trivial_abi' cannot be applied to %0">, InGroup<IgnoredAttributes>;
+
// Availability attribute
def warn_availability_unknown_platform : Warning<
"unknown platform %0 in availability macro">, InGroup<Availability>;
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -2224,6 +2224,44 @@
}];
}
+def TrivialABIDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``trivial_abi`` attribute can be applied to a C++ class, struct, or union.
+It instructs the compiler to pass and return the type using the C ABI for the
+underlying type, meaning that a type may be passed or returned directly even
+when the type is considered non-trivial for the purpose of calls according to
+the C++ ABI. Non-trivial destructors or copy/move constructors of classes
+annotated with ``trivial_abi`` do not cause the corresponding special functions
+of containing classes to be non-trivial for the purpose of calls. For example:
+
+ .. code-block:: c++
+
+ struct __attribute__((trivial_abi)) A {
+ ~A();
+ A(const A &);
+ A(A &&);
+ int x;
+ };
+
+ // B's destructor and copy/move constructor are considered trivial for the
+ // purpose of calls despite A's non-trivial special functions.
+ struct B {
+ A a;
+ };
+
+The destruction convention for arguments of ``trivial_abi`` types is that the
+callee is responsible for destroying the object regardless of how it is passed
+under the C ABI.
+
+Attribute ``trivial_abi`` will be dropped from a class in the following cases:
+
+- The class or its subobjects have virtual bases or virtual methods.
+- The class or its subobjects have Objective-C pointer type members and ARC is
+ enabled.
+ }];
+}
+
def MSInheritanceDocs : Documentation {
let Category = DocCatType;
let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance";
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1155,6 +1155,12 @@
let Documentation = [LayoutVersionDocs];
}
+def TrivialABI : InheritableAttr {
+ let Spellings = [Clang<"trivial_abi">];
+ let Subjects = SubjectList<[CXXRecord]>;
+ let Documentation = [TrivialABIDocs];
+}
+
def MaxFieldAlignment : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -808,6 +808,10 @@
/// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
bool isTriviallyCopyableType(const ASTContext &Context) const;
+ /// Determine whether this type should be destructed in the callee when passed
+ /// to a function.
+ bool destructInCallee() 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
@@ -437,14 +437,25 @@
/// which have been declared but not yet defined.
unsigned HasTrivialSpecialMembers : 6;
+ /// These bits keep track of the triviality of special functions for the
+ /// purpose of calls. Only the bits corresponding to SMF_CopyConstructor,
+ /// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+ unsigned HasTrivialSpecialMembersForCall : 6;
+
/// \brief The declared special members of this class which are known to be
/// non-trivial.
///
/// This excludes any user-declared but not user-provided special members
/// which have been declared but not yet defined, and any implicit special
/// members which have not yet been declared.
unsigned DeclaredNonTrivialSpecialMembers : 6;
+ /// These bits keep track of the declared special members that are
+ /// non-trivial for the purpose of calls.
+ /// Only the bits corresponding to SMF_CopyConstructor,
+ /// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+ unsigned DeclaredNonTrivialSpecialMembersForCall : 6;
+
/// \brief True when this class has a destructor with no semantic effect.
unsigned HasIrrelevantDestructor : 1;
@@ -462,6 +473,10 @@
/// pass an object of this class.
unsigned CanPassInRegisters : 1;
+ /// This indicate whether this class has a member that makes this class
+ /// ill-formed if it is annotated with "trivial_abi".
+ unsigned DropTrivialABI : 1;
+
/// \brief True if a defaulted default constructor for this class would
/// be constexpr.
unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -1349,28 +1364,49 @@
return data().HasTrivialSpecialMembers & SMF_CopyConstructor;
}
+ bool hasTrivialCopyConstructorForCall() const {
+ return data().HasTrivialSpecialMembersForCall & SMF_CopyConstructor;
+ }
+
/// \brief Determine whether this class has a non-trivial copy constructor
/// (C++ [class.copy]p6, C++11 [class.copy]p12)
bool hasNonTrivialCopyConstructor() const {
return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor ||
!hasTrivialCopyConstructor();
}
+ bool hasNonTrivialCopyConstructorForCall() const {
+ return data().DeclaredNonTrivialSpecialMembersForCall &
+ SMF_CopyConstructor || !hasTrivialCopyConstructorForCall();
+ }
+
/// \brief Determine whether this class has a trivial move constructor
/// (C++11 [class.copy]p12)
bool hasTrivialMoveConstructor() const {
return hasMoveConstructor() &&
(data().HasTrivialSpecialMembers & SMF_MoveConstructor);
}
+ bool hasTrivialMoveConstructorForCall() const {
+ return hasMoveConstructor() &&
+ (data().HasTrivialSpecialMembersForCall & SMF_MoveConstructor);
+ }
+
/// \brief Determine whether this class has a non-trivial move constructor
/// (C++11 [class.copy]p12)
bool hasNonTrivialMoveConstructor() const {
return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
(needsImplicitMoveConstructor() &&
!(data().HasTrivialSpecialMembers & SMF_MoveConstructor));
}
+ bool hasNonTrivialMoveConstructorForCall() const {
+ return (data().DeclaredNonTrivialSpecialMembersForCall &
+ SMF_MoveConstructor) ||
+ (needsImplicitMoveConstructor() &&
+ !(data().HasTrivialSpecialMembersForCall & SMF_MoveConstructor));
+ }
+
/// \brief Determine whether this class has a trivial copy assignment operator
/// (C++ [class.copy]p11, C++11 [class.copy]p25)
bool hasTrivialCopyAssignment() const {
@@ -1405,12 +1441,25 @@
return data().HasTrivialSpecialMembers & SMF_Destructor;
}
+ bool hasTrivialDestructorForCall() const {
+ return data().HasTrivialSpecialMembersForCall & SMF_Destructor;
+ }
+
/// \brief Determine whether this class has a non-trivial destructor
/// (C++ [class.dtor]p3)
bool hasNonTrivialDestructor() const {
return !(data().HasTrivialSpecialMembers & SMF_Destructor);
}
+ bool hasNonTrivialDestructorForCall() const {
+ return !(data().HasTrivialSpecialMembersForCall & SMF_Destructor);
+ }
+
+ void setHasTrivialSpecialMemberForCall() {
+ data().HasTrivialSpecialMembersForCall =
+ (SMF_CopyConstructor | SMF_MoveConstructor | SMF_Destructor);
+ }
+
/// \brief Determine whether declaring a const variable with this type is ok
/// per core issue 253.
bool allowConstDefaultInit() const {
@@ -1440,6 +1489,18 @@
data().CanPassInRegisters = CanPass;
}
+ bool dropTrivialABI() const {
+ return data().DropTrivialABI;
+ }
+
+ void setDropTrivialABI() {
+ data().DropTrivialABI = true;
+ }
+
+ bool destructInCallee() const {
+ return data().CanPassInRegisters && hasNonTrivialDestructor();
+ }
+
/// \brief Determine whether this class has a non-literal or/ volatile type
/// non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
@@ -1797,6 +1858,8 @@
/// member function is now complete.
void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD);
+ void finishedUserProvidedMethod(CXXMethodDecl *MD);
+
/// \brief Indicates that the definition of this class is now complete.
void completeDefinition() override;
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1732,6 +1732,12 @@
unsigned HasWrittenPrototype : 1;
unsigned IsDeleted : 1;
unsigned IsTrivial : 1; // sunk from CXXMethodDecl
+
+ /// This flag indicates whether this function is trivial for the purpose of
+ /// calls. This is meaningful only when this function is a copy/move
+ /// constructor or a destructor.
+ unsigned IsTrivialForCall : 1;
+
unsigned IsDefaulted : 1; // sunk from CXXMethoDecl
unsigned IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl
unsigned HasImplicitReturnZero : 1;
@@ -1842,7 +1848,8 @@
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
IsExplicitSpecified(false), IsVirtualAsWritten(false), IsPure(false),
HasInheritedPrototype(false), HasWrittenPrototype(true),
- IsDeleted(false), IsTrivial(false), IsDefaulted(false),
+ IsDeleted(false), IsTrivial(false), IsTrivialForCall(false),
+ IsDefaulted(false),
IsExplicitlyDefaulted(false), HasImplicitReturnZero(false),
IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified),
InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false),
@@ -2007,6 +2014,9 @@
bool isTrivial() const { return IsTrivial; }
void setTrivial(bool IT) { IsTrivial = IT; }
+ bool isTrivialForCall() const { return IsTrivialForCall; }
+ void setTrivialForCall(bool IT) { IsTrivialForCall = IT; }
+
/// Whether this function is defaulted per C++0x. Only valid for
/// special member functions.
bool isDefaulted() const { return IsDefaulted; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits