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 | 8453ddb5fed2d04e12824e92a0bd2cc66091bb4c (patch) | |
| tree | 7b3a15f8e49f2994f9bf2372593e6c1c1a3fa79a /clang | |
| parent | 0e980755d332cb14b9d6a9d4c11a7879510927a6 (diff) | |
| download | bcm5719-llvm-8453ddb5fed2d04e12824e92a0bd2cc66091bb4c.tar.gz bcm5719-llvm-8453ddb5fed2d04e12824e92a0bd2cc66091bb4c.zip | |
Provide exception specifications for implicitly-declared copy constructors.
llvm-svn: 107429
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 59 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 49 | ||||
| -rw-r--r-- | clang/test/CXX/except/except.spec/p14-ir.cpp | 44 | 
3 files changed, 123 insertions, 29 deletions
| diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ab8a20994ee..e900165353c 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index cb454581d1a..56e965f81fe 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/test/CXX/except/except.spec/p14-ir.cpp b/clang/test/CXX/except/except.spec/p14-ir.cpp new file mode 100644 index 00000000000..646a87e4e4f --- /dev/null +++ b/clang/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); +} | 

