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
= 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) {
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,
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));
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
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,
--- /dev/null
+// 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);
+}