diff options
author | David Majnemer <david.majnemer@gmail.com> | 2015-03-06 18:53:55 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2015-03-06 18:53:55 +0000 |
commit | e7a818fec88726844e8acbfeb43da94dea81f4ca (patch) | |
tree | a318bfea08dc92c45a33ddbe7d52cf1a0225f83a /clang/lib/Sema | |
parent | eafe55200c2cc996f24c27e2d26aa3bef897ff04 (diff) | |
download | bcm5719-llvm-e7a818fec88726844e8acbfeb43da94dea81f4ca.tar.gz bcm5719-llvm-e7a818fec88726844e8acbfeb43da94dea81f4ca.zip |
MS ABI: Insert copy-constructors into the CatchableType
Find all unambiguous public classes of the exception object's class type
and reference all of their copy constructors. Yes, this is not
conforming but it is necessary in order to implement their ABI. This is
because the copy constructor is actually referenced by the metadata
describing which catch handlers are eligible to handle the exception
object.
N.B. This doesn't yet handle the copy constructor closure case yet,
that work is ongoing.
Differential Revision: http://reviews.llvm.org/D8101
llvm-svn: 231499
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 29e5150073d..0cedf349b95 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -657,6 +657,55 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } +static void +collectPublicBases(CXXRecordDecl *RD, + llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen, + llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases, + llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen, + bool ParentIsPublic) { + for (const CXXBaseSpecifier &BS : RD->bases()) { + CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); + bool NewSubobject; + // Virtual bases constitute the same subobject. Non-virtual bases are + // always distinct subobjects. + if (BS.isVirtual()) + NewSubobject = VBases.insert(BaseDecl).second; + else + NewSubobject = true; + + if (NewSubobject) + ++SubobjectsSeen[BaseDecl]; + + // Only add subobjects which have public access throughout the entire chain. + bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; + if (PublicPath) + PublicSubobjectsSeen.insert(BaseDecl); + + // Recurse on to each base subobject. + collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, + PublicPath); + } +} + +static void getUnambiguousPublicSubobjects( + CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) { + llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen; + llvm::SmallSet<CXXRecordDecl *, 2> VBases; + llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen; + SubobjectsSeen[RD] = 1; + PublicSubobjectsSeen.insert(RD); + collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, + /*ParentIsPublic=*/true); + + for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { + // Skip ambiguous objects. + if (SubobjectsSeen[PublicSubobject] > 1) + continue; + + Objects.push_back(PublicSubobject); + } +} + /// CheckCXXThrowOperand - Validate the operand of a throw. ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, bool IsThrownVarInScope) { @@ -723,18 +772,29 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, return E; // If the class has a destructor, we must be able to call it. - if (RD->hasIrrelevantDestructor()) - return E; + if (!RD->hasIrrelevantDestructor()) { + if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { + MarkFunctionReferenced(E->getExprLoc(), Destructor); + CheckDestructorAccess(E->getExprLoc(), Destructor, + PDiag(diag::err_access_dtor_exception) << Ty); + if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) + return ExprError(); + } + } - CXXDestructorDecl *Destructor = LookupDestructor(RD); - if (!Destructor) - return E; + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects; + getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); + for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { + if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) { + if (CD->isTrivial()) + continue; + MarkFunctionReferenced(E->getExprLoc(), CD); + Context.addCopyConstructorForExceptionObject(Subobject, CD); + } + } + } - MarkFunctionReferenced(E->getExprLoc(), Destructor); - CheckDestructorAccess(E->getExprLoc(), Destructor, - PDiag(diag::err_access_dtor_exception) << Ty); - if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) - return ExprError(); return E; } |