aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-07-01 22:31:05 +0000
committerDouglas Gregor <dgregor@apple.com>2010-07-01 22:31:05 +0000
commiteb8c670d2949eb62005eca36c64c9461f2a2173e (patch)
tree87910e72de01cc550c3a913c8d6bcfae2152d576
parent32df23e749f12a1eaf2a8c7a31e6e69ad0ec64d8 (diff)
Provide exception specifications for implicitly-declared default constructors.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107437 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclCXX.h2
-rw-r--r--lib/AST/DeclCXX.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp51
-rw-r--r--test/CXX/except/except.spec/p14-ir.cpp26
4 files changed, 75 insertions, 7 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 78f8cb9f0c..a543cf0d5b 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -785,7 +785,7 @@ public:
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
/// getDefaultConstructor - Returns the default constructor for this class
- CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
+ CXXConstructorDecl *getDefaultConstructor();
/// getDestructor - Returns the destructor decl for this class.
CXXDestructorDecl *getDestructor() const;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index e900165353..9ab44b6385 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -624,7 +624,8 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
}
CXXConstructorDecl *
-CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
+CXXRecordDecl::getDefaultConstructor() {
+ ASTContext &Context = getASTContext();
QualType ClassType = Context.getTypeDeclType(this);
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 714814afc1..391541d484 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2656,9 +2656,6 @@ namespace {
/// The scope, if provided, is the class scope.
void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S,
CXXRecordDecl *ClassDecl) {
- // FIXME: Implicit declarations have exception specifications, which are
- // the union of the specifications of the implicitly called functions.
-
if (!ClassDecl->hasUserDeclaredConstructor())
DeclareImplicitDefaultConstructor(S, ClassDecl);
@@ -4146,6 +4143,48 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(Scope *S,
// user-declared constructor for class X, a default constructor is
// implicitly declared. An implicitly-declared default constructor
// is an inline public member of its class.
+
+ // C++ [except.spec]p14:
+ // An implicitly declared special member function (Clause 12) shall have an
+ // exception-specification. [...]
+ ImplicitExceptionSpecification ExceptSpec(Context);
+
+ // Direct base-class destructors.
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(),
+ BEnd = ClassDecl->bases_end();
+ B != BEnd; ++B) {
+ if (B->isVirtual()) // Handled below.
+ continue;
+
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
+ if (CXXConstructorDecl *Constructor
+ = cast<CXXRecordDecl>(BaseType->getDecl())->getDefaultConstructor())
+ ExceptSpec.CalledDecl(Constructor);
+ }
+
+ // Virtual base-class destructors.
+ for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(),
+ BEnd = ClassDecl->vbases_end();
+ B != BEnd; ++B) {
+ if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
+ if (CXXConstructorDecl *Constructor
+ = cast<CXXRecordDecl>(BaseType->getDecl())->getDefaultConstructor())
+ ExceptSpec.CalledDecl(Constructor);
+ }
+
+ // Field destructors.
+ for (RecordDecl::field_iterator F = ClassDecl->field_begin(),
+ FEnd = ClassDecl->field_end();
+ F != FEnd; ++F) {
+ if (const RecordType *RecordTy
+ = Context.getBaseElementType(F->getType())->getAs<RecordType>())
+ if (CXXConstructorDecl *Constructor
+ = cast<CXXRecordDecl>(RecordTy->getDecl())->getDefaultConstructor())
+ ExceptSpec.CalledDecl(Constructor);
+ }
+
+
+ // Create the actual constructor declaration.
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
DeclarationName Name
@@ -4155,8 +4194,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(Scope *S,
ClassDecl->getLocation(), Name,
Context.getFunctionType(Context.VoidTy,
0, 0, false, 0,
- /*FIXME*/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
index 646a87e4e4..bc89ce934f 100644
--- a/test/CXX/except/except.spec/p14-ir.cpp
+++ b/test/CXX/except/except.spec/p14-ir.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -o - %s | FileCheck %s
+// Copy constructor
struct X0 {
X0();
X0(const X0 &) throw();
@@ -42,3 +43,28 @@ void test(X2 x2, X3 x3, X5 x5) {
// CHECK: ret void
X5 x5a(x5);
}
+
+// Default constructor
+struct X6 {
+ X6() throw();
+};
+
+struct X7 {
+ X7();
+};
+
+struct X8 : X6 { };
+struct X9 : X6, X7 { };
+
+void test() {
+ // CHECK: define linkonce_odr void @_ZN2X8C1Ev
+ // CHECK-NOT: define
+ // CHECK: call void @__cxa_call_unexpected
+ // CHECK-NOT: define
+ // CHECK: ret void
+ X8();
+ // CHECK: define linkonce_odr void @_ZN2X9C1Ev
+ // CHECK-NOT: call void @__cxa_call_unexpected
+ // CHECK: ret void
+ X9();
+}