diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-07-01 20:59:04 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-07-01 20:59:04 +0000 |
commit | 0d405db2d847acba979a74d747894bcf4d580fe3 (patch) | |
tree | 5456eacd685703c6a781af9c7bdff8101a7c08a4 | |
parent | daa81c06835e438b65b22e071712571a492d6dee (diff) |
Provide exception specifications for implicitly-declared copy constructors.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107429 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/AST/DeclCXX.cpp | 59 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 49 | ||||
-rw-r--r-- | test/CXX/except/except.spec/p14-ir.cpp | 44 |
3 files changed, 123 insertions, 29 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ab8a20994e..e900165353 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -159,6 +159,29 @@ bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { return getCopyConstructor(Context, Qualifiers::Const) != 0; } +/// \brief Perform a simplistic form of overload resolution that only considers +/// cv-qualifiers on a single parameter, and return the best overload candidate +/// (if there is one). +static CXXMethodDecl * +GetBestOverloadCandidateSimple( + const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { + if (Cands.empty()) + return 0; + if (Cands.size() == 1) + return Cands[0].first; + + unsigned Best = 0, N = Cands.size(); + for (unsigned I = 1; I != N; ++I) + if (Cands[Best].second.isSupersetOf(Cands[I].second)) + Best = I; + + for (unsigned I = 1; I != N; ++I) + if (Cands[Best].second.isSupersetOf(Cands[I].second)) + return 0; + + return Cands[Best].first; +} + CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, unsigned TypeQuals) const{ QualType ClassType @@ -167,6 +190,7 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned FoundTQs; + llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); Con != ConEnd; ++Con) { @@ -175,14 +199,18 @@ CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, if (isa<FunctionTemplateDecl>(*Con)) continue; - if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(FoundTQs)) { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) - return cast<CXXConstructorDecl>(*Con); - + Found.push_back(std::make_pair( + const_cast<CXXConstructorDecl *>(Constructor), + Qualifiers::fromCVRMask(FoundTQs))); } } - return 0; + + return cast_or_null<CXXConstructorDecl>( + GetBestOverloadCandidateSimple(Found)); } bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, @@ -232,29 +260,6 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, return false; } -/// \brief Perform a simplistic form of overload resolution that only considers -/// cv-qualifiers on a single parameter, and return the best overload candidate -/// (if there is one). -static CXXMethodDecl * -GetBestOverloadCandidateSimple( - const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { - if (Cands.empty()) - return 0; - if (Cands.size() == 1) - return Cands[0].first; - - unsigned Best = 0, N = Cands.size(); - for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) - Best = I; - - for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) - return 0; - - return Cands[Best].first; -} - CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { ASTContext &Context = getASTContext(); QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index cb454581d1..56e965f81f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4988,6 +4988,49 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(Scope *S, ArgType = ArgType.withConst(); ArgType = Context.getLValueReferenceType(ArgType); + // C++ [except.spec]p14: + // An implicitly declared special member function (Clause 12) shall have an + // exception-specification. [...] + ImplicitExceptionSpecification ExceptSpec(Context); + unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0; + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + BaseEnd = ClassDecl->bases_end(); + Base != BaseEnd; + ++Base) { + // Virtual bases are handled below. + if (Base->isVirtual()) + continue; + + const CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXConstructorDecl *CopyConstructor + = BaseClassDecl->getCopyConstructor(Context, Quals)) + ExceptSpec.CalledDecl(CopyConstructor); + } + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + Base != BaseEnd; + ++Base) { + const CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + if (CXXConstructorDecl *CopyConstructor + = BaseClassDecl->getCopyConstructor(Context, Quals)) + ExceptSpec.CalledDecl(CopyConstructor); + } + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; + ++Field) { + QualType FieldType = Context.getBaseElementType((*Field)->getType()); + if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { + const CXXRecordDecl *FieldClassDecl + = cast<CXXRecordDecl>(FieldClassType->getDecl()); + if (CXXConstructorDecl *CopyConstructor + = FieldClassDecl->getCopyConstructor(Context, Quals)) + ExceptSpec.CalledDecl(CopyConstructor); + } + } + // An implicitly-declared copy constructor is an inline public // member of its class. DeclarationName Name @@ -4999,8 +5042,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(Scope *S, Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0, - /*FIXME: hasExceptionSpec*/false, - false, 0, 0, + ExceptSpec.hasExceptionSpecification(), + ExceptSpec.hasAnyExceptionSpecification(), + ExceptSpec.size(), + ExceptSpec.data(), FunctionType::ExtInfo()), /*TInfo=*/0, /*isExplicit=*/false, diff --git a/test/CXX/except/except.spec/p14-ir.cpp b/test/CXX/except/except.spec/p14-ir.cpp new file mode 100644 index 0000000000..646a87e4e4 --- /dev/null +++ b/test/CXX/except/except.spec/p14-ir.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - %s | FileCheck %s + +struct X0 { + X0(); + X0(const X0 &) throw(); + X0(X0 &); +}; + +struct X1 { + X1(); + X1(const X1 &) throw(); +}; + +struct X2 : X1 { + X2(); +}; +struct X3 : X0, X1 { + X3(); +}; + +struct X4 { + X4(X4 &) throw(); +}; + +struct X5 : X0, X4 { }; + +void test(X2 x2, X3 x3, X5 x5) { + // CHECK: define linkonce_odr void @_ZN2X2C1ERKS_ + // CHECK-NOT: define + // CHECK: call void @__cxa_call_unexpected + // CHECK-NOT: define + // CHECK: ret void + X2 x2a(x2); + // CHECK: define linkonce_odr void @_ZN2X3C1ERKS_ + // CHECK-NOT: define + // CHECK: call void @__cxa_call_unexpected + // CHECK-NOT: define + // CHECK: ret void + X3 x3a(x3); + // CHECK: define linkonce_odr void @_ZN2X5C1ERS_ + // CHECK-NOT: call void @__cxa_call_unexpected + // CHECK: ret void + X5 x5a(x5); +} |