<p dir="ltr">A function template or a (non-template) member function of a class temploid. Basically, a thing that can be instantiated to produce a function. This terminology isn't yet in the standard, but core issue 1253 is all about this.</p>

<div class="gmail_quote">On 26 Jul 2012 22:22, "Sean Silva" <<a href="mailto:silvas@purdue.edu">silvas@purdue.edu</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
what is a "function temploid"?<br>
<br>
--Sean Silva<br>
<br>
On Thu, Jul 26, 2012 at 9:22 PM, Richard Smith<br>
<<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>> wrote:<br>
> Author: rsmith<br>
> Date: Thu Jul 26 23:22:15 2012<br>
> New Revision: 160847<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=160847&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=160847&view=rev</a><br>
> Log:<br>
> Final piece of core issue 1330: delay computing the exception specification of<br>
> a defaulted special member function until the exception specification is needed<br>
> (using the same criteria used for the delayed instantiation of exception<br>
> specifications for function temploids).<br>
><br>
> EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like<br>
> EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to<br>
> resolve the exception specification.<br>
><br>
> This is enabled for all C++ modes: it's a little faster in the case where the<br>
> exception specification isn't used, allows our C++11-in-C++98 extensions to<br>
> work, and is still correct for C++98, since in that mode the computation of the<br>
> exception specification can't fail.<br>
><br>
> The diagnostics here aren't great (in particular, we should include implicit<br>
> evaluation of exception specifications for defaulted special members in the<br>
> template instantiation backtraces), but they're not much worse than before.<br>
><br>
> Our approach to the problem of cycles between in-class initializers and the<br>
> exception specification for a defaulted default constructor is modified a<br>
> little by this change -- we now reject any odr-use of a defaulted default<br>
> constructor if that constructor uses an in-class initializer and the use is in<br>
> an in-class initialzer which is declared lexically earlier. This is a closer<br>
> approximation to the current draft solution in core issue 1351, but isn't an<br>
> exact match (but the current draft wording isn't reasonable, so that's to be<br>
> expected).<br>
><br>
> Removed:<br>
>     cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp<br>
> Modified:<br>
>     cfe/trunk/include/clang/AST/Type.h<br>
>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
>     cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h<br>
>     cfe/trunk/include/clang/Sema/DeclSpec.h<br>
>     cfe/trunk/include/clang/Sema/Sema.h<br>
>     cfe/trunk/lib/AST/ASTContext.cpp<br>
>     cfe/trunk/lib/AST/Type.cpp<br>
>     cfe/trunk/lib/Analysis/CFG.cpp<br>
>     cfe/trunk/lib/Sema/SemaDecl.cpp<br>
>     cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
>     cfe/trunk/lib/Sema/SemaExceptionSpec.cpp<br>
>     cfe/trunk/lib/Sema/SemaExpr.cpp<br>
>     cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
>     cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
>     cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
>     cfe/trunk/lib/Serialization/ASTReader.cpp<br>
>     cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
>     cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp<br>
>     cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp<br>
>     cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp<br>
>     cfe/trunk/test/SemaCXX/member-init.cpp<br>
>     cfe/trunk/test/SemaCXX/type-traits.cpp<br>
>     cfe/trunk/test/SemaTemplate/instantiation-depth.cpp<br>
><br>
> Modified: cfe/trunk/include/clang/AST/Type.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/AST/Type.h (original)<br>
> +++ cfe/trunk/include/clang/AST/Type.h Thu Jul 26 23:22:15 2012<br>
> @@ -2847,6 +2847,8 @@<br>
>      } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
>        EPI.ExceptionSpecDecl = getExceptionSpecDecl();<br>
>        EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();<br>
> +    } else if (EPI.ExceptionSpecType == EST_Unevaluated) {<br>
> +      EPI.ExceptionSpecDecl = getExceptionSpecDecl();<br>
>      }<br>
>      if (hasAnyConsumedArgs())<br>
>        EPI.ConsumedArguments = getConsumedArgsBuffer();<br>
> @@ -2890,11 +2892,13 @@<br>
>      // NoexceptExpr sits where the arguments end.<br>
>      return *reinterpret_cast<Expr *const *>(arg_type_end());<br>
>    }<br>
> -  /// \brief If this function type has an uninstantiated exception<br>
> -  /// specification, this is the function whose exception specification<br>
> -  /// is represented by this type.<br>
> +  /// \brief If this function type has an exception specification which hasn't<br>
> +  /// been determined yet (either because it has not been evaluated or because<br>
> +  /// it has not been instantiated), this is the function whose exception<br>
> +  /// specification is represented by this type.<br>
>    FunctionDecl *getExceptionSpecDecl() const {<br>
> -    if (getExceptionSpecType() != EST_Uninstantiated)<br>
> +    if (getExceptionSpecType() != EST_Uninstantiated &&<br>
> +        getExceptionSpecType() != EST_Unevaluated)<br>
>        return 0;<br>
>      return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];<br>
>    }<br>
> @@ -2909,7 +2913,7 @@<br>
>    }<br>
>    bool isNothrow(ASTContext &Ctx) const {<br>
>      ExceptionSpecificationType EST = getExceptionSpecType();<br>
> -    assert(EST != EST_Delayed && EST != EST_Uninstantiated);<br>
> +    assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);<br>
>      if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)<br>
>        return true;<br>
>      if (EST != EST_ComputedNoexcept)<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 26 23:22:15 2012<br>
> @@ -870,8 +870,6 @@<br>
>    "%0 is missing exception specification '%1'">;<br>
>  def err_noexcept_needs_constant_expression : Error<<br>
>    "argument to noexcept specifier must be a constant expression">;<br>
> -def err_exception_spec_unknown : Error<<br>
> -  "exception specification is not available until end of class definition">;<br>
><br>
>  // C++ access checking<br>
>  def err_class_redeclared_with_different_access : Error<<br>
> @@ -5088,6 +5086,9 @@<br>
>    "'constexpr' specifier">;<br>
>  def err_in_class_initializer_non_constant : Error<<br>
>    "in-class initializer for static data member is not a constant expression">;<br>
> +def err_in_class_initializer_references_def_ctor : Error<<br>
> +  "defaulted default constructor of %0 cannot be used by non-static data "<br>
> +  "member initializer which appears before end of class definition">;<br>
><br>
>  def ext_in_class_initializer_non_constant : Extension<<br>
>    "in-class initializer for static data member is not a constant expression; "<br>
><br>
> Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)<br>
> +++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Thu Jul 26 23:22:15 2012<br>
> @@ -25,7 +25,7 @@<br>
>    EST_MSAny,            ///< Microsoft throw(...) extension<br>
>    EST_BasicNoexcept,    ///< noexcept<br>
>    EST_ComputedNoexcept, ///< noexcept(expression)<br>
> -  EST_Delayed,          ///< not known yet<br>
> +  EST_Unevaluated,      ///< not evaluated yet, for special member function<br>
>    EST_Uninstantiated    ///< not instantiated yet<br>
>  };<br>
><br>
> @@ -37,6 +37,10 @@<br>
>    return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept;<br>
>  }<br>
><br>
> +inline bool isUnresolvedExceptionSpec(ExceptionSpecificationType ESpecType) {<br>
> +  return ESpecType == EST_Unevaluated || ESpecType == EST_Uninstantiated;<br>
> +}<br>
> +<br>
>  /// \brief Possible results from evaluation of a noexcept expression.<br>
>  enum CanThrowResult {<br>
>    CT_Cannot,<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Thu Jul 26 23:22:15 2012<br>
> @@ -1152,8 +1152,7 @@<br>
>      /// any.<br>
>      unsigned MutableLoc;<br>
><br>
> -    /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the<br>
> -    /// location of the keyword introducing the spec.<br>
> +    /// \brief The location of the keyword introducing the spec, if any.<br>
>      unsigned ExceptionSpecLoc;<br>
><br>
>      /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that<br>
><br>
> Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
> +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 26 23:22:15 2012<br>
> @@ -3335,17 +3335,6 @@<br>
>      /// \brief Integrate an invoked expression into the collected data.<br>
>      void CalledExpr(Expr *E);<br>
><br>
> -    /// \brief Specify that the exception specification can't be detemined yet.<br>
> -    void SetDelayed() {<br>
> -      ClearExceptions();<br>
> -      ComputedEST = EST_Delayed;<br>
> -    }<br>
> -<br>
> -    /// \brief Have we been unable to compute this exception specification?<br>
> -    bool isDelayed() {<br>
> -      return ComputedEST == EST_Delayed;<br>
> -    }<br>
> -<br>
>      /// \brief Overwrite an EPI's exception specification with this<br>
>      /// computed exception specification.<br>
>      void getEPI(FunctionProtoType::ExtProtoInfo &EPI) const {<br>
> @@ -3363,34 +3352,39 @@<br>
>    /// \brief Determine what sort of exception specification a defaulted<br>
>    /// copy constructor of a class will have.<br>
>    ImplicitExceptionSpecification<br>
> -  ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl);<br>
> +  ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,<br>
> +                                           CXXMethodDecl *MD);<br>
><br>
>    /// \brief Determine what sort of exception specification a defaulted<br>
>    /// default constructor of a class will have, and whether the parameter<br>
>    /// will be const.<br>
> -  std::pair<ImplicitExceptionSpecification, bool><br>
> -  ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl);<br>
> +  ImplicitExceptionSpecification<br>
> +  ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD);<br>
><br>
>    /// \brief Determine what sort of exception specification a defautled<br>
>    /// copy assignment operator of a class will have, and whether the<br>
>    /// parameter will be const.<br>
> -  std::pair<ImplicitExceptionSpecification, bool><br>
> -  ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl);<br>
> +  ImplicitExceptionSpecification<br>
> +  ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD);<br>
><br>
>    /// \brief Determine what sort of exception specification a defaulted move<br>
>    /// constructor of a class will have.<br>
>    ImplicitExceptionSpecification<br>
> -  ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl);<br>
> +  ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD);<br>
><br>
>    /// \brief Determine what sort of exception specification a defaulted move<br>
>    /// assignment operator of a class will have.<br>
>    ImplicitExceptionSpecification<br>
> -  ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl);<br>
> +  ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD);<br>
><br>
>    /// \brief Determine what sort of exception specification a defaulted<br>
>    /// destructor of a class will have.<br>
>    ImplicitExceptionSpecification<br>
> -  ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);<br>
> +  ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD);<br>
> +<br>
> +  /// \brief Evaluate the implicit exception specification for a defaulted<br>
> +  /// special member function.<br>
> +  void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD);<br>
><br>
>    /// \brief Check the given exception-specification and update the<br>
>    /// extended prototype information with the results.<br>
> @@ -3438,8 +3432,7 @@<br>
>    /// C++11 says that user-defined destructors with no exception spec get one<br>
>    /// that looks as if the destructor was implicitly declared.<br>
>    void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,<br>
> -                                     CXXDestructorDecl *Destructor,<br>
> -                                     bool WasDelayed = false);<br>
> +                                     CXXDestructorDecl *Destructor);<br>
><br>
>    /// \brief Declare all inherited constructors for the given class.<br>
>    ///<br>
> @@ -4262,6 +4255,11 @@<br>
>    void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,<br>
>                        bool DefinitionRequired = false);<br>
><br>
> +  /// \brief Mark the exception specifications of all virtual member functions<br>
> +  /// in the given class as needed.<br>
> +  void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,<br>
> +                                             const CXXRecordDecl *RD);<br>
> +<br>
>    /// MarkVirtualMembersReferenced - Will mark all members of the given<br>
>    /// CXXRecordDecl referenced.<br>
>    void MarkVirtualMembersReferenced(SourceLocation Loc,<br>
><br>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
> +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -2367,15 +2367,18 @@<br>
>    //  - exception types<br>
>    //  - consumed-arguments flags<br>
>    // Instead of the exception types, there could be a noexcept<br>
> -  // expression.<br>
> +  // expression, or information used to resolve the exception<br>
> +  // specification.<br>
>    size_t Size = sizeof(FunctionProtoType) +<br>
>                  NumArgs * sizeof(QualType);<br>
> -  if (EPI.ExceptionSpecType == EST_Dynamic)<br>
> +  if (EPI.ExceptionSpecType == EST_Dynamic) {<br>
>      Size += EPI.NumExceptions * sizeof(QualType);<br>
> -  else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {<br>
> +  } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {<br>
>      Size += sizeof(Expr*);<br>
>    } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {<br>
>      Size += 2 * sizeof(FunctionDecl*);<br>
> +  } else if (EPI.ExceptionSpecType == EST_Unevaluated) {<br>
> +    Size += sizeof(FunctionDecl*);<br>
>    }<br>
>    if (EPI.ConsumedArguments)<br>
>      Size += NumArgs * sizeof(bool);<br>
><br>
> Modified: cfe/trunk/lib/AST/Type.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/AST/Type.cpp (original)<br>
> +++ cfe/trunk/lib/AST/Type.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -1584,6 +1584,11 @@<br>
>      slot[1] = epi.ExceptionSpecTemplate;<br>
>      // This exception specification doesn't make the type dependent, because<br>
>      // it's not instantiated as part of instantiating the type.<br>
> +  } else if (getExceptionSpecType() == EST_Unevaluated) {<br>
> +    // Store the function decl from which we will resolve our<br>
> +    // exception specification.<br>
> +    FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);<br>
> +    slot[0] = epi.ExceptionSpecDecl;<br>
>    }<br>
><br>
>    if (epi.ConsumedArguments) {<br>
> @@ -1667,7 +1672,8 @@<br>
>        ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());<br>
>    } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){<br>
>      epi.NoexceptExpr->Profile(ID, Context, false);<br>
> -  } else if (epi.ExceptionSpecType == EST_Uninstantiated) {<br>
> +  } else if (epi.ExceptionSpecType == EST_Uninstantiated ||<br>
> +             epi.ExceptionSpecType == EST_Unevaluated) {<br>
>      ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());<br>
>    }<br>
>    if (epi.ConsumedArguments) {<br>
><br>
> Modified: cfe/trunk/lib/Analysis/CFG.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Analysis/CFG.cpp (original)<br>
> +++ cfe/trunk/lib/Analysis/CFG.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -1340,7 +1340,7 @@<br>
>    const FunctionType *FT = Ty->getAs<FunctionType>();<br>
>    if (FT) {<br>
>      if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))<br>
> -      if (Proto->getExceptionSpecType() != EST_Uninstantiated &&<br>
> +      if (!isUnresolvedExceptionSpec(Proto->getExceptionSpecType()) &&<br>
>            Proto->isNothrow(Ctx))<br>
>          return false;<br>
>    }<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -4655,11 +4655,6 @@<br>
>    return false;<br>
>  }<br>
><br>
> -static bool hasDelayedExceptionSpec(CXXMethodDecl *Method) {<br>
> -  const FunctionProtoType *Proto =Method->getType()->getAs<FunctionProtoType>();<br>
> -  return Proto && Proto->getExceptionSpecType() == EST_Delayed;<br>
> -}<br>
> -<br>
>  /// AddOverriddenMethods - See if a method overrides any in the base classes,<br>
>  /// and if so, check that it's a valid override and remember it.<br>
>  bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {<br>
> @@ -4675,8 +4670,7 @@<br>
>        if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {<br>
>          MD->addOverriddenMethod(OldMD->getCanonicalDecl());<br>
>          if (!CheckOverridingFunctionReturnType(MD, OldMD) &&<br>
> -            (hasDelayedExceptionSpec(MD) ||<br>
> -             !CheckOverridingFunctionExceptionSpec(MD, OldMD)) &&<br>
> +            !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&<br>
>              !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {<br>
>            AddedAny = true;<br>
>          }<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -128,8 +128,8 @@<br>
><br>
>  void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,<br>
>                                                        CXXMethodDecl *Method) {<br>
> -  // If we have an MSAny or unknown spec already, don't bother.<br>
> -  if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)<br>
> +  // If we have an MSAny spec already, don't bother.<br>
> +  if (!Method || ComputedEST == EST_MSAny)<br>
>      return;<br>
><br>
>    const FunctionProtoType *Proto<br>
> @@ -141,7 +141,7 @@<br>
>    ExceptionSpecificationType EST = Proto->getExceptionSpecType();<br>
><br>
>    // If this function can throw any exceptions, make a note of that.<br>
> -  if (EST == EST_Delayed || EST == EST_MSAny || EST == EST_None) {<br>
> +  if (EST == EST_MSAny || EST == EST_None) {<br>
>      ClearExceptions();<br>
>      ComputedEST = EST;<br>
>      return;<br>
> @@ -198,7 +198,7 @@<br>
>  }<br>
><br>
>  void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) {<br>
> -  if (!E || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)<br>
> +  if (!E || ComputedEST == EST_MSAny)<br>
>      return;<br>
><br>
>    // FIXME:<br>
> @@ -3881,9 +3881,6 @@<br>
>    //   instantiated (e.g. meta-functions). This doesn't apply to classes that<br>
>    //   have inherited constructors.<br>
>    DeclareInheritedConstructors(Record);<br>
> -<br>
> -  if (!Record->isDependentType())<br>
> -    CheckExplicitlyDefaultedMethods(Record);<br>
>  }<br>
><br>
>  void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {<br>
> @@ -3989,6 +3986,45 @@<br>
>    return true;<br>
>  }<br>
><br>
> +static Sema::ImplicitExceptionSpecification<br>
> +computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {<br>
> +  switch (S.getSpecialMember(MD)) {<br>
> +  case Sema::CXXDefaultConstructor:<br>
> +    return S.ComputeDefaultedDefaultCtorExceptionSpec(Loc, MD);<br>
> +  case Sema::CXXCopyConstructor:<br>
> +    return S.ComputeDefaultedCopyCtorExceptionSpec(MD);<br>
> +  case Sema::CXXCopyAssignment:<br>
> +    return S.ComputeDefaultedCopyAssignmentExceptionSpec(MD);<br>
> +  case Sema::CXXMoveConstructor:<br>
> +    return S.ComputeDefaultedMoveCtorExceptionSpec(MD);<br>
> +  case Sema::CXXMoveAssignment:<br>
> +    return S.ComputeDefaultedMoveAssignmentExceptionSpec(MD);<br>
> +  case Sema::CXXDestructor:<br>
> +    return S.ComputeDefaultedDtorExceptionSpec(MD);<br>
> +  case Sema::CXXInvalid:<br>
> +    break;<br>
> +  }<br>
> +  llvm_unreachable("only special members have implicit exception specs");<br>
> +}<br>
> +<br>
> +void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {<br>
> +  const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();<br>
> +  if (FPT->getExceptionSpecType() != EST_Unevaluated)<br>
> +    return;<br>
> +<br>
> +  // Evaluate the exception specification and update the type of the special<br>
> +  // member to use it.<br>
> +  FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();<br>
> +  computeImplicitExceptionSpec(*this, Loc, MD).getEPI(EPI);<br>
> +  const FunctionProtoType *NewFPT = cast<FunctionProtoType>(<br>
> +    Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),<br>
> +                            FPT->getNumArgs(), EPI));<br>
> +  MD->setType(QualType(NewFPT, 0));<br>
> +}<br>
> +<br>
> +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl);<br>
> +static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl);<br>
> +<br>
>  void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {<br>
>    CXXRecordDecl *RD = MD->getParent();<br>
>    CXXSpecialMember CSM = getSpecialMember(MD);<br>
> @@ -4023,40 +4059,28 @@<br>
><br>
>    const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();<br>
><br>
> -  // Compute implicit exception specification, argument constness, constexpr<br>
> -  // and triviality.<br>
> -  ImplicitExceptionSpecification Spec(*this);<br>
> +  // Compute argument constness, constexpr, and triviality.<br>
>    bool CanHaveConstParam = false;<br>
>    bool Trivial;<br>
>    switch (CSM) {<br>
>    case CXXDefaultConstructor:<br>
> -    Spec = ComputeDefaultedDefaultCtorExceptionSpec(RD);<br>
> -    if (Spec.isDelayed())<br>
> -      // Exception specification depends on some deferred part of the class.<br>
> -      // We'll try again when the class's definition has been fully processed.<br>
> -      return;<br>
>      Trivial = RD->hasTrivialDefaultConstructor();<br>
>      break;<br>
>    case CXXCopyConstructor:<br>
> -    llvm::tie(Spec, CanHaveConstParam) =<br>
> -      ComputeDefaultedCopyCtorExceptionSpecAndConst(RD);<br>
> +    CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD);<br>
>      Trivial = RD->hasTrivialCopyConstructor();<br>
>      break;<br>
>    case CXXCopyAssignment:<br>
> -    llvm::tie(Spec, CanHaveConstParam) =<br>
> -      ComputeDefaultedCopyAssignmentExceptionSpecAndConst(RD);<br>
> +    CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD);<br>
>      Trivial = RD->hasTrivialCopyAssignment();<br>
>      break;<br>
>    case CXXMoveConstructor:<br>
> -    Spec = ComputeDefaultedMoveCtorExceptionSpec(RD);<br>
>      Trivial = RD->hasTrivialMoveConstructor();<br>
>      break;<br>
>    case CXXMoveAssignment:<br>
> -    Spec = ComputeDefaultedMoveAssignmentExceptionSpec(RD);<br>
>      Trivial = RD->hasTrivialMoveAssignment();<br>
>      break;<br>
>    case CXXDestructor:<br>
> -    Spec = ComputeDefaultedDtorExceptionSpec(RD);<br>
>      Trivial = RD->hasTrivialDestructor();<br>
>      break;<br>
>    case CXXInvalid:<br>
> @@ -4126,11 +4150,15 @@<br>
>      HadError = true;<br>
>    }<br>
><br>
> -  // Rebuild the type with the implicit exception specification added.<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();<br>
> -  Spec.getEPI(EPI);<br>
> -  const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(<br>
> -    Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));<br>
> +  // Rebuild the type with the implicit exception specification added, if we<br>
> +  // are going to need it.<br>
> +  const FunctionProtoType *ImplicitType = 0;<br>
> +  if (First || Type->hasExceptionSpec()) {<br>
> +    FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();<br>
> +    computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);<br>
> +    ImplicitType = cast<FunctionProtoType>(<br>
> +      Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));<br>
> +  }<br>
><br>
>    // C++11 [dcl.fct.def.default]p2:<br>
>    //   An explicitly-defaulted function may be declared constexpr only if it<br>
> @@ -6685,7 +6713,10 @@<br>
>  }<br>
><br>
>  Sema::ImplicitExceptionSpecification<br>
> -Sema::ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl) {<br>
> +Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,<br>
> +                                               CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
> +<br>
>    // C++ [except.spec]p14:<br>
>    //   An implicitly declared special member function (Clause 12) shall have an<br>
>    //   exception-specification. [...]<br>
> @@ -6732,7 +6763,21 @@<br>
>        if (Expr *E = F->getInClassInitializer())<br>
>          ExceptSpec.CalledExpr(E);<br>
>        else if (!F->isInvalidDecl())<br>
> -        ExceptSpec.SetDelayed();<br>
> +        // DR1351:<br>
> +        //   If the brace-or-equal-initializer of a non-static data member<br>
> +        //   invokes a defaulted default constructor of its class or of an<br>
> +        //   enclosing class in a potentially evaluated subexpression, the<br>
> +        //   program is ill-formed.<br>
> +        //<br>
> +        // This resolution is unworkable: the exception specification of the<br>
> +        // default constructor can be needed in an unevaluated context, in<br>
> +        // particular, in the operand of a noexcept-expression, and we can be<br>
> +        // unable to compute an exception specification for an enclosed class.<br>
> +        //<br>
> +        // We do not allow an in-class initializer to require the evaluation<br>
> +        // of the exception specification for any in-class initializer whose<br>
> +        // definition is not lexically complete.<br>
> +        Diag(Loc, diag::err_in_class_initializer_references_def_ctor) << MD;<br>
>      } else if (const RecordType *RecordTy<br>
>                = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {<br>
>        CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());<br>
> @@ -6761,10 +6806,6 @@<br>
>    assert(!ClassDecl->hasUserDeclaredConstructor() &&<br>
>           "Should not build implicit default constructor!");<br>
><br>
> -  ImplicitExceptionSpecification Spec =<br>
> -    ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
> -<br>
>    bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,<br>
>                                                       CXXDefaultConstructor,<br>
>                                                       false);<br>
> @@ -6777,15 +6818,20 @@<br>
>      = Context.DeclarationNames.getCXXConstructorName(ClassType);<br>
>    DeclarationNameInfo NameInfo(Name, ClassLoc);<br>
>    CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(<br>
> -      Context, ClassDecl, ClassLoc, NameInfo,<br>
> -      Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0,<br>
> +      Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(), /*TInfo=*/0,<br>
>        /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,<br>
>        Constexpr);<br>
>    DefaultCon->setAccess(AS_public);<br>
>    DefaultCon->setDefaulted();<br>
>    DefaultCon->setImplicit();<br>
>    DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());<br>
> -<br>
> +<br>
> +  // Build an exception specification pointing back at this constructor.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = DefaultCon;<br>
> +  DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));<br>
> +<br>
>    // Note that we have declared this constructor.<br>
>    ++ASTContext::NumImplicitDefaultConstructorsDeclared;<br>
><br>
> @@ -6830,58 +6876,14 @@<br>
>    }<br>
>  }<br>
><br>
> -/// Get any existing defaulted default constructor for the given class. Do not<br>
> -/// implicitly define one if it does not exist.<br>
> -static CXXConstructorDecl *getDefaultedDefaultConstructorUnsafe(Sema &Self,<br>
> -                                                             CXXRecordDecl *D) {<br>
> -  ASTContext &Context = Self.Context;<br>
> -  QualType ClassType = Context.getTypeDeclType(D);<br>
> -  DeclarationName ConstructorName<br>
> -    = Context.DeclarationNames.getCXXConstructorName(<br>
> -                      Context.getCanonicalType(ClassType.getUnqualifiedType()));<br>
> -<br>
> -  DeclContext::lookup_const_iterator Con, ConEnd;<br>
> -  for (llvm::tie(Con, ConEnd) = D->lookup(ConstructorName);<br>
> -       Con != ConEnd; ++Con) {<br>
> -    // A function template cannot be defaulted.<br>
> -    if (isa<FunctionTemplateDecl>(*Con))<br>
> -      continue;<br>
> -<br>
> -    CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);<br>
> -    if (Constructor->isDefaultConstructor())<br>
> -      return Constructor->isDefaulted() ? Constructor : 0;<br>
> -  }<br>
> -  return 0;<br>
> -}<br>
> -<br>
>  void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {<br>
>    if (!D) return;<br>
>    AdjustDeclIfTemplate(D);<br>
><br>
>    CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);<br>
> -  CXXConstructorDecl *CtorDecl<br>
> -    = getDefaultedDefaultConstructorUnsafe(*this, ClassDecl);<br>
> -<br>
> -  if (!CtorDecl) return;<br>
><br>
> -  // Compute the exception specification for the default constructor.<br>
> -  const FunctionProtoType *CtorTy =<br>
> -    CtorDecl->getType()->castAs<FunctionProtoType>();<br>
> -  if (CtorTy->getExceptionSpecType() == EST_Delayed) {<br>
> -    // FIXME: Don't do this unless the exception spec is needed.<br>
> -    ImplicitExceptionSpecification Spec =<br>
> -      ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);<br>
> -    FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
> -    assert(EPI.ExceptionSpecType != EST_Delayed);<br>
> -<br>
> -    CtorDecl->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));<br>
> -  }<br>
> -<br>
> -  // If the default constructor is explicitly defaulted, checking the exception<br>
> -  // specification is deferred until now.<br>
> -  if (!CtorDecl->isInvalidDecl() && CtorDecl->isExplicitlyDefaulted() &&<br>
> -      !ClassDecl->isDependentType())<br>
> -    CheckExplicitlyDefaultedSpecialMember(CtorDecl);<br>
> +  if (!ClassDecl->isDependentType())<br>
> +    CheckExplicitlyDefaultedMethods(ClassDecl);<br>
>  }<br>
><br>
>  void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {<br>
> @@ -7065,7 +7067,9 @@<br>
>  }<br>
><br>
>  Sema::ImplicitExceptionSpecification<br>
> -Sema::ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl) {<br>
> +Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
> +<br>
>    // C++ [except.spec]p14:<br>
>    //   An implicitly declared special member function (Clause 12) shall have<br>
>    //   an exception-specification.<br>
> @@ -7112,14 +7116,8 @@<br>
>    //   If a class has no user-declared destructor, a destructor is<br>
>    //   declared implicitly. An implicitly-declared destructor is an<br>
>    //   inline public member of its class.<br>
> -<br>
> -  ImplicitExceptionSpecification Spec =<br>
> -      ComputeDefaultedDtorExceptionSpec(ClassDecl);<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
><br>
>    // Create the actual destructor declaration.<br>
> -  QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI);<br>
> -<br>
>    CanQualType ClassType<br>
>      = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));<br>
>    SourceLocation ClassLoc = ClassDecl->getLocation();<br>
> @@ -7127,24 +7125,27 @@<br>
>      = Context.DeclarationNames.getCXXDestructorName(ClassType);<br>
>    DeclarationNameInfo NameInfo(Name, ClassLoc);<br>
>    CXXDestructorDecl *Destructor<br>
> -      = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0,<br>
> -                                  /*isInline=*/true,<br>
> +      = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,<br>
> +                                  QualType(), 0, /*isInline=*/true,<br>
>                                    /*isImplicitlyDeclared=*/true);<br>
>    Destructor->setAccess(AS_public);<br>
>    Destructor->setDefaulted();<br>
>    Destructor->setImplicit();<br>
>    Destructor->setTrivial(ClassDecl->hasTrivialDestructor());<br>
> -<br>
> +<br>
> +  // Build an exception specification pointing back at this destructor.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = Destructor;<br>
> +  Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));<br>
> +<br>
>    // Note that we have declared this destructor.<br>
>    ++ASTContext::NumImplicitDestructorsDeclared;<br>
> -<br>
> +<br>
>    // Introduce this destructor into its scope.<br>
>    if (Scope *S = getScopeForContext(ClassDecl))<br>
>      PushOnScopeChains(Destructor, S, false);<br>
>    ClassDecl->addDecl(Destructor);<br>
> -<br>
> -  // This could be uniqued if it ever proves significant.<br>
> -  Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty));<br>
><br>
>    AddOverriddenMethods(ClassDecl, Destructor);<br>
><br>
> @@ -7194,15 +7195,6 @@<br>
>  /// \brief Perform any semantic analysis which needs to be delayed until all<br>
>  /// pending class member declarations have been parsed.<br>
>  void Sema::ActOnFinishCXXMemberDecls() {<br>
> -  // Now we have parsed all exception specifications, determine the implicit<br>
> -  // exception specifications for destructors.<br>
> -  for (unsigned i = 0, e = DelayedDestructorExceptionSpecs.size();<br>
> -       i != e; ++i) {<br>
> -    CXXDestructorDecl *Dtor = DelayedDestructorExceptionSpecs[i];<br>
> -    AdjustDestructorExceptionSpec(Dtor->getParent(), Dtor, true);<br>
> -  }<br>
> -  DelayedDestructorExceptionSpecs.clear();<br>
> -<br>
>    // Perform any deferred checking of exception specifications for virtual<br>
>    // destructors.<br>
>    for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();<br>
> @@ -7217,44 +7209,33 @@<br>
>    DelayedDestructorExceptionSpecChecks.clear();<br>
>  }<br>
><br>
> -void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *classDecl,<br>
> -                                         CXXDestructorDecl *destructor,<br>
> -                                         bool WasDelayed) {<br>
> +void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,<br>
> +                                         CXXDestructorDecl *Destructor) {<br>
> +  assert(getLangOpts().CPlusPlus0x &&<br>
> +         "adjusting dtor exception specs was introduced in c++11");<br>
> +<br>
>    // C++11 [class.dtor]p3:<br>
>    //   A declaration of a destructor that does not have an exception-<br>
>    //   specification is implicitly considered to have the same exception-<br>
>    //   specification as an implicit declaration.<br>
> -  const FunctionProtoType *dtorType = destructor->getType()-><br>
> +  const FunctionProtoType *DtorType = Destructor->getType()-><br>
>                                          getAs<FunctionProtoType>();<br>
> -  if (!WasDelayed && dtorType->hasExceptionSpec())<br>
> +  if (DtorType->hasExceptionSpec())<br>
>      return;<br>
><br>
> -  ImplicitExceptionSpecification exceptSpec =<br>
> -      ComputeDefaultedDtorExceptionSpec(classDecl);<br>
> -<br>
>    // Replace the destructor's type, building off the existing one. Fortunately,<br>
>    // the only thing of interest in the destructor type is its extended info.<br>
>    // The return and arguments are fixed.<br>
> -  FunctionProtoType::ExtProtoInfo epi = dtorType->getExtProtoInfo();<br>
> -  epi.ExceptionSpecType = exceptSpec.getExceptionSpecType();<br>
> -  epi.NumExceptions = exceptSpec.size();<br>
> -  epi.Exceptions = exceptSpec.data();<br>
> -  QualType ty = Context.getFunctionType(Context.VoidTy, 0, 0, epi);<br>
> -<br>
> -  destructor->setType(ty);<br>
> -<br>
> -  // If we can't compute the exception specification for this destructor yet<br>
> -  // (because it depends on an exception specification which we have not parsed<br>
> -  // yet), make a note that we need to try again when the class is complete.<br>
> -  if (epi.ExceptionSpecType == EST_Delayed) {<br>
> -    assert(!WasDelayed && "couldn't compute destructor exception spec");<br>
> -    DelayedDestructorExceptionSpecs.push_back(destructor);<br>
> -  }<br>
> +  FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = Destructor;<br>
> +  Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));<br>
><br>
>    // FIXME: If the destructor has a body that could throw, and the newly created<br>
>    // spec doesn't allow exceptions, we should emit a warning, because this<br>
>    // change in behavior can break conforming C++03 programs at runtime.<br>
> -  // However, we don't have a body yet, so it needs to be done somewhere else.<br>
> +  // However, we don't have a body or an exception specification yet, so it<br>
> +  // needs to be done somewhere else.<br>
>  }<br>
><br>
>  /// \brief Builds a statement that copies/moves the given entity from \p From to<br>
> @@ -7456,11 +7437,13 @@<br>
>                          Loc, Copy.take());<br>
>  }<br>
><br>
> -std::pair<Sema::ImplicitExceptionSpecification, bool><br>
> -Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(<br>
> -                                                   CXXRecordDecl *ClassDecl) {<br>
> +/// Determine whether an implicit copy assignment operator for ClassDecl has a<br>
> +/// const argument.<br>
> +/// FIXME: It ought to be possible to store this on the record.<br>
> +static bool isImplicitCopyAssignmentArgConst(Sema &S,<br>
> +                                             CXXRecordDecl *ClassDecl) {<br>
>    if (ClassDecl->isInvalidDecl())<br>
> -    return std::make_pair(ImplicitExceptionSpecification(*this), true);<br>
> +    return true;<br>
><br>
>    // C++ [class.copy]p10:<br>
>    //   If the class definition does not explicitly declare a copy<br>
> @@ -7471,37 +7454,34 @@<br>
>    //       X& X::operator=(const X&)<br>
>    //<br>
>    //   if<br>
> -  bool HasConstCopyAssignment = true;<br>
> -<br>
>    //       -- each direct base class B of X has a copy assignment operator<br>
>    //          whose parameter is of type const B&, const volatile B& or B,<br>
>    //          and<br>
>    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
>                                         BaseEnd = ClassDecl->bases_end();<br>
> -       HasConstCopyAssignment && Base != BaseEnd; ++Base) {<br>
> +       Base != BaseEnd; ++Base) {<br>
>      // We'll handle this below<br>
> -    if (LangOpts.CPlusPlus0x && Base->isVirtual())<br>
> +    if (S.getLangOpts().CPlusPlus0x && Base->isVirtual())<br>
>        continue;<br>
><br>
>      assert(!Base->getType()->isDependentType() &&<br>
>             "Cannot generate implicit members for class with dependent bases.");<br>
>      CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();<br>
> -    HasConstCopyAssignment &=<br>
> -      (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,<br>
> -                                    false, 0);<br>
> +    if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0))<br>
> +      return false;<br>
>    }<br>
><br>
>    // In C++11, the above citation has "or virtual" added<br>
> -  if (LangOpts.CPlusPlus0x) {<br>
> +  if (S.getLangOpts().CPlusPlus0x) {<br>
>      for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
>                                           BaseEnd = ClassDecl->vbases_end();<br>
> -         HasConstCopyAssignment && Base != BaseEnd; ++Base) {<br>
> +         Base != BaseEnd; ++Base) {<br>
>        assert(!Base->getType()->isDependentType() &&<br>
>               "Cannot generate implicit members for class with dependent bases.");<br>
>        CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();<br>
> -      HasConstCopyAssignment &=<br>
> -        (bool)LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,<br>
> -                                      false, 0);<br>
> +      if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,<br>
> +                                     false, 0))<br>
> +        return false;<br>
>      }<br>
>    }<br>
><br>
> @@ -7511,23 +7491,36 @@<br>
>    //          const volatile M& or M.<br>
>    for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),<br>
>                                    FieldEnd = ClassDecl->field_end();<br>
> -       HasConstCopyAssignment && Field != FieldEnd;<br>
> -       ++Field) {<br>
> -    QualType FieldType = Context.getBaseElementType(Field->getType());<br>
> -    if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
> -      HasConstCopyAssignment &=<br>
> -        (bool)LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,<br>
> -                                      false, 0);<br>
> -    }<br>
> +       Field != FieldEnd; ++Field) {<br>
> +    QualType FieldType = S.Context.getBaseElementType(Field->getType());<br>
> +    if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl())<br>
> +      if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,<br>
> +                                     false, 0))<br>
> +        return false;<br>
>    }<br>
><br>
>    //   Otherwise, the implicitly declared copy assignment operator will<br>
>    //   have the form<br>
>    //<br>
>    //       X& X::operator=(X&)<br>
> -<br>
> +<br>
> +  return true;<br>
> +}<br>
> +<br>
> +Sema::ImplicitExceptionSpecification<br>
> +Sema::ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
> +<br>
> +  ImplicitExceptionSpecification ExceptSpec(*this);<br>
> +  if (ClassDecl->isInvalidDecl())<br>
> +    return ExceptSpec;<br>
> +<br>
> +  const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();<br>
> +  assert(T->getNumArgs() == 1 && "not a copy assignment op");<br>
> +  unsigned ArgQuals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();<br>
> +<br>
>    // C++ [except.spec]p14:<br>
> -  //   An implicitly declared special member function (Clause 12) shall have an<br>
> +  //   An implicitly declared special member function (Clause 12) shall have an<br>
>    //   exception-specification. [...]<br>
><br>
>    // It is unspecified whether or not an implicit copy assignment operator<br>
> @@ -7536,8 +7529,6 @@<br>
>    // Based on a similar decision made for constness in C++0x, we're erring on<br>
>    // the side of assuming such calls to be made regardless of whether they<br>
>    // actually happen.<br>
> -  ImplicitExceptionSpecification ExceptSpec(*this);<br>
> -  unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;<br>
>    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
>                                         BaseEnd = ClassDecl->bases_end();<br>
>         Base != BaseEnd; ++Base) {<br>
> @@ -7575,7 +7566,7 @@<br>
>      }<br>
>    }<br>
><br>
> -  return std::make_pair(ExceptSpec, HasConstCopyAssignment);<br>
> +  return ExceptSpec;<br>
>  }<br>
><br>
>  CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {<br>
> @@ -7584,26 +7575,19 @@<br>
>    // for determining the argument type of the operator. Note also that<br>
>    // operators taking an object instead of a reference are allowed.<br>
><br>
> -  ImplicitExceptionSpecification Spec(*this);<br>
> -  bool Const;<br>
> -  llvm::tie(Spec, Const) =<br>
> -    ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);<br>
> -<br>
>    QualType ArgType = Context.getTypeDeclType(ClassDecl);<br>
>    QualType RetType = Context.getLValueReferenceType(ArgType);<br>
> -  if (Const)<br>
> +  if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))<br>
>      ArgType = ArgType.withConst();<br>
>    ArgType = Context.getLValueReferenceType(ArgType);<br>
><br>
>    //   An implicitly-declared copy assignment operator is an inline public<br>
>    //   member of its class.<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
>    DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);<br>
>    SourceLocation ClassLoc = ClassDecl->getLocation();<br>
>    DeclarationNameInfo NameInfo(Name, ClassLoc);<br>
>    CXXMethodDecl *CopyAssignment<br>
> -    = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,<br>
> -                            Context.getFunctionType(RetType, &ArgType, 1, EPI),<br>
> +    = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),<br>
>                              /*TInfo=*/0, /*isStatic=*/false,<br>
>                              /*StorageClassAsWritten=*/SC_None,<br>
>                              /*isInline=*/true, /*isConstexpr=*/false,<br>
> @@ -7612,7 +7596,13 @@<br>
>    CopyAssignment->setDefaulted();<br>
>    CopyAssignment->setImplicit();<br>
>    CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());<br>
> -<br>
> +<br>
> +  // Build an exception specification pointing back at this member.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = CopyAssignment;<br>
> +  CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));<br>
> +<br>
>    // Add the parameter to the operator.<br>
>    ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,<br>
>                                                 ClassLoc, ClassLoc, /*Id=*/0,<br>
> @@ -7950,9 +7940,10 @@<br>
>  }<br>
><br>
>  Sema::ImplicitExceptionSpecification<br>
> -Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl) {<br>
> -  ImplicitExceptionSpecification ExceptSpec(*this);<br>
> +Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
><br>
> +  ImplicitExceptionSpecification ExceptSpec(*this);<br>
>    if (ClassDecl->isInvalidDecl())<br>
>      return ExceptSpec;<br>
><br>
> @@ -8120,22 +8111,17 @@<br>
>    // Note: The following rules are largely analoguous to the move<br>
>    // constructor rules.<br>
><br>
> -  ImplicitExceptionSpecification Spec(<br>
> -      ComputeDefaultedMoveAssignmentExceptionSpec(ClassDecl));<br>
> -<br>
>    QualType ArgType = Context.getTypeDeclType(ClassDecl);<br>
>    QualType RetType = Context.getLValueReferenceType(ArgType);<br>
>    ArgType = Context.getRValueReferenceType(ArgType);<br>
><br>
>    //   An implicitly-declared move assignment operator is an inline public<br>
>    //   member of its class.<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
>    DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);<br>
>    SourceLocation ClassLoc = ClassDecl->getLocation();<br>
>    DeclarationNameInfo NameInfo(Name, ClassLoc);<br>
>    CXXMethodDecl *MoveAssignment<br>
> -    = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,<br>
> -                            Context.getFunctionType(RetType, &ArgType, 1, EPI),<br>
> +    = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),<br>
>                              /*TInfo=*/0, /*isStatic=*/false,<br>
>                              /*StorageClassAsWritten=*/SC_None,<br>
>                              /*isInline=*/true,<br>
> @@ -8146,6 +8132,12 @@<br>
>    MoveAssignment->setImplicit();<br>
>    MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());<br>
><br>
> +  // Build an exception specification pointing back at this member.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = MoveAssignment;<br>
> +  MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));<br>
> +<br>
>    // Add the parameter to the operator.<br>
>    ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,<br>
>                                                 ClassLoc, ClassLoc, /*Id=*/0,<br>
> @@ -8496,10 +8488,12 @@<br>
>    }<br>
>  }<br>
><br>
> -std::pair<Sema::ImplicitExceptionSpecification, bool><br>
> -Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl) {<br>
> +/// Determine whether an implicit copy constructor for ClassDecl has a const<br>
> +/// argument.<br>
> +/// FIXME: It ought to be possible to store this on the record.<br>
> +static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) {<br>
>    if (ClassDecl->isInvalidDecl())<br>
> -    return std::make_pair(ImplicitExceptionSpecification(*this), true);<br>
> +    return true;<br>
><br>
>    // C++ [class.copy]p5:<br>
>    //   The implicitly-declared copy constructor for a class X will<br>
> @@ -8508,60 +8502,71 @@<br>
>    //       X::X(const X&)<br>
>    //<br>
>    //   if<br>
> -  // FIXME: It ought to be possible to store this on the record.<br>
> -  bool HasConstCopyConstructor = true;<br>
> -<br>
>    //     -- each direct or virtual base class B of X has a copy<br>
>    //        constructor whose first parameter is of type const B& or<br>
>    //        const volatile B&, and<br>
>    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
>                                         BaseEnd = ClassDecl->bases_end();<br>
> -       HasConstCopyConstructor && Base != BaseEnd;<br>
> -       ++Base) {<br>
> +       Base != BaseEnd; ++Base) {<br>
>      // Virtual bases are handled below.<br>
>      if (Base->isVirtual())<br>
>        continue;<br>
> -<br>
> +<br>
>      CXXRecordDecl *BaseClassDecl<br>
>        = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
> -    HasConstCopyConstructor &=<br>
> -      (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);<br>
> +    // FIXME: This lookup is wrong. If the copy ctor for a member or base is<br>
> +    // ambiguous, we should still produce a constructor with a const-qualified<br>
> +    // parameter.<br>
> +    if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))<br>
> +      return false;<br>
>    }<br>
><br>
>    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),<br>
>                                         BaseEnd = ClassDecl->vbases_end();<br>
> -       HasConstCopyConstructor && Base != BaseEnd;<br>
> -       ++Base) {<br>
> +       Base != BaseEnd; ++Base) {<br>
>      CXXRecordDecl *BaseClassDecl<br>
>        = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());<br>
> -    HasConstCopyConstructor &=<br>
> -      (bool)LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const);<br>
> +    if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))<br>
> +      return false;<br>
>    }<br>
> -<br>
> +<br>
>    //     -- for all the nonstatic data members of X that are of a<br>
>    //        class type M (or array thereof), each such class type<br>
>    //        has a copy constructor whose first parameter is of type<br>
>    //        const M& or const volatile M&.<br>
>    for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),<br>
>                                    FieldEnd = ClassDecl->field_end();<br>
> -       HasConstCopyConstructor && Field != FieldEnd;<br>
> -       ++Field) {<br>
> -    QualType FieldType = Context.getBaseElementType(Field->getType());<br>
> +       Field != FieldEnd; ++Field) {<br>
> +    QualType FieldType = S.Context.getBaseElementType(Field->getType());<br>
>      if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {<br>
> -      HasConstCopyConstructor &=<br>
> -        (bool)LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const);<br>
> +      if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const))<br>
> +        return false;<br>
>      }<br>
>    }<br>
> +<br>
>    //   Otherwise, the implicitly declared copy constructor will have<br>
>    //   the form<br>
>    //<br>
>    //       X::X(X&)<br>
> -<br>
> +<br>
> +  return true;<br>
> +}<br>
> +<br>
> +Sema::ImplicitExceptionSpecification<br>
> +Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
> +<br>
> +  ImplicitExceptionSpecification ExceptSpec(*this);<br>
> +  if (ClassDecl->isInvalidDecl())<br>
> +    return ExceptSpec;<br>
> +<br>
> +  const FunctionProtoType *T = MD->getType()->castAs<FunctionProtoType>();<br>
> +  assert(T->getNumArgs() >= 1 && "not a copy ctor");<br>
> +  unsigned Quals = T->getArgType(0).getNonReferenceType().getCVRQualifiers();<br>
> +<br>
>    // C++ [except.spec]p14:<br>
>    //   An implicitly declared special member function (Clause 12) shall have an<br>
>    //   exception-specification. [...]<br>
> -  ImplicitExceptionSpecification ExceptSpec(*this);<br>
> -  unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;<br>
>    for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),<br>
>                                         BaseEnd = ClassDecl->bases_end();<br>
>         Base != BaseEnd;<br>
> @@ -8599,7 +8604,7 @@<br>
>      }<br>
>    }<br>
><br>
> -  return std::make_pair(ExceptSpec, HasConstCopyConstructor);<br>
> +  return ExceptSpec;<br>
>  }<br>
><br>
>  CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(<br>
> @@ -8608,18 +8613,12 @@<br>
>    //   If the class definition does not explicitly declare a copy<br>
>    //   constructor, one is declared implicitly.<br>
><br>
> -  ImplicitExceptionSpecification Spec(*this);<br>
> -  bool Const;<br>
> -  llvm::tie(Spec, Const) =<br>
> -    ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);<br>
> -<br>
>    QualType ClassType = Context.getTypeDeclType(ClassDecl);<br>
>    QualType ArgType = ClassType;<br>
> +  bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl);<br>
>    if (Const)<br>
>      ArgType = ArgType.withConst();<br>
>    ArgType = Context.getLValueReferenceType(ArgType);<br>
> -<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
><br>
>    bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,<br>
>                                                       CXXCopyConstructor,<br>
> @@ -8634,14 +8633,20 @@<br>
>    //   An implicitly-declared copy constructor is an inline public<br>
>    //   member of its class.<br>
>    CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(<br>
> -      Context, ClassDecl, ClassLoc, NameInfo,<br>
> -      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,<br>
> +      Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,<br>
>        /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,<br>
>        Constexpr);<br>
>    CopyConstructor->setAccess(AS_public);<br>
>    CopyConstructor->setDefaulted();<br>
>    CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());<br>
><br>
> +  // Build an exception specification pointing back at this member.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = CopyConstructor;<br>
> +  CopyConstructor->setType(<br>
> +      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));<br>
> +<br>
>    // Note that we have declared this constructor.<br>
>    ++ASTContext::NumImplicitCopyConstructorsDeclared;<br>
><br>
> @@ -8705,7 +8710,9 @@<br>
>  }<br>
><br>
>  Sema::ImplicitExceptionSpecification<br>
> -Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl) {<br>
> +Sema::ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD) {<br>
> +  CXXRecordDecl *ClassDecl = MD->getParent();<br>
> +<br>
>    // C++ [except.spec]p14:<br>
>    //   An implicitly declared special member function (Clause 12) shall have an<br>
>    //   exception-specification. [...]<br>
> @@ -8788,13 +8795,8 @@<br>
>      return 0;<br>
>    }<br>
><br>
> -  ImplicitExceptionSpecification Spec(<br>
> -      ComputeDefaultedMoveCtorExceptionSpec(ClassDecl));<br>
> -<br>
>    QualType ClassType = Context.getTypeDeclType(ClassDecl);<br>
>    QualType ArgType = Context.getRValueReferenceType(ClassType);<br>
> -<br>
> -  FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();<br>
><br>
>    bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,<br>
>                                                       CXXMoveConstructor,<br>
> @@ -8810,14 +8812,20 @@<br>
>    //   An implicitly-declared copy/move constructor is an inline public<br>
>    //   member of its class.<br>
>    CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(<br>
> -      Context, ClassDecl, ClassLoc, NameInfo,<br>
> -      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0,<br>
> +      Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/0,<br>
>        /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,<br>
>        Constexpr);<br>
>    MoveConstructor->setAccess(AS_public);<br>
>    MoveConstructor->setDefaulted();<br>
>    MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());<br>
><br>
> +  // Build an exception specification pointing back at this member.<br>
> +  FunctionProtoType::ExtProtoInfo EPI;<br>
> +  EPI.ExceptionSpecType = EST_Unevaluated;<br>
> +  EPI.ExceptionSpecDecl = MoveConstructor;<br>
> +  MoveConstructor->setType(<br>
> +      Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));<br>
> +<br>
>    // Add the parameter to the constructor.<br>
>    ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,<br>
>                                                 ClassLoc, ClassLoc,<br>
> @@ -10427,10 +10435,11 @@<br>
>      if (Primary == Primary->getCanonicalDecl())<br>
>        return;<br>
><br>
> +    CheckExplicitlyDefaultedSpecialMember(MD);<br>
> +<br>
>      switch (Member) {<br>
>      case CXXDefaultConstructor: {<br>
>        CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);<br>
> -      CheckExplicitlyDefaultedSpecialMember(CD);<br>
>        if (!CD->isInvalidDecl())<br>
>          DefineImplicitDefaultConstructor(DefaultLoc, CD);<br>
>        break;<br>
> @@ -10438,14 +10447,12 @@<br>
><br>
>      case CXXCopyConstructor: {<br>
>        CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);<br>
> -      CheckExplicitlyDefaultedSpecialMember(CD);<br>
>        if (!CD->isInvalidDecl())<br>
>          DefineImplicitCopyConstructor(DefaultLoc, CD);<br>
>        break;<br>
>      }<br>
><br>
>      case CXXCopyAssignment: {<br>
> -      CheckExplicitlyDefaultedSpecialMember(MD);<br>
>        if (!MD->isInvalidDecl())<br>
>          DefineImplicitCopyAssignment(DefaultLoc, MD);<br>
>        break;<br>
> @@ -10453,7 +10460,6 @@<br>
><br>
>      case CXXDestructor: {<br>
>        CXXDestructorDecl *DD = cast<CXXDestructorDecl>(MD);<br>
> -      CheckExplicitlyDefaultedSpecialMember(DD);<br>
>        if (!DD->isInvalidDecl())<br>
>          DefineImplicitDestructor(DefaultLoc, DD);<br>
>        break;<br>
> @@ -10461,14 +10467,12 @@<br>
><br>
>      case CXXMoveConstructor: {<br>
>        CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);<br>
> -      CheckExplicitlyDefaultedSpecialMember(CD);<br>
>        if (!CD->isInvalidDecl())<br>
>          DefineImplicitMoveConstructor(DefaultLoc, CD);<br>
>        break;<br>
>      }<br>
><br>
>      case CXXMoveAssignment: {<br>
> -      CheckExplicitlyDefaultedSpecialMember(MD);<br>
>        if (!MD->isInvalidDecl())<br>
>          DefineImplicitMoveAssignment(DefaultLoc, MD);<br>
>        break;<br>
> @@ -10753,7 +10757,7 @@<br>
><br>
>    // Note: The VTableUses vector could grow as a result of marking<br>
>    // the members of a class as "used", so we check the size each<br>
> -  // time through the loop and prefer indices (with are stable) to<br>
> +  // time through the loop and prefer indices (which are stable) to<br>
>    // iterators (which are not).<br>
>    bool DefinedAnything = false;<br>
>    for (unsigned I = 0; I != VTableUses.size(); ++I) {<br>
> @@ -10763,6 +10767,8 @@<br>
><br>
>      SourceLocation Loc = VTableUses[I].second;<br>
><br>
> +    bool DefineVTable = true;<br>
> +<br>
>      // If this class has a key function, but that key function is<br>
>      // defined in another translation unit, we don't need to emit the<br>
>      // vtable even though we're using it.<br>
> @@ -10773,7 +10779,8 @@<br>
>        case TSK_ExplicitSpecialization:<br>
>        case TSK_ExplicitInstantiationDeclaration:<br>
>          // The key function is in another translation unit.<br>
> -        continue;<br>
> +        DefineVTable = false;<br>
> +        break;<br>
><br>
>        case TSK_ExplicitInstantiationDefinition:<br>
>        case TSK_ImplicitInstantiation:<br>
> @@ -10802,7 +10809,15 @@<br>
>        }<br>
><br>
>        if (IsExplicitInstantiationDeclaration)<br>
> -        continue;<br>
> +        DefineVTable = false;<br>
> +    }<br>
> +<br>
> +    // The exception specifications for all virtual members may be needed even<br>
> +    // if we are not providing an authoritative form of the vtable in this TU.<br>
> +    // We may choose to emit it available_externally anyway.<br>
> +    if (!DefineVTable) {<br>
> +      MarkVirtualMemberExceptionSpecsNeeded(Loc, Class);<br>
> +      continue;<br>
>      }<br>
><br>
>      // Mark all of the virtual members of this class as referenced, so<br>
> @@ -10831,6 +10846,14 @@<br>
>    return DefinedAnything;<br>
>  }<br>
><br>
> +void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,<br>
> +                                                 const CXXRecordDecl *RD) {<br>
> +  for (CXXRecordDecl::method_iterator I = RD->method_begin(),<br>
> +                                      E = RD->method_end(); I != E; ++I)<br>
> +    if ((*I)->isVirtual() && !(*I)->isPure())<br>
> +      ResolveExceptionSpec(Loc, (*I)->getType()->castAs<FunctionProtoType>());<br>
> +}<br>
> +<br>
>  void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,<br>
>                                          const CXXRecordDecl *RD) {<br>
>    // Mark all functions which will appear in RD's vtable as used.<br>
> @@ -11067,8 +11090,8 @@<br>
><br>
>    switch (Proto->getExceptionSpecType()) {<br>
>    case EST_Uninstantiated:<br>
> +  case EST_Unevaluated:<br>
>    case EST_BasicNoexcept:<br>
> -  case EST_Delayed:<br>
>    case EST_DynamicNone:<br>
>    case EST_MSAny:<br>
>    case EST_None:<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -100,20 +100,22 @@<br>
><br>
>  const FunctionProtoType *<br>
>  Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {<br>
> -  // FIXME: If FD is a special member, we should delay computing its exception<br>
> -  // specification until this point.<br>
> -  if (FPT->getExceptionSpecType() != EST_Uninstantiated)<br>
> +  if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))<br>
>      return FPT;<br>
><br>
>    FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();<br>
>    const FunctionProtoType *SourceFPT =<br>
>        SourceDecl->getType()->castAs<FunctionProtoType>();<br>
><br>
> -  if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)<br>
> +  // If the exception specification has already been resolved, just return it.<br>
> +  if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))<br>
>      return SourceFPT;<br>
><br>
> -  // Instantiate the exception specification now.<br>
> -  InstantiateExceptionSpec(Loc, SourceDecl);<br>
> +  // Compute or instantiate the exception specification now.<br>
> +  if (FPT->getExceptionSpecType() == EST_Unevaluated)<br>
> +    EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));<br>
> +  else<br>
> +    InstantiateExceptionSpec(Loc, SourceDecl);<br>
><br>
>    return SourceDecl->getType()->castAs<FunctionProtoType>();<br>
>  }<br>
> @@ -346,8 +348,8 @@<br>
>    ExceptionSpecificationType OldEST = Old->getExceptionSpecType();<br>
>    ExceptionSpecificationType NewEST = New->getExceptionSpecType();<br>
><br>
> -  assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&<br>
> -         OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&<br>
> +  assert(!isUnresolvedExceptionSpec(OldEST) &&<br>
> +         !isUnresolvedExceptionSpec(NewEST) &&<br>
>           "Shouldn't see unknown exception specifications here");<br>
><br>
>    // Shortcut the case where both have no spec.<br>
> @@ -544,8 +546,8 @@<br>
><br>
>    ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();<br>
><br>
> -  assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&<br>
> -         SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&<br>
> +  assert(!isUnresolvedExceptionSpec(SuperEST) &&<br>
> +         !isUnresolvedExceptionSpec(SubEST) &&<br>
>           "Shouldn't see unknown exception specifications here");<br>
><br>
>    // It does not. If the subset contains everything, we've failed.<br>
> @@ -808,15 +810,6 @@<br>
>    if (!FT)<br>
>      return CT_Can;<br>
><br>
> -  if (FT->getExceptionSpecType() == EST_Delayed) {<br>
> -    // FIXME: Try to resolve a delayed exception spec in ResolveExceptionSpec.<br>
> -    assert(isa<CXXConstructorDecl>(D) &&<br>
> -           "only constructor exception specs can be unknown");<br>
> -    S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)<br>
> -      << E->getSourceRange();<br>
> -    return CT_Can;<br>
> -  }<br>
> -<br>
>    return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;<br>
>  }<br>
><br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -10224,11 +10224,11 @@<br>
>    // FIXME: Is this really right?<br>
>    if (CurContext == Func) return;<br>
><br>
> -  // Instantiate the exception specification for any function which is<br>
> +  // Resolve the exception specification for any function which is<br>
>    // used: CodeGen will need it.<br>
>    const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();<br>
> -  if (FPT && FPT->getExceptionSpecType() == EST_Uninstantiated)<br>
> -    InstantiateExceptionSpec(Loc, Func);<br>
> +  if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))<br>
> +    ResolveExceptionSpec(Loc, FPT);<br>
><br>
>    // Implicit instantiation of function templates and member functions of<br>
>    // class templates.<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -3190,8 +3190,6 @@<br>
>              CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
>              if (!CPT)<br>
>                return false;<br>
> -            if (CPT->getExceptionSpecType() == EST_Delayed)<br>
> -              return false;<br>
>              if (!CPT->isNothrow(Self.Context))<br>
>                return false;<br>
>            }<br>
> @@ -3232,8 +3230,6 @@<br>
>            CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
>            if (!CPT)<br>
>              return false;<br>
> -          if (CPT->getExceptionSpecType() == EST_Delayed)<br>
> -            return false;<br>
>            // FIXME: check whether evaluating default arguments can throw.<br>
>            // For now, we'll be conservative and assume that they can throw.<br>
>            if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1)<br>
> @@ -3270,8 +3266,6 @@<br>
>            CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);<br>
>            if (!CPT)<br>
>              return false;<br>
> -          if (CPT->getExceptionSpecType() == EST_Delayed)<br>
> -            return false;<br>
>            // TODO: check whether evaluating default arguments can throw.<br>
>            // For now, we'll be conservative and assume that they can throw.<br>
>            return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0;<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -1996,8 +1996,7 @@<br>
>    Instantiator.disableLateAttributeInstantiation();<br>
>    LateAttrs.clear();<br>
><br>
> -  if (!FieldsWithMemberInitializers.empty())<br>
> -    ActOnFinishDelayedMemberInitializers(Instantiation);<br>
> +  ActOnFinishDelayedMemberInitializers(Instantiation);<br>
><br>
>    if (TSK == TSK_ImplicitInstantiation) {<br>
>      Instantiation->setLocation(Pattern->getLocation());<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -2395,8 +2395,17 @@<br>
><br>
>    InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,<br>
>                               InstantiatingTemplate::ExceptionSpecification());<br>
> -  if (Inst)<br>
> +  if (Inst) {<br>
> +    // We hit the instantiation depth limit. Clear the exception specification<br>
> +    // so that our callers don't have to cope with EST_Uninstantiated.<br>
> +    FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();<br>
> +    EPI.ExceptionSpecType = EST_None;<br>
> +    Decl->setType(Context.getFunctionType(Proto->getResultType(),<br>
> +                                          Proto->arg_type_begin(),<br>
> +                                          Proto->getNumArgs(),<br>
> +                                          EPI));<br>
>      return;<br>
> +  }<br>
><br>
>    // Enter the scope of this instantiation. We don't use<br>
>    // PushDeclContext because we don't have a scope.<br>
> @@ -2461,6 +2470,8 @@<br>
>        FunctionDecl *ExceptionSpecTemplate = Tmpl;<br>
>        if (EPI.ExceptionSpecType == EST_Uninstantiated)<br>
>          ExceptionSpecTemplate = EPI.ExceptionSpecTemplate;<br>
> +      assert(EPI.ExceptionSpecType != EST_Unevaluated &&<br>
> +             "instantiating implicitly-declared special member");<br>
><br>
>        // Mark the function has having an uninstantiated exception specification.<br>
>        const FunctionProtoType *NewProto<br>
> @@ -3431,7 +3442,7 @@<br>
>  void Sema::PerformPendingInstantiations(bool LocalOnly) {<br>
>    // Load pending instantiations from the external source.<br>
>    if (!LocalOnly && ExternalSource) {<br>
> -    SmallVector<std::pair<ValueDecl *, SourceLocation>, 4> Pending;<br>
> +    SmallVector<PendingImplicitInstantiation, 4> Pending;<br>
>      ExternalSource->ReadPendingInstantiations(Pending);<br>
>      PendingInstantiations.insert(PendingInstantiations.begin(),<br>
>                                   Pending.begin(), Pending.end());<br>
><br>
> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -3906,6 +3906,8 @@<br>
>      } else if (EST == EST_Uninstantiated) {<br>
>        EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);<br>
>        EPI.ExceptionSpecTemplate = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);<br>
> +    } else if (EST == EST_Unevaluated) {<br>
> +      EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);<br>
>      }<br>
>      return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,<br>
>                                      EPI);<br>
><br>
> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)<br>
> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -198,6 +198,8 @@<br>
>    } else if (T->getExceptionSpecType() == EST_Uninstantiated) {<br>
>      Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);<br>
>      Writer.AddDeclRef(T->getExceptionSpecTemplate(), Record);<br>
> +  } else if (T->getExceptionSpecType() == EST_Unevaluated) {<br>
> +    Writer.AddDeclRef(T->getExceptionSpecDecl(), Record);<br>
>    }<br>
>    Code = TYPE_FUNCTION_PROTO;<br>
>  }<br>
><br>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp<br>
> URL: <a href="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" target="_blank">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</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp (original)<br>
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p1.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -4,9 +4,11 @@<br>
>  // [...]<br>
>  //   -- not have default arguments<br>
>  struct DefArg {<br>
> +  static DefArg &&make();<br>
>    DefArg(int n = 5) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}<br>
> -  DefArg(const DefArg &DA = DefArg(2)) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}<br>
> +  DefArg(const DefArg &DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}<br>
>    DefArg(const DefArg &DA, int k = 3) = default; // expected-error {{an explicitly-defaulted copy constructor cannot have default arguments}}<br>
> +  DefArg(DefArg &&DA = make()) = default; // expected-error {{an explicitly-defaulted constructor cannot have default arguments}}<br>
>    DefArg(DefArg &&DA, int k = 3) = default; // expected-error {{an explicitly-defaulted move constructor cannot have default arguments}}<br>
>    DefArg &operator=(const DefArg&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}}<br>
>    DefArg &operator=(DefArg&&, int k = 4) = default; // expected-error {{parameter of overloaded 'operator=' cannot have a default argument}}<br>
><br>
> Removed: cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp?rev=160846&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp?rev=160846&view=auto</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp (original)<br>
> +++ cfe/trunk/test/CodeGenCXX/member-init-ctor.cpp (removed)<br>
> @@ -1,14 +0,0 @@<br>
> -// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s<br>
> -<br>
> -bool b();<br>
> -struct S {<br>
> -  int n = b() ? S().n + 1 : 0;<br>
> -};<br>
> -<br>
> -S s;<br>
> -<br>
> -// CHECK: define {{.*}} @_ZN1SC2Ev(<br>
> -// CHECK-NOT }<br>
> -// CHECK: call {{.*}} @_Z1bv()<br>
> -// CHECK-NOT }<br>
> -// CHECK: call {{.*}} @_ZN1SC1Ev(<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -57,3 +57,63 @@<br>
>    friend S<bar>::S(const S&);<br>
>    friend S<bar>::S(S&&);<br>
>  };<br>
> +<br>
> +namespace DefaultedFnExceptionSpec {<br>
> +  // DR1330: The exception-specification of an implicitly-declared special<br>
> +  // member function is evaluated as needed.<br>
> +  template<typename T> T &&declval();<br>
> +  template<typename T> struct pair {<br>
> +    pair(const pair&) noexcept(noexcept(T(declval<T>())));<br>
> +  };<br>
> +<br>
> +  struct Y;<br>
> +  struct X { X(); X(const Y&); };<br>
> +  struct Y { pair<X> p; };<br>
> +<br>
> +  template<typename T><br>
> +  struct A {<br>
> +    pair<T> p;<br>
> +  };<br>
> +  struct B {<br>
> +    B();<br>
> +    B(const A<B>&);<br>
> +  };<br>
> +<br>
> +  // Don't crash here.<br>
> +  void f() {<br>
> +    X x = X();<br>
> +    (void)noexcept(B(declval<B>()));<br>
> +  }<br>
> +<br>
> +  template<typename T><br>
> +  struct Error {<br>
> +    // FIXME: Type canonicalization causes all the errors to point at the first<br>
> +    // declaration which has the type 'void () noexcept (T::error)'. We should<br>
> +    // get one error for 'Error<int>::Error()' and one for 'Error<int>::~Error()'.<br>
> +    void f() noexcept(T::error); // expected-error 2{{has no members}}<br>
> +<br>
> +    Error() noexcept(T::error);<br>
> +    Error(const Error&) noexcept(T::error);<br>
> +    Error(Error&&) noexcept(T::error);<br>
> +    Error &operator=(const Error&) noexcept(T::error);<br>
> +    Error &operator=(Error&&) noexcept(T::error);<br>
> +    ~Error() noexcept(T::error);<br>
> +  };<br>
> +<br>
> +  struct DelayImplicit {<br>
> +    Error<int> e;<br>
> +  };<br>
> +<br>
> +  // Don't instantiate the exception specification here.<br>
> +  void test1(decltype(declval<DelayImplicit>() = DelayImplicit(DelayImplicit())));<br>
> +  void test2(decltype(declval<DelayImplicit>() = declval<const DelayImplicit>()));<br>
> +  void test3(decltype(DelayImplicit(declval<const DelayImplicit>())));<br>
> +<br>
> +  // Any odr-use causes the exception specification to be evaluated.<br>
> +  struct OdrUse { // \<br>
> +    expected-note {{instantiation of exception specification for 'Error'}} \<br>
> +    expected-note {{instantiation of exception specification for '~Error'}}<br>
> +    Error<int> e;<br>
> +  };<br>
> +  OdrUse use; // expected-note {{implicit default constructor for 'DefaultedFnExceptionSpec::OdrUse' first required here}}<br>
> +}<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -17,7 +17,7 @@<br>
>    // is false.<br>
>    bool ThrowSomething() noexcept(false);<br>
>    struct ConstExpr {<br>
> -    bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{exception specification is not available until end of class definition}}<br>
> +    bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{cannot be used by non-static data member initializer}}<br>
>    };<br>
>    // We can use it now.<br>
>    bool w = noexcept(ConstExpr());<br>
> @@ -25,18 +25,27 @@<br>
>    // Much more obviously broken: we can't parse the initializer without already<br>
>    // knowing whether it produces a noexcept expression.<br>
>    struct TemplateArg {<br>
> -    int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{exception specification is not available until end of class definition}}<br>
> +    int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{cannot be used by non-static data member initializer}}<br>
>    };<br>
>    bool x = noexcept(TemplateArg());<br>
><br>
>    // And within a nested class.<br>
> +  // FIXME: The diagnostic location is terrible here.<br>
>    struct Nested {<br>
>      struct Inner {<br>
> -      int n = ExceptionIf<noexcept(Nested())>::f(); // expected-error {{exception specification is not available until end of class definition}}<br>
> -    } inner;<br>
> +      int n = ExceptionIf<noexcept(Nested())>::f();<br>
> +    } inner; // expected-error {{cannot be used by non-static data member initializer}}<br>
>    };<br>
>    bool y = noexcept(Nested());<br>
>    bool z = noexcept(Nested::Inner());<br>
> +<br>
> +  struct Nested2 {<br>
> +    struct Inner;<br>
> +    int n = Inner().n; // expected-error {{cannot be used by non-static data member initializer}}<br>
> +    struct Inner {<br>
> +      int n = ExceptionIf<noexcept(Nested())>::f();<br>
> +    } inner;<br>
> +  };<br>
>  }<br>
><br>
>  namespace ExceptionSpecification {<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/member-init.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/member-init.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/member-init.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -14,7 +14,7 @@<br>
>  bool b();<br>
>  int k;<br>
>  struct Recurse {<br>
> -  int &n = b() ? Recurse().n : k; // ok<br>
> +  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}}<br>
>  };<br>
><br>
>  struct UnknownBound {<br>
><br>
> Modified: cfe/trunk/test/SemaCXX/type-traits.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-traits.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaCXX/type-traits.cpp (original)<br>
> +++ cfe/trunk/test/SemaCXX/type-traits.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -1384,9 +1384,6 @@<br>
>    { int arr[F(__has_nothrow_copy(cvoid))]; }<br>
>  }<br>
><br>
> -template<bool b> struct assert_expr;<br>
> -template<> struct assert_expr<true> {};<br>
> -<br>
>  void has_nothrow_constructor() {<br>
>    { int arr[T(__has_nothrow_constructor(Int))]; }<br>
>    { int arr[T(__has_nothrow_constructor(IntAr))]; }<br>
> @@ -1415,11 +1412,6 @@<br>
>    { int arr[F(__has_nothrow_constructor(void))]; }<br>
>    { int arr[F(__has_nothrow_constructor(cvoid))]; }<br>
>    { int arr[F(__has_nothrow_constructor(HasTemplateCons))]; }<br>
> -<br>
> -  // While parsing an in-class initializer, the constructor is not known to be<br>
> -  // non-throwing yet.<br>
> -  struct HasInClassInit { int n = (assert_expr<!__has_nothrow_constructor(HasInClassInit)>(), 0); };<br>
> -  { int arr[T(__has_nothrow_constructor(HasInClassInit))]; }<br>
>  }<br>
><br>
>  void has_virtual_destructor() {<br>
><br>
> Modified: cfe/trunk/test/SemaTemplate/instantiation-depth.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-depth.cpp?rev=160847&r1=160846&r2=160847&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiation-depth.cpp?rev=160847&r1=160846&r2=160847&view=diff</a><br>

> ==============================================================================<br>
> --- cfe/trunk/test/SemaTemplate/instantiation-depth.cpp (original)<br>
> +++ cfe/trunk/test/SemaTemplate/instantiation-depth.cpp Thu Jul 26 23:22:15 2012<br>
> @@ -2,12 +2,30 @@<br>
>  // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth-5 -ftemplate-backtrace-limit=4 %s<br>
>  // RUN: %clang -fsyntax-only -Xclang -verify -ftemplate-depth=5 -ftemplate-backtrace-limit=4 %s<br>
><br>
> +#ifndef NOEXCEPT<br>
> +<br>
>  template<typename T> struct X : X<T*> { }; \<br>
>  // expected-error{{recursive template instantiation exceeded maximum depth of 5}} \<br>
>  // expected-note 3 {{instantiation of template class}} \<br>
>  // expected-note {{skipping 2 contexts in backtrace}} \<br>
>  // expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}<br>
><br>
> -void test() {<br>
> +void test() {<br>
>    (void)sizeof(X<int>); // expected-note {{instantiation of template class}}<br>
>  }<br>
> +<br>
> +#else<br>
> +<br>
> +// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 -std=c++11 -DNOEXCEPT %s<br>
> +<br>
> +template<typename T> struct S {<br>
> +  S() noexcept(noexcept(T()));<br>
> +};<br>
> +struct T : S<T> {}; \<br>
> +// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \<br>
> +// expected-note 4 {{in instantiation of exception spec}} \<br>
> +// expected-note {{skipping 2 contexts in backtrace}} \<br>
> +// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}<br>
> +T t; // expected-note {{implicit default constructor for 'T' first required here}}<br>
> +<br>
> +#endif<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>