[cfe-commits] r160847 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Analysis/ lib/Sema/ lib/Serialization/ test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/ test/CodeGenCXX/ test/SemaCXX/ test/
Sean Silva
silvas at purdue.edu
Thu Jul 26 22:21:59 PDT 2012
what is a "function temploid"?
--Sean Silva
On Thu, Jul 26, 2012 at 9:22 PM, Richard Smith
<richard-llvm at metafoo.co.uk> wrote:
> Author: rsmith
> Date: Thu Jul 26 23:22:15 2012
> New Revision: 160847
>
> URL: http://llvm.org/viewvc/llvm-project?rev=160847&view=rev
> Log:
> Final piece of core issue 1330: delay computing the exception specification of
> a defaulted special member function until the exception specification is needed
> (using the same criteria used for the delayed instantiation of exception
> specifications for function temploids).
>
> EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
> EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
> resolve the exception specification.
>
> This is enabled for all C++ modes: it's a little faster in the case where the
> exception specification isn't used, allows our C++11-in-C++98 extensions to
> work, and is still correct for C++98, since in that mode the computation of the
> exception specification can't fail.
>
> The diagnostics here aren't great (in particular, we should include implicit
> evaluation of exception specifications for defaulted special members in the
> template instantiation backtraces), but they're not much worse than before.
>
> Our approach to the problem of cycles between in-class initializers and the
> exception specification for a defaulted default constructor is modified a
> little by this change -- we now reject any odr-use of a defaulted default
> constructor if that constructor uses an in-class initializer and the use is in
> an in-class initialzer which is declared lexically earlier. This is a closer
> approximation to the current draft solution in core issue 1351, but isn't an
> exact match (but the current draft wording isn't reasonable, so that's to be
> expected).
>
> Removed:
> cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp
> Modified:
> cfe/trunk/include/clang/AST/Type.h
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
> cfe/trunk/include/clang/Sema/DeclSpec.h
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/AST/ASTContext.cpp
> cfe/trunk/lib/AST/Type.cpp
> cfe/trunk/lib/Analysis/CFG.cpp
> cfe/trunk/lib/Sema/SemaDecl.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
> cfe/trunk/lib/Sema/SemaExpr.cpp
> cfe/trunk/lib/Sema/SemaExprCXX.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> cfe/trunk/lib/Serialization/ASTReader.cpp
> cfe/trunk/lib/Serialization/ASTWriter.cpp
> cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp
> cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
> cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
> cfe/trunk/test/SemaCXX/member-init.cpp
> cfe/trunk/test/SemaCXX/type-traits.cpp
> cfe/trunk/test/SemaTemplate/instantiation-depth.cpp
>
> Modified: cfe/trunk/include/clang/AST/Type.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Type.h (original)
> +++ cfe/trunk/include/clang/AST/Type.h Thu Jul 26 23:22:15 2012
> @@ -2847,6 +2847,8 @@
> } 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 @@
> // 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 @@
> }
> 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)
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 26 23:22:15 2012
> @@ -870,8 +870,6 @@
> "%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 @@
> "'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; "
>
> Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)
> +++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Thu Jul 26 23:22:15 2012
> @@ -25,7 +25,7 @@
> 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 @@
> 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,
>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Thu Jul 26 23:22:15 2012
> @@ -1152,8 +1152,7 @@
> /// 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
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 26 23:22:15 2012
> @@ -3335,17 +3335,6 @@
> /// \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 @@
> /// \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 @@
> /// 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 @@
> 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,
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jul 26 23:22:15 2012
> @@ -2367,15 +2367,18 @@
> // - 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);
>
> Modified: cfe/trunk/lib/AST/Type.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/Type.cpp (original)
> +++ cfe/trunk/lib/AST/Type.cpp Thu Jul 26 23:22:15 2012
> @@ -1584,6 +1584,11 @@
> 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 @@
> 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) {
>
> Modified: cfe/trunk/lib/Analysis/CFG.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CFG.cpp (original)
> +++ cfe/trunk/lib/Analysis/CFG.cpp Thu Jul 26 23:22:15 2012
> @@ -1340,7 +1340,7 @@
> 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;
> }
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul 26 23:22:15 2012
> @@ -4655,11 +4655,6 @@
> 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 @@
> 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;
> }
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jul 26 23:22:15 2012
> @@ -128,8 +128,8 @@
>
> 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 @@
> 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::CalledExpr(Expr *E) {
> - if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
> + if (!E || ComputedEST == EST_MSAny)
> return;
>
> // FIXME:
> @@ -3881,9 +3881,6 @@
> // 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 @@
> 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 @@
>
> 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 @@
> 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 @@
> }
>
> 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 @@
> 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 @@
> 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 @@
> = 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 @@
> }
> }
>
> -/// 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 @@
> }
>
> 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 @@
> // 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 @@
> = 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 @@
> /// \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 @@
> 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 @@
> 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 possible to store this on the record.
> +static bool isImplicitCopyAssignmentArgConst(Sema &S,
> + CXXRecordDecl *ClassDecl) {
> if (ClassDecl->isInvalidDecl())
> - return std::make_pair(ImplicitExceptionSpecification(*this), true);
> + return true;
>
> // C++ [class.copy]p10:
> // If the class definition does not explicitly declare a copy
> @@ -7471,37 +7454,34 @@
> // X& X::operator=(const X&)
> //
> // if
> - bool HasConstCopyAssignment = true;
> -
> // -- each direct base class B of X has a copy assignment operator
> // whose parameter is of type const B&, const volatile B& or B,
> // and
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> - HasConstCopyAssignment && Base != BaseEnd; ++Base) {
> + Base != BaseEnd; ++Base) {
> // We'll handle this below
> - if (LangOpts.CPlusPlus0x && Base->isVirtual())
> + if (S.getLangOpts().CPlusPlus0x && Base->isVirtual())
> continue;
>
> assert(!Base->getType()->isDependentType() &&
> "Cannot generate implicit members for class with dependent bases.");
> CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
> - HasConstCopyAssignment &=
> - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
> - false, 0);
> + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0))
> + return false;
> }
>
> // In C++11, the above citation has "or virtual" added
> - if (LangOpts.CPlusPlus0x) {
> + if (S.getLangOpts().CPlusPlus0x) {
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> BaseEnd = ClassDecl->vbases_end();
> - HasConstCopyAssignment && Base != BaseEnd; ++Base) {
> + Base != BaseEnd; ++Base) {
> assert(!Base->getType()->isDependentType() &&
> "Cannot generate implicit members for class with dependent bases.");
> CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
> - HasConstCopyAssignment &=
> - (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
> - false, 0);
> + if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
> + false, 0))
> + return false;
> }
> }
>
> @@ -7511,23 +7491,36 @@
> // const volatile M& or M.
> for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> FieldEnd = ClassDecl->field_end();
> - HasConstCopyAssignment && Field != FieldEnd;
> - ++Field) {
> - QualType FieldType = Context.getBaseElementType(Field->getType());
> - if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
> - HasConstCopyAssignment &=
> - (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
> - false, 0);
> - }
> + Field != FieldEnd; ++Field) {
> + QualType FieldType = S.Context.getBaseElementType(Field->getType());
> + if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl())
> + if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
> + false, 0))
> + return false;
> }
>
> // Otherwise, the implicitly declared copy assignment operator will
> // have the form
> //
> // X& X::operator=(X&)
> -
> +
> + return true;
> +}
> +
> +Sema::ImplicitExceptionSpecification
> +Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {
> + CXXRecordDecl *ClassDecl = MD->getParent();
> +
> + ImplicitExceptionSpecification ExceptSpec(*this);
> + if (ClassDecl->isInvalidDecl())
> + return ExceptSpec;
> +
> + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
> + assert(T->getNumArgs() == 1 && "not a copy assignment op");
> + unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
> +
> // C++ [except.spec]p14:
> - // An implicitly declared special member function (Clause 12) shall have an
> + // An implicitly declared special member function (Clause 12) shall have an
> // exception-specification. [...]
>
> // It is unspecified whether or not an implicit copy assignment operator
> @@ -7536,8 +7529,6 @@
> // Based on a similar decision made for constness in C++0x, we're erring on
> // the side of assuming such calls to be made regardless of whether they
> // actually happen.
> - ImplicitExceptionSpecification ExceptSpec(*this);
> - unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> Base != BaseEnd; ++Base) {
> @@ -7575,7 +7566,7 @@
> }
> }
>
> - return std::make_pair(ExceptSpec, HasConstCopyAssignment);
> + return ExceptSpec;
> }
>
> CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
> @@ -7584,26 +7575,19 @@
> // for determining the argument type of the operator. Note also that
> // operators taking an object instead of a reference are allowed.
>
> - ImplicitExceptionSpecification Spec(*this);
> - bool Const;
> - llvm::tie(Spec, Const) =
> - ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
> -
> QualType ArgType = Context.getTypeDeclType(ClassDecl);
> QualType RetType = Context.getLValueReferenceType(ArgType);
> - if (Const)
> + if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))
> ArgType = ArgType.withConst();
> ArgType = Context.getLValueReferenceType(ArgType);
>
> // An implicitly-declared copy assignment operator is an inline public
> // member of its class.
> - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
> DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
> SourceLocation ClassLoc = ClassDecl->getLocation();
> DeclarationNameInfo NameInfo(Name, ClassLoc);
> CXXMethodDecl *CopyAssignment
> - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
> - Context.getFunctionType(RetType, &ArgType, 1, EPI),
> + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
> /*TInfo=*/0, /*isStatic=*/false,
> /*StorageClassAsWritten=*/SC_None,
> /*isInline=*/true, /*isConstexpr=*/false,
> @@ -7612,7 +7596,13 @@
> CopyAssignment->setDefaulted();
> CopyAssignment->setImplicit();
> CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
> -
> +
> + // Build an exception specification pointing back at this member.
> + FunctionProtoType::ExtProtoInfo EPI;
> + EPI.ExceptionSpecType = EST_Unevaluated;
> + EPI.ExceptionSpecDecl = CopyAssignment;
> + CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
> +
> // Add the parameter to the operator.
> ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
> ClassLoc, ClassLoc, /*Id=*/0,
> @@ -7950,9 +7940,10 @@
> }
>
> Sema::ImplicitExceptionSpecification
> -Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {
> - ImplicitExceptionSpecification ExceptSpec(*this);
> +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {
> + CXXRecordDecl *ClassDecl = MD->getParent();
>
> + ImplicitExceptionSpecification ExceptSpec(*this);
> if (ClassDecl->isInvalidDecl())
> return ExceptSpec;
>
> @@ -8120,22 +8111,17 @@
> // Note: The following rules are largely analoguous to the move
> // constructor rules.
>
> - ImplicitExceptionSpecification Spec(
> - ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl));
> -
> QualType ArgType = Context.getTypeDeclType(ClassDecl);
> QualType RetType = Context.getLValueReferenceType(ArgType);
> ArgType = Context.getRValueReferenceType(ArgType);
>
> // An implicitly-declared move assignment operator is an inline public
> // member of its class.
> - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
> DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
> SourceLocation ClassLoc = ClassDecl->getLocation();
> DeclarationNameInfo NameInfo(Name, ClassLoc);
> CXXMethodDecl *MoveAssignment
> - = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
> - Context.getFunctionType(RetType, &ArgType, 1, EPI),
> + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
> /*TInfo=*/0, /*isStatic=*/false,
> /*StorageClassAsWritten=*/SC_None,
> /*isInline=*/true,
> @@ -8146,6 +8132,12 @@
> MoveAssignment->setImplicit();
> MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
>
> + // Build an exception specification pointing back at this member.
> + FunctionProtoType::ExtProtoInfo EPI;
> + EPI.ExceptionSpecType = EST_Unevaluated;
> + EPI.ExceptionSpecDecl = MoveAssignment;
> + MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
> +
> // Add the parameter to the operator.
> ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
> ClassLoc, ClassLoc, /*Id=*/0,
> @@ -8496,10 +8488,12 @@
> }
> }
>
> -std::pair<Sema::ImplicitExceptionSpecification, bool>
> -Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {
> +/// Determine whether an implicit copy constructor for ClassDecl has a const
> +/// argument.
> +/// FIXME: It ought to be possible to store this on the record.
> +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) {
> if (ClassDecl->isInvalidDecl())
> - return std::make_pair(ImplicitExceptionSpecification(*this), true);
> + return true;
>
> // C++ [class.copy]p5:
> // The implicitly-declared copy constructor for a class X will
> @@ -8508,60 +8502,71 @@
> // X::X(const X&)
> //
> // if
> - // FIXME: It ought to be possible to store this on the record.
> - bool HasConstCopyConstructor = true;
> -
> // -- each direct or virtual base class B of X has a copy
> // constructor whose first parameter is of type const B& or
> // const volatile B&, and
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> - HasConstCopyConstructor && Base != BaseEnd;
> - ++Base) {
> + Base != BaseEnd; ++Base) {
> // Virtual bases are handled below.
> if (Base->isVirtual())
> continue;
> -
> +
> CXXRecordDecl *BaseClassDecl
> = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> - HasConstCopyConstructor &=
> - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);
> + // FIXME: This lookup is wrong. If the copy ctor for a member or base is
> + // ambiguous, we should still produce a constructor with a const-qualified
> + // parameter.
> + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
> + return false;
> }
>
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> BaseEnd = ClassDecl->vbases_end();
> - HasConstCopyConstructor && Base != BaseEnd;
> - ++Base) {
> + Base != BaseEnd; ++Base) {
> CXXRecordDecl *BaseClassDecl
> = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> - HasConstCopyConstructor &=
> - (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);
> + if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
> + return false;
> }
> -
> +
> // -- for all the nonstatic data members of X that are of a
> // class type M (or array thereof), each such class type
> // has a copy constructor whose first parameter is of type
> // const M& or const volatile M&.
> for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> FieldEnd = ClassDecl->field_end();
> - HasConstCopyConstructor && Field != FieldEnd;
> - ++Field) {
> - QualType FieldType = Context.getBaseElementType(Field->getType());
> + Field != FieldEnd; ++Field) {
> + QualType FieldType = S.Context.getBaseElementType(Field->getType());
> if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
> - HasConstCopyConstructor &=
> - (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const);
> + if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const))
> + return false;
> }
> }
> +
> // Otherwise, the implicitly declared copy constructor will have
> // the form
> //
> // X::X(X&)
> -
> +
> + return true;
> +}
> +
> +Sema::ImplicitExceptionSpecification
> +Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
> + CXXRecordDecl *ClassDecl = MD->getParent();
> +
> + ImplicitExceptionSpecification ExceptSpec(*this);
> + if (ClassDecl->isInvalidDecl())
> + return ExceptSpec;
> +
> + const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();
> + assert(T->getNumArgs() >= 1 && "not a copy ctor");
> + unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();
> +
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall have an
> // exception-specification. [...]
> - ImplicitExceptionSpecification ExceptSpec(*this);
> - unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> Base != BaseEnd;
> @@ -8599,7 +8604,7 @@
> }
> }
>
> - return std::make_pair(ExceptSpec, HasConstCopyConstructor);
> + return ExceptSpec;
> }
>
> CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
> @@ -8608,18 +8613,12 @@
> // If the class definition does not explicitly declare a copy
> // constructor, one is declared implicitly.
>
> - ImplicitExceptionSpecification Spec(*this);
> - bool Const;
> - llvm::tie(Spec, Const) =
> - ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
> -
> QualType ClassType = Context.getTypeDeclType(ClassDecl);
> QualType ArgType = ClassType;
> + bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl);
> if (Const)
> ArgType = ArgType.withConst();
> ArgType = Context.getLValueReferenceType(ArgType);
> -
> - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
>
> bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
> CXXCopyConstructor,
> @@ -8634,14 +8633,20 @@
> // An implicitly-declared copy constructor is an inline public
> // member of its class.
> CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
> - Context, ClassDecl, ClassLoc, NameInfo,
> - Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
> + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
> /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
> Constexpr);
> CopyConstructor->setAccess(AS_public);
> CopyConstructor->setDefaulted();
> CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
>
> + // Build an exception specification pointing back at this member.
> + FunctionProtoType::ExtProtoInfo EPI;
> + EPI.ExceptionSpecType = EST_Unevaluated;
> + EPI.ExceptionSpecDecl = CopyConstructor;
> + CopyConstructor->setType(
> + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
> +
> // Note that we have declared this constructor.
> ++ASTContext::NumImplicitCopyConstructorsDeclared;
>
> @@ -8705,7 +8710,9 @@
> }
>
> Sema::ImplicitExceptionSpecification
> -Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {
> +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {
> + CXXRecordDecl *ClassDecl = MD->getParent();
> +
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall have an
> // exception-specification. [...]
> @@ -8788,13 +8795,8 @@
> return 0;
> }
>
> - ImplicitExceptionSpecification Spec(
> - ComputeDefaultedMoveCtorExceptionSpec(ClassDecl));
> -
> QualType ClassType = Context.getTypeDeclType(ClassDecl);
> QualType ArgType = Context.getRValueReferenceType(ClassType);
> -
> - FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
>
> bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
> CXXMoveConstructor,
> @@ -8810,14 +8812,20 @@
> // An implicitly-declared copy/move constructor is an inline public
> // member of its class.
> CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
> - Context, ClassDecl, ClassLoc, NameInfo,
> - Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,
> + Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,
> /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
> Constexpr);
> MoveConstructor->setAccess(AS_public);
> MoveConstructor->setDefaulted();
> MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
>
> + // Build an exception specification pointing back at this member.
> + FunctionProtoType::ExtProtoInfo EPI;
> + EPI.ExceptionSpecType = EST_Unevaluated;
> + EPI.ExceptionSpecDecl = MoveConstructor;
> + MoveConstructor->setType(
> + Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
> +
> // Add the parameter to the constructor.
> ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
> ClassLoc, ClassLoc,
> @@ -10427,10 +10435,11 @@
> if (Primary == Primary->getCanonicalDecl())
> return;
>
> + CheckExplicitlyDefaultedSpecialMember(MD);
> +
> switch (Member) {
> case CXXDefaultConstructor: {
> CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
> - CheckExplicitlyDefaultedSpecialMember(CD);
> if (!CD->isInvalidDecl())
> DefineImplicitDefaultConstructor(DefaultLoc, CD);
> break;
> @@ -10438,14 +10447,12 @@
>
> case CXXCopyConstructor: {
> CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
> - CheckExplicitlyDefaultedSpecialMember(CD);
> if (!CD->isInvalidDecl())
> DefineImplicitCopyConstructor(DefaultLoc, CD);
> break;
> }
>
> case CXXCopyAssignment: {
> - CheckExplicitlyDefaultedSpecialMember(MD);
> if (!MD->isInvalidDecl())
> DefineImplicitCopyAssignment(DefaultLoc, MD);
> break;
> @@ -10453,7 +10460,6 @@
>
> case CXXDestructor: {
> CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);
> - CheckExplicitlyDefaultedSpecialMember(DD);
> if (!DD->isInvalidDecl())
> DefineImplicitDestructor(DefaultLoc, DD);
> break;
> @@ -10461,14 +10467,12 @@
>
> case CXXMoveConstructor: {
> CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
> - CheckExplicitlyDefaultedSpecialMember(CD);
> if (!CD->isInvalidDecl())
> DefineImplicitMoveConstructor(DefaultLoc, CD);
> break;
> }
>
> case CXXMoveAssignment: {
> - CheckExplicitlyDefaultedSpecialMember(MD);
> if (!MD->isInvalidDecl())
> DefineImplicitMoveAssignment(DefaultLoc, MD);
> break;
> @@ -10753,7 +10757,7 @@
>
> // Note: The VTableUses vector could grow as a result of marking
> // the members of a class as "used", so we check the size each
> - // time through the loop and prefer indices (with are stable) to
> + // time through the loop and prefer indices (which are stable) to
> // iterators (which are not).
> bool DefinedAnything = false;
> for (unsigned I = 0; I != VTableUses.size(); ++I) {
> @@ -10763,6 +10767,8 @@
>
> SourceLocation Loc = VTableUses[I].second;
>
> + bool DefineVTable = true;
> +
> // If this class has a key function, but that key function is
> // defined in another translation unit, we don't need to emit the
> // vtable even though we're using it.
> @@ -10773,7 +10779,8 @@
> case TSK_ExplicitSpecialization:
> case TSK_ExplicitInstantiationDeclaration:
> // The key function is in another translation unit.
> - continue;
> + DefineVTable = false;
> + break;
>
> case TSK_ExplicitInstantiationDefinition:
> case TSK_ImplicitInstantiation:
> @@ -10802,7 +10809,15 @@
> }
>
> if (IsExplicitInstantiationDeclaration)
> - continue;
> + DefineVTable = false;
> + }
> +
> + // The exception specifications for all virtual members may be needed even
> + // if we are not providing an authoritative form of the vtable in this TU.
> + // We may choose to emit it available_externally anyway.
> + if (!DefineVTable) {
> + MarkVirtualMemberExceptionSpecsNeeded(Loc, Class);
> + continue;
> }
>
> // Mark all of the virtual members of this class as referenced, so
> @@ -10831,6 +10846,14 @@
> return DefinedAnything;
> }
>
> +void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
> + const CXXRecordDecl *RD) {
> + for (CXXRecordDecl::method_iterator I = RD->method_begin(),
> + E = RD->method_end(); I != E; ++I)
> + if ((*I)->isVirtual() && !(*I)->isPure())
> + ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>());
> +}
> +
> void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
> const CXXRecordDecl *RD) {
> // Mark all functions which will appear in RD's vtable as used.
> @@ -11067,8 +11090,8 @@
>
> switch (Proto->getExceptionSpecType()) {
> case EST_Uninstantiated:
> + case EST_Unevaluated:
> case EST_BasicNoexcept:
> - case EST_Delayed:
> case EST_DynamicNone:
> case EST_MSAny:
> case EST_None:
>
> Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Thu Jul 26 23:22:15 2012
> @@ -100,20 +100,22 @@
>
> const FunctionProtoType *
> Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
> - // FIXME: If FD is a special member, we should delay computing its exception
> - // specification until this point.
> - if (FPT->getExceptionSpecType() != EST_Uninstantiated)
> + if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
> return FPT;
>
> FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
> const FunctionProtoType *SourceFPT =
> SourceDecl->getType()->castAs<FunctionProtoType>();
>
> - if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)
> + // If the exception specification has already been resolved, just return it.
> + if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
> return SourceFPT;
>
> - // Instantiate the exception specification now.
> - InstantiateExceptionSpec(Loc, SourceDecl);
> + // Compute or instantiate the exception specification now.
> + if (FPT->getExceptionSpecType() == EST_Unevaluated)
> + EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
> + else
> + InstantiateExceptionSpec(Loc, SourceDecl);
>
> return SourceDecl->getType()->castAs<FunctionProtoType>();
> }
> @@ -346,8 +348,8 @@
> ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
> ExceptionSpecificationType NewEST = New->getExceptionSpecType();
>
> - assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
> - OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&
> + assert(!isUnresolvedExceptionSpec(OldEST) &&
> + !isUnresolvedExceptionSpec(NewEST) &&
> "Shouldn't see unknown exception specifications here");
>
> // Shortcut the case where both have no spec.
> @@ -544,8 +546,8 @@
>
> ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
>
> - assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
> - SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&
> + assert(!isUnresolvedExceptionSpec(SuperEST) &&
> + !isUnresolvedExceptionSpec(SubEST) &&
> "Shouldn't see unknown exception specifications here");
>
> // It does not. If the subset contains everything, we've failed.
> @@ -808,15 +810,6 @@
> if (!FT)
> return CT_Can;
>
> - if (FT->getExceptionSpecType() == EST_Delayed) {
> - // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec.
> - assert(isa<CXXConstructorDecl>(D) &&
> - "only constructor exception specs can be unknown");
> - S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)
> - << E->getSourceRange();
> - return CT_Can;
> - }
> -
> return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
> }
>
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jul 26 23:22:15 2012
> @@ -10224,11 +10224,11 @@
> // FIXME: Is this really right?
> if (CurContext == Func) return;
>
> - // Instantiate the exception specification for any function which is
> + // Resolve the exception specification for any function which is
> // used: CodeGen will need it.
> const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
> - if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)
> - InstantiateExceptionSpec(Loc, Func);
> + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
> + ResolveExceptionSpec(Loc, FPT);
>
> // Implicit instantiation of function templates and member functions of
> // class templates.
>
> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jul 26 23:22:15 2012
> @@ -3190,8 +3190,6 @@
> CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> if (!CPT)
> return false;
> - if (CPT->getExceptionSpecType() == EST_Delayed)
> - return false;
> if (!CPT->isNothrow(Self.Context))
> return false;
> }
> @@ -3232,8 +3230,6 @@
> CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> if (!CPT)
> return false;
> - if (CPT->getExceptionSpecType() == EST_Delayed)
> - return false;
> // FIXME: check whether evaluating default arguments can throw.
> // For now, we'll be conservative and assume that they can throw.
> if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)
> @@ -3270,8 +3266,6 @@
> CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> if (!CPT)
> return false;
> - if (CPT->getExceptionSpecType() == EST_Delayed)
> - return false;
> // TODO: check whether evaluating default arguments can throw.
> // For now, we'll be conservative and assume that they can throw.
> return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Jul 26 23:22:15 2012
> @@ -1996,8 +1996,7 @@
> Instantiator.disableLateAttributeInstantiation();
> LateAttrs.clear();
>
> - if (!FieldsWithMemberInitializers.empty())
> - ActOnFinishDelayedMemberInitializers(Instantiation);
> + ActOnFinishDelayedMemberInitializers(Instantiation);
>
> if (TSK == TSK_ImplicitInstantiation) {
> Instantiation->setLocation(Pattern->getLocation());
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Jul 26 23:22:15 2012
> @@ -2395,8 +2395,17 @@
>
> InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
> InstantiatingTemplate::ExceptionSpecification());
> - if (Inst)
> + if (Inst) {
> + // We hit the instantiation depth limit. Clear the exception specification
> + // so that our callers don't have to cope with EST_Uninstantiated.
> + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
> + EPI.ExceptionSpecType = EST_None;
> + Decl->setType(Context.getFunctionType(Proto->getResultType(),
> + Proto->arg_type_begin(),
> + Proto->getNumArgs(),
> + EPI));
> return;
> + }
>
> // Enter the scope of this instantiation. We don't use
> // PushDeclContext because we don't have a scope.
> @@ -2461,6 +2470,8 @@
> FunctionDecl *ExceptionSpecTemplate = Tmpl;
> if (EPI.ExceptionSpecType == EST_Uninstantiated)
> ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;
> + assert(EPI.ExceptionSpecType != EST_Unevaluated &&
> + "instantiating implicitly-declared special member");
>
> // Mark the function has having an uninstantiated exception specification.
> const FunctionProtoType *NewProto
> @@ -3431,7 +3442,7 @@
> void Sema::PerformPendingInstantiations(bool LocalOnly) {
> // Load pending instantiations from the external source.
> if (!LocalOnly && ExternalSource) {
> - SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending;
> + SmallVector<PendingImplicitInstantiation, 4> Pending;
> ExternalSource->ReadPendingInstantiations(Pending);
> PendingInstantiations.insert(PendingInstantiations.begin(),
> Pending.begin(), Pending.end());
>
> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jul 26 23:22:15 2012
> @@ -3906,6 +3906,8 @@
> } else if (EST == EST_Uninstantiated) {
> EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
> EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
> + } else if (EST == EST_Unevaluated) {
> + EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
> }
> return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
> EPI);
>
> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Jul 26 23:22:15 2012
> @@ -198,6 +198,8 @@
> } else if (T->getExceptionSpecType() == EST_Uninstantiated) {
> Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
> Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record);
> + } else if (T->getExceptionSpecType() == EST_Unevaluated) {
> + Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);
> }
> Code = TYPE_FUNCTION_PROTO;
> }
>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp (original)
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp Thu Jul 26 23:22:15 2012
> @@ -4,9 +4,11 @@
> // [...]
> // -- not have default arguments
> struct DefArg {
> + static DefArg &&make();
> DefArg(int n = 5) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}
> - DefArg(const DefArg &DA = DefArg(2)) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}
> + DefArg(const DefArg &DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}
> DefArg(const DefArg &DA, int k = 3) = default; // expected-error {{an explicitly-defaulted copy constructor cannot have default arguments}}
> + DefArg(DefArg &&DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}
> DefArg(DefArg &&DA, int k = 3) = default; // expected-error {{an explicitly-defaulted move constructor cannot have default arguments}}
> DefArg &operator=(const DefArg&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}}
> DefArg &operator=(DefArg&&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}}
>
> Removed: cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp?rev=160846&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp (removed)
> @@ -1,14 +0,0 @@
> -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
> -
> -bool b();
> -struct S {
> - int n = b() ? S().n + 1 : 0;
> -};
> -
> -S s;
> -
> -// CHECK: define {{.*}} @_ZN1SC2Ev(
> -// CHECK-NOT }
> -// CHECK: call {{.*}} @_Z1bv()
> -// CHECK-NOT }
> -// CHECK: call {{.*}} @_ZN1SC1Ev(
>
> Modified: cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp Thu Jul 26 23:22:15 2012
> @@ -57,3 +57,63 @@
> friend S<bar>::S(const S&);
> friend S<bar>::S(S&&);
> };
> +
> +namespace DefaultedFnExceptionSpec {
> + // DR1330: The exception-specification of an implicitly-declared special
> + // member function is evaluated as needed.
> + template<typename T> T &&declval();
> + template<typename T> struct pair {
> + pair(const pair&) noexcept(noexcept(T(declval<T>())));
> + };
> +
> + struct Y;
> + struct X { X(); X(const Y&); };
> + struct Y { pair<X> p; };
> +
> + template<typename T>
> + struct A {
> + pair<T> p;
> + };
> + struct B {
> + B();
> + B(const A<B>&);
> + };
> +
> + // Don't crash here.
> + void f() {
> + X x = X();
> + (void)noexcept(B(declval<B>()));
> + }
> +
> + template<typename T>
> + struct Error {
> + // FIXME: Type canonicalization causes all the errors to point at the first
> + // declaration which has the type 'void () noexcept (T::error)'. We should
> + // get one error for 'Error<int>::Error()' and one for 'Error<int>::~Error()'.
> + void f() noexcept(T::error); // expected-error 2{{has no members}}
> +
> + Error() noexcept(T::error);
> + Error(const Error&) noexcept(T::error);
> + Error(Error&&) noexcept(T::error);
> + Error &operator=(const Error&) noexcept(T::error);
> + Error &operator=(Error&&) noexcept(T::error);
> + ~Error() noexcept(T::error);
> + };
> +
> + struct DelayImplicit {
> + Error<int> e;
> + };
> +
> + // Don't instantiate the exception specification here.
> + void test1(decltype(declval<DelayImplicit>() = DelayImplicit(DelayImplicit())));
> + void test2(decltype(declval<DelayImplicit>() = declval<const DelayImplicit>()));
> + void test3(decltype(DelayImplicit(declval<const DelayImplicit>())));
> +
> + // Any odr-use causes the exception specification to be evaluated.
> + struct OdrUse { // \
> + expected-note {{instantiation of exception specification for 'Error'}} \
> + expected-note {{instantiation of exception specification for '~Error'}}
> + Error<int> e;
> + };
> + OdrUse use; // expected-note {{implicit default constructor for 'DefaultedFnExceptionSpec::OdrUse' first required here}}
> +}
>
> Modified: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (original)
> +++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Thu Jul 26 23:22:15 2012
> @@ -17,7 +17,7 @@
> // is false.
> bool ThrowSomething() noexcept(false);
> struct ConstExpr {
> - bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}
> + bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot be used by non-static data member initializer}}
> };
> // We can use it now.
> bool w = noexcept(ConstExpr());
> @@ -25,18 +25,27 @@
> // Much more obviously broken: we can't parse the initializer without already
> // knowing whether it produces a noexcept expression.
> struct TemplateArg {
> - int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}
> + int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{cannot be used by non-static data member initializer}}
> };
> bool x = noexcept(TemplateArg());
>
> // And within a nested class.
> + // FIXME: The diagnostic location is terrible here.
> struct Nested {
> struct Inner {
> - int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}
> - } inner;
> + int n = ExceptionIf<noexcept(Nested())>::f();
> + } inner; // expected-error {{cannot be used by non-static data member initializer}}
> };
> bool y = noexcept(Nested());
> bool z = noexcept(Nested::Inner());
> +
> + struct Nested2 {
> + struct Inner;
> + int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}}
> + struct Inner {
> + int n = ExceptionIf<noexcept(Nested())>::f();
> + } inner;
> + };
> }
>
> namespace ExceptionSpecification {
>
> Modified: cfe/trunk/test/SemaCXX/member-init.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/member-init.cpp (original)
> +++ cfe/trunk/test/SemaCXX/member-init.cpp Thu Jul 26 23:22:15 2012
> @@ -14,7 +14,7 @@
> bool b();
> int k;
> struct Recurse {
> - int &n = b() ? Recurse().n : k; // ok
> + int &n = b() ? Recurse().n : k; // expected-error {{defaulted default constructor of 'Recurse' cannot be used by non-static data member initializer which appears before end of class definition}}
> };
>
> struct UnknownBound {
>
> Modified: cfe/trunk/test/SemaCXX/type-traits.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/type-traits.cpp (original)
> +++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jul 26 23:22:15 2012
> @@ -1384,9 +1384,6 @@
> { int arr[F(__has_nothrow_copy(cvoid))]; }
> }
>
> -template<bool b> struct assert_expr;
> -template<> struct assert_expr<true> {};
> -
> void has_nothrow_constructor() {
> { int arr[T(__has_nothrow_constructor(Int))]; }
> { int arr[T(__has_nothrow_constructor(IntAr))]; }
> @@ -1415,11 +1412,6 @@
> { int arr[F(__has_nothrow_constructor(void))]; }
> { int arr[F(__has_nothrow_constructor(cvoid))]; }
> { int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }
> -
> - // While parsing an in-class initializer, the constructor is not known to be
> - // non-throwing yet.
> - struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };
> - { int arr[T(__has_nothrow_constructor(HasInClassInit))]; }
> }
>
> void has_virtual_destructor() {
>
> Modified: cfe/trunk/test/SemaTemplate/instantiation-depth.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-depth.cpp?rev=160847&r1=160846&r2=160847&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiation-depth.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/instantiation-depth.cpp Thu Jul 26 23:22:15 2012
> @@ -2,12 +2,30 @@
> // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth-5 -ftemplate-backtrace-limit=4 %s
> // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s
>
> +#ifndef NOEXCEPT
> +
> template<typename T> struct X : X<T*> { }; \
> // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
> // expected-note 3 {{instantiation of template class}} \
> // expected-note {{skipping 2 contexts in backtrace}} \
> // expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
>
> -void test() {
> +void test() {
> (void)sizeof(X<int>); // expected-note {{instantiation of template class}}
> }
> +
> +#else
> +
> +// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 -std=c++11 -DNOEXCEPT %s
> +
> +template<typename T> struct S {
> + S() noexcept(noexcept(T()));
> +};
> +struct T : S<T> {}; \
> +// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
> +// expected-note 4 {{in instantiation of exception spec}} \
> +// expected-note {{skipping 2 contexts in backtrace}} \
> +// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
> +T t; // expected-note {{implicit default constructor for 'T' first required here}}
> +
> +#endif
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list