summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp2
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp160
2 files changed, 78 insertions, 84 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f8ab8a6b385..65d930c61d9 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11288,7 +11288,7 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
if (!ClassDecl->isInvalidDecl() &&
!ClassDecl->hasIrrelevantDestructor() &&
!ClassDecl->isDependentContext() &&
- Context.isParamDestroyedInCallee(Param->getType())) {
+ ClassDecl->isParamDestroyedInCallee()) {
CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
MarkFunctionReferenced(Param->getLocation(), Destructor);
DiagnoseUseOfDecl(Destructor, Param->getLocation());
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 102e7a50584..d5af147279a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5806,12 +5806,10 @@ static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
}
}
-/// 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) {
+/// Determine whether a type is permitted to be passed or returned in
+/// registers, per C++ [class.temporary]p3.
+static bool canPassInRegisters(Sema &S, CXXRecordDecl *D,
+ TargetInfo::CallingConvKind CCK) {
if (D->isDependentType() || D->isInvalidDecl())
return false;
@@ -5821,6 +5819,63 @@ static bool paramCanBeDestroyedInCallee(Sema &S, CXXRecordDecl *D,
return !D->hasNonTrivialDestructorForCall() &&
!D->hasNonTrivialCopyConstructorForCall();
+ if (CCK == TargetInfo::CCK_MicrosoftX86_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 (D->needsImplicitCopyConstructor()) {
+ if (!D->defaultedCopyConstructorIsDeleted()) {
+ if (D->hasTrivialCopyConstructor())
+ CopyCtorIsTrivial = true;
+ if (D->hasTrivialCopyConstructorForCall())
+ CopyCtorIsTrivialForCall = true;
+ }
+ } else {
+ for (const CXXConstructorDecl *CD : D->ctors()) {
+ if (CD->isCopyConstructor() && !CD->isDeleted()) {
+ if (CD->isTrivial())
+ CopyCtorIsTrivial = true;
+ if (CD->isTrivialForCall())
+ CopyCtorIsTrivialForCall = true;
+ }
+ }
+ }
+
+ if (D->needsImplicitDestructor()) {
+ if (!D->defaultedDestructorIsDeleted() &&
+ D->hasTrivialDestructorForCall())
+ DtorIsTrivialForCall = true;
+ } else if (const auto *DD = D->getDestructor()) {
+ if (!DD->isDeleted() && DD->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(D->getTypeForDecl()) <= 64)
+ return true;
+ return false;
+ }
+
// 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
@@ -5862,77 +5917,6 @@ static bool paramCanBeDestroyedInCallee(Sema &S, CXXRecordDecl *D,
return HasNonDeletedCopyOrMove;
}
-static RecordDecl::ArgPassingKind
-computeArgPassingRestrictions(bool DestroyedInCallee, const CXXRecordDecl *RD,
- TargetInfo::CallingConvKind CCK, Sema &S) {
- if (RD->isDependentType() || RD->isInvalidDecl())
- return RecordDecl::APK_CanPassInRegs;
-
- // The param cannot be passed in registers if ArgPassingRestrictions is set to
- // APK_CanNeverPassInRegs.
- if (RD->getArgPassingRestrictions() == RecordDecl::APK_CanNeverPassInRegs)
- return RecordDecl::APK_CanNeverPassInRegs;
-
- if (CCK != TargetInfo::CCK_MicrosoftX86_64)
- return DestroyedInCallee ? RecordDecl::APK_CanPassInRegs
- : RecordDecl::APK_CannotPassInRegs;
-
- 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 RecordDecl::APK_CanPassInRegs;
-
- // 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 RecordDecl::APK_CanPassInRegs;
- return RecordDecl::APK_CannotPassInRegs;
-}
-
/// Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -6100,13 +6084,23 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver4;
TargetInfo::CallingConvKind CCK =
Context.getTargetInfo().getCallingConvKind(ClangABICompat4);
- bool DestroyedInCallee = paramCanBeDestroyedInCallee(*this, Record, CCK);
+ bool CanPass = canPassInRegisters(*this, Record, CCK);
- if (Record->hasNonTrivialDestructor())
- Record->setParamDestroyedInCallee(DestroyedInCallee);
-
- Record->setArgPassingRestrictions(
- computeArgPassingRestrictions(DestroyedInCallee, Record, CCK, *this));
+ // Do not change ArgPassingRestrictions if it has already been set to
+ // APK_CanNeverPassInRegs.
+ if (Record->getArgPassingRestrictions() != RecordDecl::APK_CanNeverPassInRegs)
+ Record->setArgPassingRestrictions(CanPass
+ ? RecordDecl::APK_CanPassInRegs
+ : RecordDecl::APK_CannotPassInRegs);
+
+ // If canPassInRegisters returns true despite the record having a non-trivial
+ // destructor, the record is destructed in the callee. This happens only when
+ // the record or one of its subobjects has a field annotated with trivial_abi
+ // or a field qualified with ObjC __strong/__weak.
+ if (Context.getTargetInfo().getCXXABI().areArgsDestroyedLeftToRightInCallee())
+ Record->setParamDestroyedInCallee(true);
+ else if (Record->hasNonTrivialDestructor())
+ Record->setParamDestroyedInCallee(CanPass);
}
/// Look up the special member function that would be called by a special
OpenPOWER on IntegriCloud