diff options
24 files changed, 432 insertions, 332 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index fbb3a582ca..bf30777922 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2847,6 +2847,8 @@ public: } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { EPI.ExceptionSpecDecl = getExceptionSpecDecl(); EPI.ExceptionSpecTemplate = getExceptionSpecTemplate(); + } else if (EPI.ExceptionSpecType == EST_Unevaluated) { + EPI.ExceptionSpecDecl = getExceptionSpecDecl(); } if (hasAnyConsumedArgs()) EPI.ConsumedArguments = getConsumedArgsBuffer(); @@ -2890,11 +2892,13 @@ public: // NoexceptExpr sits where the arguments end. return *reinterpret_cast<Expr *const *>(arg_type_end()); } - /// \brief If this function type has an uninstantiated exception - /// specification, this is the function whose exception specification - /// is represented by this type. + /// \brief If this function type has an exception specification which hasn't + /// been determined yet (either because it has not been evaluated or because + /// it has not been instantiated), this is the function whose exception + /// specification is represented by this type. FunctionDecl *getExceptionSpecDecl() const { - if (getExceptionSpecType() != EST_Uninstantiated) + if (getExceptionSpecType() != EST_Uninstantiated && + getExceptionSpecType() != EST_Unevaluated) return 0; return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0]; } @@ -2909,7 +2913,7 @@ public: } bool isNothrow(ASTContext &Ctx) const { ExceptionSpecificationType EST = getExceptionSpecType(); - assert(EST != EST_Delayed && EST != EST_Uninstantiated); + assert(EST != EST_Unevaluated && EST != EST_Uninstantiated); if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) return true; if (EST != EST_ComputedNoexcept) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6a4e7d8c9b..eb8fcbba3e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -870,8 +870,6 @@ def warn_missing_exception_specification : Warning< "%0 is missing exception specification '%1'">; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; -def err_exception_spec_unknown : Error< - "exception specification is not available until end of class definition">; // C++ access checking def err_class_redeclared_with_different_access : Error< @@ -5088,6 +5086,9 @@ def err_in_class_initializer_literal_type : Error< "'constexpr' specifier">; def err_in_class_initializer_non_constant : Error< "in-class initializer for static data member is not a constant expression">; +def err_in_class_initializer_references_def_ctor : Error< + "defaulted default constructor of %0 cannot be used by non-static data " + "member initializer which appears before end of class definition">; def ext_in_class_initializer_non_constant : Extension< "in-class initializer for static data member is not a constant expression; " diff --git a/include/clang/Basic/ExceptionSpecificationType.h b/include/clang/Basic/ExceptionSpecificationType.h index 6be5053b1b..edd89ec709 100644 --- a/include/clang/Basic/ExceptionSpecificationType.h +++ b/include/clang/Basic/ExceptionSpecificationType.h @@ -25,7 +25,7 @@ enum ExceptionSpecificationType { EST_MSAny, ///< Microsoft throw(...) extension EST_BasicNoexcept, ///< noexcept EST_ComputedNoexcept, ///< noexcept(expression) - EST_Delayed, ///< not known yet + EST_Unevaluated, ///< not evaluated yet, for special member function EST_Uninstantiated ///< not instantiated yet }; @@ -37,6 +37,10 @@ inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) { return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept; } +inline bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType == EST_Unevaluated || ESpecType == EST_Uninstantiated; +} + /// \brief Possible results from evaluation of a noexcept expression. enum CanThrowResult { CT_Cannot, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 7999748b0f..00d42a814a 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1152,8 +1152,7 @@ struct DeclaratorChunk { /// any. unsigned MutableLoc; - /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the - /// location of the keyword introducing the spec. + /// \brief The location of the keyword introducing the spec, if any. unsigned ExceptionSpecLoc; /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e5b3b5a012..9675e08e4a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3335,17 +3335,6 @@ public: /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); - /// \brief Specify that the exception specification can't be detemined yet. - void SetDelayed() { - ClearExceptions(); - ComputedEST = EST_Delayed; - } - - /// \brief Have we been unable to compute this exception specification? - bool isDelayed() { - return ComputedEST == EST_Delayed; - } - /// \brief Overwrite an EPI's exception specification with this /// computed exception specification. void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const { @@ -3363,34 +3352,39 @@ public: /// \brief Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. - std::pair<ImplicitExceptionSpecification, bool> - ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + ImplicitExceptionSpecification + ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. - std::pair<ImplicitExceptionSpecification, bool> - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + ImplicitExceptionSpecification + ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification - ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification - ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl); + ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); + + /// \brief Evaluate the implicit exception specification for a defaulted + /// special member function. + void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Check the given exception-specification and update the /// extended prototype information with the results. @@ -3438,8 +3432,7 @@ 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, - bool WasDelayed = false); + CXXDestructorDecl *Destructor); /// \brief Declare all inherited constructors for the given class. /// @@ -4262,6 +4255,11 @@ public: void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); + /// \brief Mark the exception specifications of all virtual member functions + /// in the given class as needed. + void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, + const CXXRecordDecl *RD); + /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2e13d0cc44..5b57ce4557 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2367,15 +2367,18 @@ ASTContext::getFunctionType(QualType ResultTy, // - exception types // - consumed-arguments flags // Instead of the exception types, there could be a noexcept - // expression. + // expression, or information used to resolve the exception + // specification. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); - if (EPI.ExceptionSpecType == EST_Dynamic) + if (EPI.ExceptionSpecType == EST_Dynamic) { Size += EPI.NumExceptions * sizeof(QualType); - else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); + } else if (EPI.ExceptionSpecType == EST_Unevaluated) { + Size += sizeof(FunctionDecl*); } if (EPI.ConsumedArguments) Size += NumArgs * sizeof(bool); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index eacf505442..abefae44b2 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1584,6 +1584,11 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, slot[1] = epi.ExceptionSpecTemplate; // This exception specification doesn't make the type dependent, because // it's not instantiated as part of instantiating the type. + } else if (getExceptionSpecType() == EST_Unevaluated) { + // Store the function decl from which we will resolve our + // exception specification. + FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs); + slot[0] = epi.ExceptionSpecDecl; } if (epi.ConsumedArguments) { @@ -1667,7 +1672,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ epi.NoexceptExpr->Profile(ID, Context, false); - } else if (epi.ExceptionSpecType == EST_Uninstantiated) { + } else if (epi.ExceptionSpecType == EST_Uninstantiated || + epi.ExceptionSpecType == EST_Unevaluated) { ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl()); } if (epi.ConsumedArguments) { diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 1284527595..05c53850f5 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -1340,7 +1340,7 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) { const FunctionType *FT = Ty->getAs<FunctionType>(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - if (Proto->getExceptionSpecType() != EST_Uninstantiated && + if (!isUnresolvedExceptionSpec(Proto->getExceptionSpecType()) && Proto->isNothrow(Ctx)) return false; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7233fc7c13..81b94a4ecd 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4655,11 +4655,6 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } -static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) { - const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>(); - return Proto && Proto->getExceptionSpecType() == EST_Delayed; -} - /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4675,8 +4670,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { MD->addOverriddenMethod(OldMD->getCanonicalDecl()); if (!CheckOverridingFunctionReturnType(MD, OldMD) && - (hasDelayedExceptionSpec(MD) || - !CheckOverridingFunctionExceptionSpec(MD, OldMD)) && + !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { AddedAny = true; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1480c2ef98..9c4272de0c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -128,8 +128,8 @@ namespace { void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method) { - // If we have an MSAny or unknown spec already, don't bother. - if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + // If we have an MSAny spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny) return; const FunctionProtoType *Proto @@ -141,7 +141,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, ExceptionSpecificationType EST = Proto->getExceptionSpecType(); // If this function can throw any exceptions, make a note of that. - if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) { + if (EST == EST_MSAny || EST == EST_None) { ClearExceptions(); ComputedEST = EST; return; @@ -198,7 +198,7 @@ void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, } void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { - if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed) + if (!E || ComputedEST == EST_MSAny) return; // FIXME: @@ -3881,9 +3881,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inherited constructors. DeclareInheritedConstructors(Record); - - if (!Record->isDependentType()) - CheckExplicitlyDefaultedMethods(Record); } void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { @@ -3989,6 +3986,45 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, return true; } +static Sema::ImplicitExceptionSpecification +computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { + switch (S.getSpecialMember(MD)) { + case Sema::CXXDefaultConstructor: + return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD); + case Sema::CXXCopyConstructor: + return S.ComputeDefaultedCopyCtorExceptionSpec(MD); + case Sema::CXXCopyAssignment: + return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD); + case Sema::CXXMoveConstructor: + return S.ComputeDefaultedMoveCtorExceptionSpec(MD); + case Sema::CXXMoveAssignment: + return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD); + case Sema::CXXDestructor: + return S.ComputeDefaultedDtorExceptionSpec(MD); + case Sema::CXXInvalid: + break; + } + llvm_unreachable("only special members have implicit exception specs"); +} + +void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); + if (FPT->getExceptionSpecType() != EST_Unevaluated) + return; + + // Evaluate the exception specification and update the type of the special + // member to use it. + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + computeImplicitExceptionSpec(*this, Loc, MD).getEPI(EPI); + const FunctionProtoType *NewFPT = cast<FunctionProtoType>( + Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI)); + MD->setType(QualType(NewFPT, 0)); +} + +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl); +static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl); + void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { CXXRecordDecl *RD = MD->getParent(); CXXSpecialMember CSM = getSpecialMember(MD); @@ -4023,40 +4059,28 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>(); - // Compute implicit exception specification, argument constness, constexpr - // and triviality. - ImplicitExceptionSpecification Spec(*this); + // Compute argument constness, constexpr, and triviality. bool CanHaveConstParam = false; bool Trivial; switch (CSM) { case CXXDefaultConstructor: - Spec = ComputeDefaultedDefaultCtorExceptionSpec(RD); - if (Spec.isDelayed()) - // Exception specification depends on some deferred part of the class. - // We'll try again when the class's definition has been fully processed. - return; Trivial = RD->hasTrivialDefaultConstructor(); break; case CXXCopyConstructor: - llvm::tie(Spec, CanHaveConstParam) = - ComputeDefaultedCopyCtorExceptionSpecAndConst(RD); + CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD); Trivial = RD->hasTrivialCopyConstructor(); break; case CXXCopyAssignment: - llvm::tie(Spec, CanHaveConstParam) = - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(RD); + CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD); Trivial = RD->hasTrivialCopyAssignment(); break; case CXXMoveConstructor: - Spec = ComputeDefaultedMoveCtorExceptionSpec(RD); Trivial = RD->hasTrivialMoveConstructor(); break; case CXXMoveAssignment: - Spec = ComputeDefaultedMoveAssignmentExceptionSpec(RD); Trivial = RD->hasTrivialMoveAssignment(); break; case CXXDestructor: - Spec = ComputeDefaultedDtorExceptionSpec(RD); Trivial = RD->hasTrivialDestructor(); break; case CXXInvalid: @@ -4126,11 +4150,15 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { HadError = true; } - // Rebuild the type with the implicit exception specification added. - FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); - Spec.getEPI(EPI); - const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( - Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI)); + // Rebuild the type with the implicit exception specification added, if we + // are going to need it. + const FunctionProtoType *ImplicitType = 0; + if (First || Type->hasExceptionSpec()) { + FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); + computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI); + ImplicitType = cast<FunctionProtoType>( + Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI)); + } // C++11 [dcl.fct.def.default]p2: // An explicitly-defaulted function may be declared constexpr only if it @@ -6685,7 +6713,10 @@ namespace { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, + CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have an // exception-specification. [...] @@ -6732,7 +6763,21 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) { if (Expr *E = F->getInClassInitializer()) ExceptSpec.CalledExpr(E); else if (!F->isInvalidDecl()) - ExceptSpec.SetDelayed(); + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // We do not allow an in-class initializer to require the evaluation + // of the exception specification for any in-class initializer whose + // definition is not lexically complete. + Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD; } else if (const RecordType *RecordTy = Context.getBaseElementType(F->getType())->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -6761,10 +6806,6 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( assert(!ClassDecl->hasUserDeclaredConstructor() && "Should not build implicit default constructor!"); - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, CXXDefaultConstructor, false); @@ -6777,15 +6818,20 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( = Context.DeclarationNames.getCXXConstructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( - Context, ClassDecl, ClassLoc, NameInfo, - Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0, + Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0, /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); - + + // Build an exception specification pointing back at this constructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = DefaultCon; + DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; @@ -6830,58 +6876,14 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, } } -/// Get any existing defaulted default constructor for the given class. Do not -/// implicitly define one if it does not exist. -static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self, - CXXRecordDecl *D) { - ASTContext &Context = Self.Context; - QualType ClassType = Context.getTypeDeclType(D); - DeclarationName ConstructorName - = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ClassType.getUnqualifiedType())); - - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName); - Con != ConEnd; ++Con) { - // A function template cannot be defaulted. - if (isa<FunctionTemplateDecl>(*Con)) - continue; - - CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); - if (Constructor->isDefaultConstructor()) - return Constructor->isDefaulted() ? Constructor : 0; - } - return 0; -} - void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { if (!D) return; AdjustDeclIfTemplate(D); CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D); - CXXConstructorDecl *CtorDecl - = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl); - - if (!CtorDecl) return; - - // Compute the exception specification for the default constructor. - const FunctionProtoType *CtorTy = - CtorDecl->getType()->castAs<FunctionProtoType>(); - if (CtorTy->getExceptionSpecType() == EST_Delayed) { - // FIXME: Don't do this unless the exception spec is needed. - ImplicitExceptionSpecification Spec = - ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); - assert(EPI.ExceptionSpecType != EST_Delayed); - CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); - } - - // If the default constructor is explicitly defaulted, checking the exception - // specification is deferred until now. - if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() && - !ClassDecl->isDependentType()) - CheckExplicitlyDefaultedSpecialMember(CtorDecl); + if (!ClassDecl->isDependentType()) + CheckExplicitlyDefaultedMethods(ClassDecl); } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { @@ -7065,7 +7067,9 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { } Sema::ImplicitExceptionSpecification -Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) { +Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) { + CXXRecordDecl *ClassDecl = MD->getParent(); + // C++ [except.spec]p14: // An implicitly declared special member function (Clause 12) shall have // an exception-specification. @@ -7112,14 +7116,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // If a class has no user-declared destructor, a destructor is // declared implicitly. An implicitly-declared destructor is an // inline public member of its class. - - ImplicitExceptionSpecification Spec = - ComputeDefaultedDtorExceptionSpec(ClassDecl); - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI(); // Create the actual destructor declaration. - QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); - CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); SourceLocation ClassLoc = ClassDecl->getLocation(); @@ -7127,24 +7125,27 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, - /*isInline=*/true, + = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, + QualType(), 0, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setDefaulted(); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - + + // Build an exception specification pointing back at this destructor. + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); + // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; - + // Introduce this destructor into its scope. if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); - - // This could be uniqued if it ever proves significant. - Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); AddOverriddenMethods(ClassDecl, Destructor); @@ -7194,15 +7195,6 @@ 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(); @@ -7217,44 +7209,33 @@ void Sema::ActOnFinishCXXMemberDecls() { DelayedDestructorExceptionSpecChecks.clear(); } -void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl, - CXXDestructorDecl *destructor, - bool WasDelayed) { +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, + CXXDestructorDecl *Destructor) { + assert(getLangOpts().CPlusPlus0x && + "adjusting dtor exception specs was introduced in c++11"); + // 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()-> + const FunctionProtoType *DtorType = Destructor->getType()-> getAs<FunctionProtoType>(); - if (!WasDelayed && dtorType->hasExceptionSpec()) + if (DtorType->hasExceptionSpec()) return; - ImplicitExceptionSpecification exceptSpec = - ComputeDefaultedDtorExceptionSpec(classDecl); - // Replace the destructor's type, building off the existing one. Fortunately, // the only thing of interest in the destructor type is its extended info. // The return and arguments are fixed. - FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo(); - epi.ExceptionSpecType = exceptSpec.getExceptionSpecType(); - epi.NumExceptions = exceptSpec.size(); - epi.Exceptions = exceptSpec.data(); - QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi); - - 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); - } + FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_Unevaluated; + EPI.ExceptionSpecDecl = Destructor; + Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI)); // 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. - // However, we don't have a body yet, so it needs to be done somewhere else. + // However, we don't have a body or an exception specification yet, so it + // needs to be done somewhere else. } /// \brief Builds a statement that copies/moves the given entity from \p From to @@ -7456,11 +7437,13 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Loc, Copy.take()); } -std::pair<Sema::ImplicitExceptionSpecification, bool> -Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( - CXXRecordDecl *ClassDecl) { +/// Determine whether an implicit copy assignment operator for ClassDecl has a +/// const argument. +/// FIXME: It ought to be possi |