diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 150 |
1 files changed, 125 insertions, 25 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 28a88d5bb8b..45adbe3a16e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5780,20 +5780,20 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { 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()) { @@ -5806,7 +5806,7 @@ static bool computeCanPassInRegisters(Sema &S, CXXRecordDecl *D) { else if (!isa<CXXDestructorDecl>(MD)) continue; - if (!MD->isTrivial()) + if (!MD->isTrivialForCall()) return false; } @@ -5890,6 +5890,13 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } + // 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()) { @@ -5912,12 +5919,23 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (!M->isImplicit() && !M->isUserProvided()) { if (CSM != CXXInvalid) { M->setTrivial(SpecialMemberIsTrivial(M, CSM)); - // Inform the class that we've finished declaring this member. Record->finishedDefaultedOrDeletedMember(M); + M->setTrivialForCall( + HasTrivialABI || + SpecialMemberIsTrivial(M, CSM, TAH_ConsiderTrivialABI)); + Record->setTrivialForCallFlags(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->setTrivialForCallFlags(M); + } + if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() && M->hasAttr<DLLExportAttr>()) { if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && @@ -7029,9 +7047,14 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, /// /// 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, + Sema::TrivialABIHandling TAH, + CXXMethodDecl **Selected) { if (Selected) *Selected = nullptr; @@ -7072,7 +7095,9 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // C++11 [class.dtor]p5: // A destructor is trivial if: // - all the direct [subobjects] have trivial destructors - if (RD->hasTrivialDestructor()) + if (RD->hasTrivialDestructor() || + (TAH == Sema::TAH_ConsiderTrivialABI && + RD->hasTrivialDestructorForCall())) return true; if (Selected) { @@ -7087,7 +7112,9 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // 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() || + (TAH == Sema::TAH_ConsiderTrivialABI && + 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. @@ -7140,6 +7167,10 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // not supposed to! if (Selected) *Selected = SMOR.getMethod(); + + if (TAH == Sema::TAH_ConsiderTrivialABI && + (CSM == Sema::CXXCopyConstructor || CSM == Sema::CXXMoveConstructor)) + return SMOR.getMethod()->isTrivialForCall(); return SMOR.getMethod()->isTrivial(); } @@ -7178,14 +7209,14 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, QualType SubType, bool ConstRHS, Sema::CXXSpecialMember CSM, TrivialSubobjectKind Kind, - bool Diagnose) { + Sema::TrivialABIHandling TAH, bool Diagnose) { CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl(); if (!SubRD) return true; CXXMethodDecl *Selected; if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(), - ConstRHS, Diagnose ? &Selected : nullptr)) + ConstRHS, TAH, Diagnose ? &Selected : nullptr)) return true; if (Diagnose) { @@ -7215,7 +7246,8 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, << Kind << SubType.getUnqualifiedType() << CSM; // Explain why the defaulted or deleted special member isn't trivial. - S.SpecialMemberIsTrivial(Selected, CSM, Diagnose); + S.SpecialMemberIsTrivial(Selected, CSM, Sema::TAH_IgnoreTrivialABI, + Diagnose); } } @@ -7226,7 +7258,9 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, /// trivial. static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM, - bool ConstArg, bool Diagnose) { + bool ConstArg, + Sema::TrivialABIHandling TAH, + bool Diagnose) { for (const auto *FI : RD->fields()) { if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) continue; @@ -7236,7 +7270,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // Pretend anonymous struct or union members are members of this class. if (FI->isAnonymousStructOrUnion()) { if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(), - CSM, ConstArg, Diagnose)) + CSM, ConstArg, TAH, Diagnose)) return false; continue; } @@ -7264,7 +7298,7 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, bool ConstRHS = ConstArg && !FI->isMutable(); if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, ConstRHS, - CSM, TSK_Field, Diagnose)) + CSM, TSK_Field, TAH, Diagnose)) return false; } @@ -7278,14 +7312,15 @@ void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { bool ConstArg = (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment); checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, ConstArg, CSM, - TSK_CompleteObject, /*Diagnose*/true); + TSK_CompleteObject, TAH_IgnoreTrivialABI, + /*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) { + TrivialABIHandling TAH, bool Diagnose) { assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough"); CXXRecordDecl *RD = MD->getParent(); @@ -7362,7 +7397,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // destructors] for (const auto &BI : RD->bases()) if (!checkTrivialSubobjectCall(*this, BI.getLocStart(), BI.getType(), - ConstArg, CSM, TSK_BaseClass, Diagnose)) + ConstArg, CSM, TSK_BaseClass, TAH, Diagnose)) return false; // C++11 [class.ctor]p5, C++11 [class.dtor]p5: @@ -7377,7 +7412,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // -- 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, TAH, Diagnose)) return false; // C++11 [class.dtor]p5: @@ -7559,6 +7594,50 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) { } } +void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { + auto PrintDiagAndRemoveAttr = [&]() { + // No diagnostics if this is a template instantiation. + if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) + Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), + diag::ext_cannot_use_trivial_abi) << &RD; + RD.dropAttr<TrivialABIAttr>(); + }; + + // Ill-formed if the struct has virtual functions. + if (RD.isPolymorphic()) { + PrintDiagAndRemoveAttr(); + return; + } + + for (const auto &B : RD.bases()) { + // Ill-formed if the base class is non-trivial for the purpose of calls or a + // virtual base. + if ((!B.getType()->isDependentType() && + !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) || + B.isVirtual()) { + PrintDiagAndRemoveAttr(); + return; + } + } + + for (const auto *FD : RD.fields()) { + // Ill-formed if the field is an ObjectiveC pointer or of a type that is + // non-trivial for the purpose of calls. + QualType FT = FD->getType(); + if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { + PrintDiagAndRemoveAttr(); + return; + } + + if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>()) + if (!RT->isDependentType() && + !cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) { + PrintDiagAndRemoveAttr(); + return; + } + } +} + void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, @@ -7577,12 +7656,17 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, l->getName(); } + // See if trivial_abi has to be dropped. + auto *RD = dyn_cast<CXXRecordDecl>(TagDecl); + if (RD && RD->hasAttr<TrivialABIAttr>()) + checkIllFormedTrivialABIStruct(*RD); + 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 @@ -10732,6 +10816,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // We don't need to use SpecialMemberIsTrivial here; triviality for // destructors is easy to compute. Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); + Destructor->setTrivialForCall(ClassDecl->hasAttr<TrivialABIAttr>() || + ClassDecl->hasTrivialDestructorForCall()); // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; @@ -12035,9 +12121,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setParams(FromParam); CopyConstructor->setTrivial( - ClassDecl->needsOverloadResolutionForCopyConstructor() - ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) - : ClassDecl->hasTrivialCopyConstructor()); + ClassDecl->needsOverloadResolutionForCopyConstructor() + ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) + : ClassDecl->hasTrivialCopyConstructor()); + + CopyConstructor->setTrivialForCall( + ClassDecl->hasAttr<TrivialABIAttr>() || + (ClassDecl->needsOverloadResolutionForCopyConstructor() + ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor, + TAH_ConsiderTrivialABI) + : ClassDecl->hasTrivialCopyConstructorForCall())); // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; @@ -12158,9 +12251,16 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setParams(FromParam); MoveConstructor->setTrivial( - ClassDecl->needsOverloadResolutionForMoveConstructor() - ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) - : ClassDecl->hasTrivialMoveConstructor()); + ClassDecl->needsOverloadResolutionForMoveConstructor() + ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) + : ClassDecl->hasTrivialMoveConstructor()); + + MoveConstructor->setTrivialForCall( + ClassDecl->hasAttr<TrivialABIAttr>() || + (ClassDecl->needsOverloadResolutionForMoveConstructor() + ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor, + TAH_ConsiderTrivialABI) + : ClassDecl->hasTrivialMoveConstructorForCall())); // Note that we have declared this constructor. ++ASTContext::NumImplicitMoveConstructorsDeclared; |