Commit 7da58705 authored by Bill Wendling's avatar Bill Wendling
Browse files

Merging r155293:

------------------------------------------------------------------------
r155293 | rsmith | 2012-04-21 11:42:51 -0700 (Sat, 21 Apr 2012) | 4 lines

Fix regression in r154844. If necessary, defer computing adjusted destructor
exception specifications in C++11 until after we've parsed the exception
specifications for nested classes.

------------------------------------------------------------------------

llvm-svn: 156683
parent fc08c674
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -331,6 +331,11 @@ public:
  /// cycle detection at the end of the TU.
  DelegatingCtorDeclsType DelegatingCtorDecls;

  /// \brief All the destructors seen during a class definition that had their
  /// exception spec computation delayed because it depended on an unparsed
  /// exception spec.
  SmallVector<CXXDestructorDecl*, 2> DelayedDestructorExceptionSpecs;

  /// \brief All the overriding destructors seen during a class definition
  /// (there could be multiple due to nested classes) that had their exception
  /// spec checks delayed, plus the overridden destructor.
@@ -3196,7 +3201,8 @@ public:
  /// C++11 says that user-defined destructors with no exception spec get one
  /// that looks as if the destructor was implicitly declared.
  void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
                                     CXXDestructorDecl *Destructor);
                                     CXXDestructorDecl *Destructor,
                                     bool WasDelayed = false);

  /// \brief Declare all inherited constructors for the given class.
  ///
@@ -4034,6 +4040,7 @@ public:
                                         SourceLocation LBrac,
                                         SourceLocation RBrac,
                                         AttributeList *AttrList);
  void ActOnFinishCXXMemberDecls();

  void ActOnReenterTemplateScope(Scope *S, Decl *Template);
  void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D);
+4 −0
Original line number Diff line number Diff line
@@ -2369,6 +2369,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
    SourceLocation SavedPrevTokLocation = PrevTokLocation;
    ParseLexedAttributes(getCurrentClass());
    ParseLexedMethodDeclarations(getCurrentClass());

    // We've finished with all pending member declarations.
    Actions.ActOnFinishCXXMemberDecls();

    ParseLexedMemberInitializers(getCurrentClass());
    ParseLexedMethodDefs(getCurrentClass());
    PrevTokLocation = SavedPrevTokLocation;
+0 −15
Original line number Diff line number Diff line
@@ -9784,21 +9784,6 @@ void Sema::ActOnFields(Scope* S,
    if (!Completed)
      Record->completeDefinition();

    // Now that the record is complete, do any delayed exception spec checks
    // we were missing.
    while (!DelayedDestructorExceptionSpecChecks.empty()) {
      const CXXDestructorDecl *Dtor =
              DelayedDestructorExceptionSpecChecks.back().first;
      if (Dtor->getParent() != Record)
        break;

      assert(!Dtor->getParent()->isDependentType() &&
          "Should not ever add destructors of templates into the list.");
      CheckOverridingFunctionExceptionSpec(Dtor,
          DelayedDestructorExceptionSpecChecks.back().second);
      DelayedDestructorExceptionSpecChecks.pop_back();
    }

  } else {
    ObjCIvarDecl **ClsFields =
      reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
+37 −2
Original line number Diff line number Diff line
@@ -7319,15 +7319,42 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
  }
}

/// \brief Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
  // Now we have parsed all exception specifications, determine the implicit
  // exception specifications for destructors.
  for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size();
       i != e; ++i) {
    CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i];
    AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true);
  }
  DelayedDestructorExceptionSpecs.clear();

  // Perform any deferred checking of exception specifications for virtual
  // destructors.
  for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
       i != e; ++i) {
    const CXXDestructorDecl *Dtor =
        DelayedDestructorExceptionSpecChecks[i].first;
    assert(!Dtor->getParent()->isDependentType() &&
           "Should not ever add destructors of templates into the list.");
    CheckOverridingFunctionExceptionSpec(Dtor,
        DelayedDestructorExceptionSpecChecks[i].second);
  }
  DelayedDestructorExceptionSpecChecks.clear();
}

void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,
                                         CXXDestructorDecl *destructor) {
                                         CXXDestructorDecl *destructor,
                                         bool WasDelayed) {
  // C++11 [class.dtor]p3:
  //   A declaration of a destructor that does not have an exception-
  //   specification is implicitly considered to have the same exception-
  //   specification as an implicit declaration.
  const FunctionProtoType *dtorType = destructor->getType()->
                                        getAs<FunctionProtoType>();
  if (dtorType->hasExceptionSpec())
  if (!WasDelayed && dtorType->hasExceptionSpec())
    return;

  ImplicitExceptionSpecification exceptSpec =
@@ -7344,6 +7371,14 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,

  destructor->setType(ty);

  // If we can't compute the exception specification for this destructor yet
  // (because it depends on an exception specification which we have not parsed
  // yet), make a note that we need to try again when the class is complete.
  if (epi.ExceptionSpecType == EST_Delayed) {
    assert(!WasDelayed && "couldn't compute destructor exception spec");
    DelayedDestructorExceptionSpecs.push_back(destructor);
  }

  // FIXME: If the destructor has a body that could throw, and the newly created
  // spec doesn't allow exceptions, we should emit a warning, because this
  // change in behavior can break conforming C++03 programs at runtime.
+30 −0
Original line number Diff line number Diff line
@@ -57,3 +57,33 @@ namespace DefaultArgument {
    } t; // expected-note {{has no default constructor}}
  };
}

namespace ImplicitDtorExceptionSpec {
  struct A {
    virtual ~A();

    struct Inner {
      ~Inner() throw();
    };
    Inner inner;
  };

  struct B {
    virtual ~B() {} // expected-note {{here}}
  };

  struct C : B {
    virtual ~C() {}
    A a;
  };

  struct D : B {
    ~D(); // expected-error {{more lax than base}}
    struct E {
      ~E();
      struct F {
        ~F() throw(A);
      } f;
    } e;
  };
}