[cfe-commits] r107429 - in /cfe/trunk: lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/except/except.spec/p14-ir.cpp

Douglas Gregor dgregor at apple.com
Thu Jul 1 13:59:04 PDT 2010


Author: dgregor
Date: Thu Jul  1 15:59:04 2010
New Revision: 107429

URL: http://llvm.org/viewvc/llvm-project?rev=107429&view=rev
Log:
Provide exception specifications for implicitly-declared copy constructors.

Added:
    cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp
Modified:
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=107429&r1=107428&r2=107429&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jul  1 15:59:04 2010
@@ -159,6 +159,29 @@
   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 @@
     = 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 @@
     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 @@
   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));

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=107429&r1=107428&r2=107429&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jul  1 15:59:04 2010
@@ -4988,6 +4988,49 @@
     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 @@
                                  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,

Added: cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp?rev=107429&view=auto
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp (added)
+++ cfe/trunk/test/CXX/except/except.spec/p14-ir.cpp Thu Jul  1 15:59:04 2010
@@ -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);
+}





More information about the cfe-commits mailing list