[cfe-commits] r154886 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Analysis/ lib/Sema/ test/CXX/except/except.spec/ test/CodeGenCXX/ test/SemaTemplate/
Matthieu Monrocq
matthieu.monrocq at gmail.com
Wed Apr 18 11:37:59 PDT 2012
Le 17 avril 2012 02:58, Richard Smith <richard-llvm at metafoo.co.uk> a écrit :
> Author: rsmith
> Date: Mon Apr 16 19:58:00 2012
> New Revision: 154886
>
> URL: http://llvm.org/viewvc/llvm-project?rev=154886&view=rev
> Log:
> Implement DR1330 in C++11 mode, to support libstdc++4.7 which uses it.
>
> We have a new flavor of exception specification, EST_Uninstantiated. A
> function
> type with this exception specification carries a pointer to a
> FunctionDecl, and
> the exception specification for that FunctionDecl is instantiated (if
> needed)
> and used in the place of the function type's exception specification.
>
> When a function template declaration with a non-trivial exception
> specification
> is instantiated, the specialization's exception specification is set to
> this
> new 'uninstantiated' kind rather than being instantiated immediately.
>
> Expr::CanThrow has migrated onto Sema, so it can instantiate exception
> specs
> on-demand. Also, any odr-use of a function triggers the instantiation of
> its
> exception specification (the exception specification could be needed by
> IRGen).
> In passing, fix two places where a DeclRefExpr was created but the
> corresponding
> function was not actually marked odr-used. We used to get away with this,
> but
> don't any more.
>
> Also fix a bug where instantiating an exception specification which refers
> to
> function parameters resulted in a crash. We still have the same bug in
> default
> arguments, which I'll be looking into next.
>
> This, plus a tiny patch to fix libstdc++'s common_type, is enough for
> clang to
> parse (and, in very limited testing, support) all of libstdc++4.7's
> standard
> headers.
>
>
Will it be available in Clang 3.1 ?
> Added:
> cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp
> cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> Modified:
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/include/clang/AST/Type.h
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/AST/ASTContext.cpp
> cfe/trunk/lib/AST/Expr.cpp
> cfe/trunk/lib/AST/Type.cpp
> cfe/trunk/lib/Analysis/CFG.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
> cfe/trunk/lib/Sema/SemaExpr.cpp
> cfe/trunk/lib/Sema/SemaExprCXX.cpp
> cfe/trunk/lib/Sema/SemaOverload.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> cfe/trunk/lib/Sema/TreeTransform.h
> cfe/trunk/test/CXX/except/except.spec/p1.cpp
> cfe/trunk/test/SemaTemplate/instantiate-declref.cpp
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Mon Apr 16 19:58:00 2012
> @@ -581,16 +581,6 @@
> /// member expression.
> static QualType findBoundMemberType(const Expr *expr);
>
> - /// \brief Result type of CanThrow().
> - enum CanThrowResult {
> - CT_Cannot,
> - CT_Dependent,
> - CT_Can
> - };
> - /// \brief Test if this expression, if evaluated, might throw,
> according to
> - /// the rules of C++ [expr.unary.noexcept].
> - CanThrowResult CanThrow(ASTContext &C) const;
> -
> /// IgnoreImpCasts - Skip past any implicit casts which might
> /// surround this expression. Only skips ImplicitCastExprs.
> Expr *IgnoreImpCasts() LLVM_READONLY;
>
> Modified: cfe/trunk/include/clang/AST/Type.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Type.h (original)
> +++ cfe/trunk/include/clang/AST/Type.h Mon Apr 16 19:58:00 2012
> @@ -79,6 +79,7 @@
> class CXXRecordDecl;
> class EnumDecl;
> class FieldDecl;
> + class FunctionDecl;
> class ObjCInterfaceDecl;
> class ObjCProtocolDecl;
> class ObjCMethodDecl;
> @@ -2700,7 +2701,8 @@
> ExtProtoInfo() :
> Variadic(false), HasTrailingReturn(false), TypeQuals(0),
> ExceptionSpecType(EST_None), RefQualifier(RQ_None),
> - NumExceptions(0), Exceptions(0), NoexceptExpr(0),
> ConsumedArguments(0) {}
> + NumExceptions(0), Exceptions(0), NoexceptExpr(0),
> ExceptionSpecDecl(0),
> + ConsumedArguments(0) {}
>
> FunctionType::ExtInfo ExtInfo;
> bool Variadic : 1;
> @@ -2711,6 +2713,7 @@
> unsigned NumExceptions;
> const QualType *Exceptions;
> Expr *NoexceptExpr;
> + FunctionDecl *ExceptionSpecDecl;
> const bool *ConsumedArguments;
> };
>
> @@ -2756,6 +2759,10 @@
> // NoexceptExpr - Instead of Exceptions, there may be a single Expr*
> pointing
> // to the expression in the noexcept() specifier.
>
> + // ExceptionSpecDecl - Instead of Exceptions, there may be a single
> + // FunctionDecl* pointing to the function which should be used to
> resolve
> + // this function type's exception specification.
> +
> // ConsumedArgs - A variable size array, following Exceptions
> // and of length NumArgs, holding flags indicating which arguments
> // are consumed. This only appears if HasAnyConsumedArgs is true.
> @@ -2795,6 +2802,8 @@
> EPI.Exceptions = exception_begin();
> } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
> EPI.NoexceptExpr = getNoexceptExpr();
> + } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
> + EPI.ExceptionSpecDecl = getExceptionSpecDecl();
> }
> if (hasAnyConsumedArgs())
> EPI.ConsumedArguments = getConsumedArgsBuffer();
> @@ -2838,9 +2847,14 @@
> // NoexceptExpr sits where the arguments end.
> return *reinterpret_cast<Expr *const *>(arg_type_end());
> }
> + FunctionDecl *getExceptionSpecDecl() const {
> + if (getExceptionSpecType() != EST_Uninstantiated)
> + return 0;
> + return *reinterpret_cast<FunctionDecl * const *>(arg_type_end());
> + }
> bool isNothrow(ASTContext &Ctx) const {
> ExceptionSpecificationType EST = getExceptionSpecType();
> - assert(EST != EST_Delayed);
> + assert(EST != EST_Delayed && EST != EST_Uninstantiated);
> if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
> return true;
> if (EST != EST_ComputedNoexcept)
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 16
> 19:58:00 2012
> @@ -2583,6 +2583,8 @@
> "in instantiation of enumeration %q0 requested here">;
> def note_template_type_alias_instantiation_here : Note<
> "in instantiation of template type alias %0 requested here">;
> +def note_template_exception_spec_instantiation_here : Note<
> + "in instantiation of exception specification for %0 requested here">;
>
> def note_default_arg_instantiation_here : Note<
> "in instantiation of default argument for '%0' required here">;
>
> Modified: cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h (original)
> +++ cfe/trunk/include/clang/Basic/ExceptionSpecificationType.h Mon Apr 16
> 19:58:00 2012
> @@ -16,7 +16,7 @@
>
> namespace clang {
>
> -/// \brief The various types of exception specifications that exist in
> C++0x.
> +/// \brief The various types of exception specifications that exist in
> C++11.
> enum ExceptionSpecificationType {
> EST_None, ///< no exception specification
> EST_DynamicNone, ///< throw()
> @@ -24,7 +24,8 @@
> EST_MSAny, ///< Microsoft throw(...) extension
> EST_BasicNoexcept, ///< noexcept
> EST_ComputedNoexcept, ///< noexcept(expression)
> - EST_Delayed ///< not known yet
> + EST_Delayed, ///< not known yet
> + EST_Uninstantiated ///< not instantiated yet
> };
>
> inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
> @@ -35,6 +36,19 @@
> return ESpecType == EST_BasicNoexcept || ESpecType ==
> EST_ComputedNoexcept;
> }
>
> +/// \brief Possible results from evaluation of a noexcept expression.
> +enum CanThrowResult {
> + CT_Cannot,
> + CT_Dependent,
> + CT_Can
> +};
> +
> +inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult
> CT2) {
> + // CanThrowResult constants are ordered so that the maximum is the
> correct
> + // merge result.
> + return CT1 > CT2 ? CT1 : CT2;
> +}
> +
> } // end namespace clang
>
> #endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Mon Apr 16 19:58:00 2012
> @@ -907,6 +907,9 @@
> DeclarationNameInfo GetNameForDeclarator(Declarator &D);
> DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name);
> static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo
> = 0);
> + CanThrowResult canThrow(const Expr *E);
> + const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
> + const FunctionProtoType
> *FPT);
> bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
> bool CheckDistantExceptionSpec(QualType T);
> bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
> @@ -3050,7 +3053,7 @@
> /// implicitly-declared special member functions.
> class ImplicitExceptionSpecification {
> // Pointer to allow copying
> - ASTContext *Context;
> + Sema *Self;
> // We order exception specifications thus:
> // noexcept is the most restrictive, but is only used in C++0x.
> // throw() comes next.
> @@ -3074,9 +3077,9 @@
> }
>
> public:
> - explicit ImplicitExceptionSpecification(ASTContext &Context)
> - : Context(&Context), ComputedEST(EST_BasicNoexcept) {
> - if (!Context.getLangOpts().CPlusPlus0x)
> + explicit ImplicitExceptionSpecification(Sema &Self)
> + : Self(&Self), ComputedEST(EST_BasicNoexcept) {
> + if (!Self.Context.getLangOpts().CPlusPlus0x)
> ComputedEST = EST_DynamicNone;
> }
>
> @@ -3094,7 +3097,7 @@
> const QualType *data() const { return Exceptions.data(); }
>
> /// \brief Integrate another called method into the collected data.
> - void CalledDecl(CXXMethodDecl *Method);
> + void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);
>
> /// \brief Integrate an invoked expression into the collected data.
> void CalledExpr(Expr *E);
> @@ -5194,7 +5197,11 @@
>
> /// We are checking the validity of a default template argument that
> /// has been used when naming a template-id.
> - DefaultTemplateArgumentChecking
> + DefaultTemplateArgumentChecking,
> +
> + /// We are instantiating the exception specification for a function
> + /// template which was deferred until it was needed.
> + ExceptionSpecInstantiation
> } Kind;
>
> /// \brief The point of instantiation within the source code.
> @@ -5242,6 +5249,7 @@
>
> switch (X.Kind) {
> case TemplateInstantiation:
> + case ExceptionSpecInstantiation:
> return true;
>
> case PriorTemplateArgumentSubstitution:
> @@ -5359,6 +5367,13 @@
> Decl *Entity,
> SourceRange InstantiationRange = SourceRange());
>
> + struct ExceptionSpecification {};
> + /// \brief Note that we are instantiating an exception specification
> + /// of a function template.
> + InstantiatingTemplate(Sema &SemaRef, SourceLocation
> PointOfInstantiation,
> + FunctionDecl *Entity, ExceptionSpecification,
> + SourceRange InstantiationRange = SourceRange());
> +
> /// \brief Note that we are instantiating a default argument in a
> /// template-id.
> InstantiatingTemplate(Sema &SemaRef, SourceLocation
> PointOfInstantiation,
> @@ -5658,6 +5673,8 @@
> TemplateArgumentListInfo &Result,
> const MultiLevelTemplateArgumentList &TemplateArgs);
>
> + void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
> + FunctionDecl *Function);
> void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
> FunctionDecl *Function,
> bool Recursive = false,
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Mon Apr 16 19:58:00 2012
> @@ -2194,6 +2194,8 @@
> Size += EPI.NumExceptions * sizeof(QualType);
> else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
> Size += sizeof(Expr*);
> + } else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
> + Size += sizeof(FunctionDecl*);
> }
> if (EPI.ConsumedArguments)
> Size += NumArgs * sizeof(bool);
>
> Modified: cfe/trunk/lib/AST/Expr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Expr.cpp (original)
> +++ cfe/trunk/lib/AST/Expr.cpp Mon Apr 16 19:58:00 2012
> @@ -1996,331 +1996,6 @@
> return QualType();
> }
>
> -static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
> - Expr::CanThrowResult CT2) {
> - // CanThrowResult constants are ordered so that the maximum is the
> correct
> - // merge result.
> - return CT1 > CT2 ? CT1 : CT2;
> -}
> -
> -static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr
> *CE) {
> - Expr *E = const_cast<Expr*>(CE);
> - Expr::CanThrowResult R = Expr::CT_Cannot;
> - for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {
> - R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));
> - }
> - return R;
> -}
> -
> -static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
> - const Decl *D,
> - bool NullThrows = true) {
> - if (!D)
> - return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
> -
> - // See if we can get a function type from the decl somehow.
> - const ValueDecl *VD = dyn_cast<ValueDecl>(D);
> - if (!VD) // If we have no clue what we're calling, assume the worst.
> - return Expr::CT_Can;
> -
> - // As an extension, we assume that __attribute__((nothrow)) functions
> don't
> - // throw.
> - if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
> - return Expr::CT_Cannot;
> -
> - QualType T = VD->getType();
> - const FunctionProtoType *FT;
> - if ((FT = T->getAs<FunctionProtoType>())) {
> - } else if (const PointerType *PT = T->getAs<PointerType>())
> - FT = PT->getPointeeType()->getAs<FunctionProtoType>();
> - else if (const ReferenceType *RT = T->getAs<ReferenceType>())
> - FT = RT->getPointeeType()->getAs<FunctionProtoType>();
> - else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
> - FT = MT->getPointeeType()->getAs<FunctionProtoType>();
> - else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
> - FT = BT->getPointeeType()->getAs<FunctionProtoType>();
> -
> - if (!FT)
> - return Expr::CT_Can;
> -
> - if (FT->getExceptionSpecType() == EST_Delayed) {
> - assert(isa<CXXConstructorDecl>(D) &&
> - "only constructor exception specs can be unknown");
> - Ctx.getDiagnostics().Report(E->getLocStart(),
> - diag::err_exception_spec_unknown)
> - << E->getSourceRange();
> - return Expr::CT_Can;
> - }
> -
> - return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
> -}
> -
> -static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr
> *DC) {
> - if (DC->isTypeDependent())
> - return Expr::CT_Dependent;
> -
> - if (!DC->getTypeAsWritten()->isReferenceType())
> - return Expr::CT_Cannot;
> -
> - if (DC->getSubExpr()->isTypeDependent())
> - return Expr::CT_Dependent;
> -
> - return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can :
> Expr::CT_Cannot;
> -}
> -
> -static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
> - const CXXTypeidExpr *DC) {
> - if (DC->isTypeOperand())
> - return Expr::CT_Cannot;
> -
> - Expr *Op = DC->getExprOperand();
> - if (Op->isTypeDependent())
> - return Expr::CT_Dependent;
> -
> - const RecordType *RT = Op->getType()->getAs<RecordType>();
> - if (!RT)
> - return Expr::CT_Cannot;
> -
> - if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
> - return Expr::CT_Cannot;
> -
> - if (Op->Classify(C).isPRValue())
> - return Expr::CT_Cannot;
> -
> - return Expr::CT_Can;
> -}
> -
> -Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
> - // C++ [expr.unary.noexcept]p3:
> - // [Can throw] if in a potentially-evaluated context the expression
> would
> - // contain:
> - switch (getStmtClass()) {
> - case CXXThrowExprClass:
> - // - a potentially evaluated throw-expression
> - return CT_Can;
> -
> - case CXXDynamicCastExprClass: {
> - // - a potentially evaluated dynamic_cast expression
> dynamic_cast<T>(v),
> - // where T is a reference type, that requires a run-time check
> - CanThrowResult CT =
> CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
> - if (CT == CT_Can)
> - return CT;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - case CXXTypeidExprClass:
> - // - a potentially evaluated typeid expression applied to a glvalue
> - // expression whose type is a polymorphic class type
> - return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
> -
> - // - a potentially evaluated call to a function, member function,
> function
> - // pointer, or member function pointer that does not have a
> non-throwing
> - // exception-specification
> - case CallExprClass:
> - case CXXMemberCallExprClass:
> - case CXXOperatorCallExprClass:
> - case UserDefinedLiteralClass: {
> - const CallExpr *CE = cast<CallExpr>(this);
> - CanThrowResult CT;
> - if (isTypeDependent())
> - CT = CT_Dependent;
> - else if
> (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
> - CT = CT_Cannot;
> - else
> - CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
> - if (CT == CT_Can)
> - return CT;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - case CXXConstructExprClass:
> - case CXXTemporaryObjectExprClass: {
> - CanThrowResult CT = CanCalleeThrow(C, this,
> - cast<CXXConstructExpr>(this)->getConstructor());
> - if (CT == CT_Can)
> - return CT;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - case LambdaExprClass: {
> - const LambdaExpr *Lambda = cast<LambdaExpr>(this);
> - CanThrowResult CT = Expr::CT_Cannot;
> - for (LambdaExpr::capture_init_iterator Cap =
> Lambda->capture_init_begin(),
> - CapEnd =
> Lambda->capture_init_end();
> - Cap != CapEnd; ++Cap)
> - CT = MergeCanThrow(CT, (*Cap)->CanThrow(C));
> - return CT;
> - }
> -
> - case CXXNewExprClass: {
> - CanThrowResult CT;
> - if (isTypeDependent())
> - CT = CT_Dependent;
> - else
> - CT = CanCalleeThrow(C, this,
> cast<CXXNewExpr>(this)->getOperatorNew());
> - if (CT == CT_Can)
> - return CT;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - case CXXDeleteExprClass: {
> - CanThrowResult CT;
> - QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
> - if (DTy.isNull() || DTy->isDependentType()) {
> - CT = CT_Dependent;
> - } else {
> - CT = CanCalleeThrow(C, this,
> - cast<CXXDeleteExpr>(this)->getOperatorDelete());
> - if (const RecordType *RT = DTy->getAs<RecordType>()) {
> - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> - CT = MergeCanThrow(CT, CanCalleeThrow(C, this,
> RD->getDestructor()));
> - }
> - if (CT == CT_Can)
> - return CT;
> - }
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - case CXXBindTemporaryExprClass: {
> - // The bound temporary has to be destroyed again, which might throw.
> - CanThrowResult CT = CanCalleeThrow(C, this,
> - cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
> - if (CT == CT_Can)
> - return CT;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - // ObjC message sends are like function calls, but never have
> exception
> - // specs.
> - case ObjCMessageExprClass:
> - case ObjCPropertyRefExprClass:
> - case ObjCSubscriptRefExprClass:
> - return CT_Can;
> -
> - // All the ObjC literals that are implemented as calls are
> - // potentially throwing unless we decide to close off that
> - // possibility.
> - case ObjCArrayLiteralClass:
> - case ObjCDictionaryLiteralClass:
> - case ObjCNumericLiteralClass:
> - return CT_Can;
> -
> - // Many other things have subexpressions, so we have to test those.
> - // Some are simple:
> - case ConditionalOperatorClass:
> - case CompoundLiteralExprClass:
> - case CXXConstCastExprClass:
> - case CXXDefaultArgExprClass:
> - case CXXReinterpretCastExprClass:
> - case DesignatedInitExprClass:
> - case ExprWithCleanupsClass:
> - case ExtVectorElementExprClass:
> - case InitListExprClass:
> - case MemberExprClass:
> - case ObjCIsaExprClass:
> - case ObjCIvarRefExprClass:
> - case ParenExprClass:
> - case ParenListExprClass:
> - case ShuffleVectorExprClass:
> - case VAArgExprClass:
> - return CanSubExprsThrow(C, this);
> -
> - // Some might be dependent for other reasons.
> - case ArraySubscriptExprClass:
> - case BinaryOperatorClass:
> - case CompoundAssignOperatorClass:
> - case CStyleCastExprClass:
> - case CXXStaticCastExprClass:
> - case CXXFunctionalCastExprClass:
> - case ImplicitCastExprClass:
> - case MaterializeTemporaryExprClass:
> - case UnaryOperatorClass: {
> - CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
> - return MergeCanThrow(CT, CanSubExprsThrow(C, this));
> - }
> -
> - // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of
> worms.
> - case StmtExprClass:
> - return CT_Can;
> -
> - case ChooseExprClass:
> - if (isTypeDependent() || isValueDependent())
> - return CT_Dependent;
> - return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
> -
> - case GenericSelectionExprClass:
> - if (cast<GenericSelectionExpr>(this)->isResultDependent())
> - return CT_Dependent;
> - return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
> -
> - // Some expressions are always dependent.
> - case CXXDependentScopeMemberExprClass:
> - case CXXUnresolvedConstructExprClass:
> - case DependentScopeDeclRefExprClass:
> - return CT_Dependent;
> -
> - case AtomicExprClass:
> - case AsTypeExprClass:
> - case BinaryConditionalOperatorClass:
> - case BlockExprClass:
> - case CUDAKernelCallExprClass:
> - case DeclRefExprClass:
> - case ObjCBridgedCastExprClass:
> - case ObjCIndirectCopyRestoreExprClass:
> - case ObjCProtocolExprClass:
> - case ObjCSelectorExprClass:
> - case OffsetOfExprClass:
> - case PackExpansionExprClass:
> - case PseudoObjectExprClass:
> - case SubstNonTypeTemplateParmExprClass:
> - case SubstNonTypeTemplateParmPackExprClass:
> - case UnaryExprOrTypeTraitExprClass:
> - case UnresolvedLookupExprClass:
> - case UnresolvedMemberExprClass:
> - // FIXME: Can any of the above throw? If so, when?
> - return CT_Cannot;
> -
> - case AddrLabelExprClass:
> - case ArrayTypeTraitExprClass:
> - case BinaryTypeTraitExprClass:
> - case TypeTraitExprClass:
> - case CXXBoolLiteralExprClass:
> - case CXXNoexceptExprClass:
> - case CXXNullPtrLiteralExprClass:
> - case CXXPseudoDestructorExprClass:
> - case CXXScalarValueInitExprClass:
> - case CXXThisExprClass:
> - case CXXUuidofExprClass:
> - case CharacterLiteralClass:
> - case ExpressionTraitExprClass:
> - case FloatingLiteralClass:
> - case GNUNullExprClass:
> - case ImaginaryLiteralClass:
> - case ImplicitValueInitExprClass:
> - case IntegerLiteralClass:
> - case ObjCEncodeExprClass:
> - case ObjCStringLiteralClass:
> - case ObjCBoolLiteralExprClass:
> - case OpaqueValueExprClass:
> - case PredefinedExprClass:
> - case SizeOfPackExprClass:
> - case StringLiteralClass:
> - case UnaryTypeTraitExprClass:
> - // These expressions can never throw.
> - return CT_Cannot;
> -
> -#define STMT(CLASS, PARENT) case CLASS##Class:
> -#define STMT_RANGE(Base, First, Last)
> -#define LAST_STMT_RANGE(BASE, FIRST, LAST)
> -#define EXPR(CLASS, PARENT)
> -#define ABSTRACT_STMT(STMT)
> -#include "clang/AST/StmtNodes.inc"
> - case NoStmtClass:
> - llvm_unreachable("Invalid class for expression");
> - }
> - llvm_unreachable("Bogus StmtClass");
> -}
> -
> Expr* Expr::IgnoreParens() {
> Expr* E = this;
> while (true) {
>
> Modified: cfe/trunk/lib/AST/Type.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/Type.cpp (original)
> +++ cfe/trunk/lib/AST/Type.cpp Mon Apr 16 19:58:00 2012
> @@ -1546,6 +1546,13 @@
> else if (epi.NoexceptExpr->isInstantiationDependent())
> setInstantiationDependent();
> }
> + } else if (getExceptionSpecType() == EST_Uninstantiated) {
> + // Store the function decl from which we will resolve our
> + // exception specification.
> + FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot +
> numArgs);
> + *slot = epi.ExceptionSpecDecl;
> + // This exception specification doesn't make the type dependent,
> because
> + // it's not instantiated as part of instantiating the type.
> }
>
> if (epi.ConsumedArguments) {
> @@ -1629,6 +1636,8 @@
> ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
> } else if (epi.ExceptionSpecType == EST_ComputedNoexcept &&
> epi.NoexceptExpr){
> epi.NoexceptExpr->Profile(ID, Context, false);
> + } else if (epi.ExceptionSpecType == EST_Uninstantiated) {
> + ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
> }
> if (epi.ConsumedArguments) {
> for (unsigned i = 0; i != NumArgs; ++i)
>
> Modified: cfe/trunk/lib/Analysis/CFG.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Analysis/CFG.cpp (original)
> +++ cfe/trunk/lib/Analysis/CFG.cpp Mon Apr 16 19:58:00 2012
> @@ -1284,7 +1284,8 @@
> const FunctionType *FT = Ty->getAs<FunctionType>();
> if (FT) {
> if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
> - if (Proto->isNothrow(Ctx))
> + if (Proto->getExceptionSpecType() != EST_Uninstantiated &&
> + Proto->isNothrow(Ctx))
> return false;
> }
> return true;
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Apr 16 19:58:00 2012
> @@ -125,14 +125,17 @@
> }
> }
>
> -void Sema::ImplicitExceptionSpecification::CalledDecl(CXXMethodDecl
> *Method) {
> - assert(Context && "ImplicitExceptionSpecification without an
> ASTContext");
> +void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation
> CallLoc,
> + CXXMethodDecl
> *Method) {
> // If we have an MSAny or unknown spec already, don't bother.
> if (!Method || ComputedEST == EST_MSAny || ComputedEST == EST_Delayed)
> return;
>
> const FunctionProtoType *Proto
> = Method->getType()->getAs<FunctionProtoType>();
> + Proto = Self->ResolveExceptionSpec(CallLoc, Proto);
> + if (!Proto)
> + return;
>
> ExceptionSpecificationType EST = Proto->getExceptionSpecType();
>
> @@ -164,7 +167,8 @@
>
> // Check out noexcept specs.
> if (EST == EST_ComputedNoexcept) {
> - FunctionProtoType::NoexceptResult NR =
> Proto->getNoexceptSpec(*Context);
> + FunctionProtoType::NoexceptResult NR =
> + Proto->getNoexceptSpec(Self->Context);
> assert(NR != FunctionProtoType::NR_NoNoexcept &&
> "Must have noexcept result for EST_ComputedNoexcept.");
> assert(NR != FunctionProtoType::NR_Dependent &&
> @@ -188,7 +192,7 @@
> for (FunctionProtoType::exception_iterator E = Proto->exception_begin(),
> EEnd = Proto->exception_end();
> E != EEnd; ++E)
> - if (ExceptionsSeen.insert(Context->getCanonicalType(*E)))
> + if (ExceptionsSeen.insert(Self->Context.getCanonicalType(*E)))
> Exceptions.push_back(*E);
> }
>
> @@ -217,7 +221,7 @@
> // implicit definition. For now, we assume that any non-nothrow
> expression can
> // throw any exception.
>
> - if (E->CanThrow(*Context))
> + if (Self->canThrow(E))
> ComputedEST = EST_None;
> }
>
> @@ -3922,7 +3926,7 @@
> HadError = true;
> }
>
> - ImplicitExceptionSpecification Spec(Context);
> + ImplicitExceptionSpecification Spec(*this);
> bool Const;
> llvm::tie(Spec, Const) =
> ComputeDefaultedCopyCtorExceptionSpecAndConst(CD->getParent());
> @@ -4031,7 +4035,7 @@
> HadError = true;
> }
>
> - ImplicitExceptionSpecification Spec(Context);
> + ImplicitExceptionSpecification Spec(*this);
> bool Const;
> llvm::tie(Spec, Const) =
> ComputeDefaultedCopyCtorExceptionSpecAndConst(MD->getParent());
> @@ -6814,7 +6818,7 @@
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall
> have an
> // exception-specification. [...]
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
> if (ClassDecl->isInvalidDecl())
> return ExceptSpec;
>
> @@ -6831,7 +6835,7 @@
> // If this is a deleted function, add it anyway. This might be
> conformant
> // with the standard. This might not. I'm not sure. It might not
> matter.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
> }
> }
>
> @@ -6845,7 +6849,7 @@
> // If this is a deleted function, add it anyway. This might be
> conformant
> // with the standard. This might not. I'm not sure. It might not
> matter.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
> }
> }
>
> @@ -6868,7 +6872,7 @@
> // might just be ill-formed because this function attempts to refer
> to
> // a deleted function here.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(F->getLocation(), Constructor);
> }
> }
>
> @@ -6990,6 +6994,7 @@
> const FunctionProtoType *CtorTy =
> CtorDecl->getType()->castAs<FunctionProtoType>();
> if (CtorTy->getExceptionSpecType() == EST_Delayed) {
> + // FIXME: Don't do this unless the exception spec is needed.
> ImplicitExceptionSpecification Spec =
> ComputeDefaultedDefaultCtorExceptionSpec(ClassDecl);
> FunctionProtoType::ExtProtoInfo EPI = Spec.getEPI();
> @@ -7190,7 +7195,7 @@
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall
> have
> // an exception-specification.
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
> if (ClassDecl->isInvalidDecl())
> return ExceptSpec;
>
> @@ -7202,7 +7207,7 @@
> continue;
>
> if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
> - ExceptSpec.CalledDecl(
> + ExceptSpec.CalledDecl(B->getLocStart(),
>
> LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
> }
>
> @@ -7211,7 +7216,7 @@
> BEnd = ClassDecl->vbases_end();
> B != BEnd; ++B) {
> if (const RecordType *BaseType = B->getType()->getAs<RecordType>())
> - ExceptSpec.CalledDecl(
> + ExceptSpec.CalledDecl(B->getLocStart(),
>
> LookupDestructor(cast<CXXRecordDecl>(BaseType->getDecl())));
> }
>
> @@ -7221,7 +7226,7 @@
> F != FEnd; ++F) {
> if (const RecordType *RecordTy
> = Context.getBaseElementType(F->getType())->getAs<RecordType>())
> - ExceptSpec.CalledDecl(
> + ExceptSpec.CalledDecl(F->getLocation(),
>
> LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl())));
> }
>
> @@ -7546,7 +7551,7 @@
> Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst(
> CXXRecordDecl
> *ClassDecl) {
> if (ClassDecl->isInvalidDecl())
> - return std::make_pair(ImplicitExceptionSpecification(Context), false);
> + return std::make_pair(ImplicitExceptionSpecification(*this), false);
>
> // C++ [class.copy]p10:
> // If the class definition does not explicitly declare a copy
> @@ -7619,7 +7624,7 @@
> // Based on a similar decision made for constness in C++0x, we're erring
> on
> // the side of assuming such calls to be made regardless of whether they
> // actually happen.
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
> unsigned ArgQuals = HasConstCopyAssignment ? Qualifiers::Const : 0;
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> @@ -7631,7 +7636,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
> ArgQuals,
> false, 0))
> - ExceptSpec.CalledDecl(CopyAssign);
> + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
> }
>
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> @@ -7641,7 +7646,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXMethodDecl *CopyAssign = LookupCopyingAssignment(BaseClassDecl,
> ArgQuals,
> false, 0))
> - ExceptSpec.CalledDecl(CopyAssign);
> + ExceptSpec.CalledDecl(Base->getLocStart(), CopyAssign);
> }
>
> for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> @@ -7652,7 +7657,7 @@
> if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
> if (CXXMethodDecl *CopyAssign =
> LookupCopyingAssignment(FieldClassDecl, ArgQuals, false, 0))
> - ExceptSpec.CalledDecl(CopyAssign);
> + ExceptSpec.CalledDecl(Field->getLocation(), CopyAssign);
> }
> }
>
> @@ -7665,7 +7670,7 @@
> // for determining the argument type of the operator. Note also that
> // operators taking an object instead of a reference are allowed.
>
> - ImplicitExceptionSpecification Spec(Context);
> + ImplicitExceptionSpecification Spec(*this);
> bool Const;
> llvm::tie(Spec, Const) =
> ComputeDefaultedCopyAssignmentExceptionSpecAndConst(ClassDecl);
> @@ -8032,7 +8037,7 @@
>
> Sema::ImplicitExceptionSpecification
> Sema::ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl
> *ClassDecl) {
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
>
> if (ClassDecl->isInvalidDecl())
> return ExceptSpec;
> @@ -8059,7 +8064,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
> false, 0))
> - ExceptSpec.CalledDecl(MoveAssign);
> + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
> }
>
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> @@ -8069,7 +8074,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXMethodDecl *MoveAssign = LookupMovingAssignment(BaseClassDecl,
> false, 0))
> - ExceptSpec.CalledDecl(MoveAssign);
> + ExceptSpec.CalledDecl(Base->getLocStart(), MoveAssign);
> }
>
> for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> @@ -8080,7 +8085,7 @@
> if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
> if (CXXMethodDecl *MoveAssign =
> LookupMovingAssignment(FieldClassDecl,
> false, 0))
> - ExceptSpec.CalledDecl(MoveAssign);
> + ExceptSpec.CalledDecl(Field->getLocation(), MoveAssign);
> }
> }
>
> @@ -8578,7 +8583,7 @@
> std::pair<Sema::ImplicitExceptionSpecification, bool>
> Sema::ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl
> *ClassDecl) {
> if (ClassDecl->isInvalidDecl())
> - return std::make_pair(ImplicitExceptionSpecification(Context), false);
> + return std::make_pair(ImplicitExceptionSpecification(*this), false);
>
> // C++ [class.copy]p5:
> // The implicitly-declared copy constructor for a class X will
> @@ -8639,7 +8644,7 @@
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall
> have an
> // exception-specification. [...]
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
> unsigned Quals = HasConstCopyConstructor? Qualifiers::Const : 0;
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
> BaseEnd = ClassDecl->bases_end();
> @@ -8653,7 +8658,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXConstructorDecl *CopyConstructor =
> LookupCopyingConstructor(BaseClassDecl, Quals))
> - ExceptSpec.CalledDecl(CopyConstructor);
> + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
> }
> for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
> BaseEnd = ClassDecl->vbases_end();
> @@ -8663,7 +8668,7 @@
> =
> cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
> if (CXXConstructorDecl *CopyConstructor =
> LookupCopyingConstructor(BaseClassDecl, Quals))
> - ExceptSpec.CalledDecl(CopyConstructor);
> + ExceptSpec.CalledDecl(Base->getLocStart(), CopyConstructor);
> }
> for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
> FieldEnd = ClassDecl->field_end();
> @@ -8673,7 +8678,7 @@
> if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
> if (CXXConstructorDecl *CopyConstructor =
> LookupCopyingConstructor(FieldClassDecl, Quals))
> - ExceptSpec.CalledDecl(CopyConstructor);
> + ExceptSpec.CalledDecl(Field->getLocation(), CopyConstructor);
> }
> }
>
> @@ -8686,7 +8691,7 @@
> // If the class definition does not explicitly declare a copy
> // constructor, one is declared implicitly.
>
> - ImplicitExceptionSpecification Spec(Context);
> + ImplicitExceptionSpecification Spec(*this);
> bool Const;
> llvm::tie(Spec, Const) =
> ComputeDefaultedCopyCtorExceptionSpecAndConst(ClassDecl);
> @@ -8784,7 +8789,7 @@
> // C++ [except.spec]p14:
> // An implicitly declared special member function (Clause 12) shall
> have an
> // exception-specification. [...]
> - ImplicitExceptionSpecification ExceptSpec(Context);
> + ImplicitExceptionSpecification ExceptSpec(*this);
> if (ClassDecl->isInvalidDecl())
> return ExceptSpec;
>
> @@ -8801,7 +8806,7 @@
> // If this is a deleted function, add it anyway. This might be
> conformant
> // with the standard. This might not. I'm not sure. It might not
> matter.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
> }
> }
>
> @@ -8815,7 +8820,7 @@
> // If this is a deleted function, add it anyway. This might be
> conformant
> // with the standard. This might not. I'm not sure. It might not
> matter.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(B->getLocStart(), Constructor);
> }
> }
>
> @@ -8833,7 +8838,7 @@
> // might just be ill-formed because this function attempts to refer
> to
> // a deleted function here.
> if (Constructor)
> - ExceptSpec.CalledDecl(Constructor);
> + ExceptSpec.CalledDecl(F->getLocation(), Constructor);
> }
> }
>
> @@ -11116,6 +11121,7 @@
> FindCXXThisExpr Finder(*this);
>
> switch (Proto->getExceptionSpecType()) {
> + case EST_Uninstantiated:
> case EST_BasicNoexcept:
> case EST_Delayed:
> case EST_DynamicNone:
>
> Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Mon Apr 16 19:58:00 2012
> @@ -96,6 +96,26 @@
> return FnT->hasExceptionSpec();
> }
>
> +const FunctionProtoType *
> +Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType
> *FPT) {
> + // FIXME: If FD is a special member, we should delay computing its
> exception
> + // specification until this point.
> + if (FPT->getExceptionSpecType() != EST_Uninstantiated)
> + return FPT;
> +
> + FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
> + const FunctionProtoType *SourceFPT =
> + SourceDecl->getType()->castAs<FunctionProtoType>();
> +
> + if (SourceFPT->getExceptionSpecType() != EST_Uninstantiated)
> + return SourceFPT;
> +
> + // Instantiate the exception specification now.
> + InstantiateExceptionSpec(Loc, SourceDecl);
> +
> + return SourceDecl->getType()->castAs<FunctionProtoType>();
> +}
> +
> bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl
> *New) {
> OverloadedOperatorKind OO =
> New->getDeclName().getCXXOverloadedOperator();
> bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
> @@ -104,7 +124,7 @@
> unsigned DiagID = diag::err_mismatched_exception_spec;
> if (getLangOpts().MicrosoftExt)
> DiagID = diag::warn_mismatched_exception_spec;
> -
> +
> if (!CheckEquivalentExceptionSpec(PDiag(DiagID),
> PDiag(diag::note_previous_declaration),
>
> Old->getType()->getAs<FunctionProtoType>(),
> @@ -295,6 +315,13 @@
> if (MissingEmptyExceptionSpecification)
> *MissingEmptyExceptionSpecification = false;
>
> + Old = ResolveExceptionSpec(NewLoc, Old);
> + if (!Old)
> + return false;
> + New = ResolveExceptionSpec(NewLoc, New);
> + if (!New)
> + return false;
> +
> // C++0x [except.spec]p3: Two exception-specifications are compatible if:
> // - both are non-throwing, regardless of their form,
> // - both have the form noexcept(constant-expression) and the constant-
> @@ -318,6 +345,7 @@
> ExceptionSpecificationType NewEST = New->getExceptionSpecType();
>
> assert(OldEST != EST_Delayed && NewEST != EST_Delayed &&
> + OldEST != EST_Uninstantiated && NewEST != EST_Uninstantiated &&
> "Shouldn't see unknown exception specifications here");
>
> // Shortcut the case where both have no spec.
> @@ -483,6 +511,14 @@
> if (!SubLoc.isValid())
> SubLoc = SuperLoc;
>
> + // Resolve the exception specifications, if needed.
> + Superset = ResolveExceptionSpec(SuperLoc, Superset);
> + if (!Superset)
> + return false;
> + Subset = ResolveExceptionSpec(SubLoc, Subset);
> + if (!Subset)
> + return false;
> +
> ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
>
> // If superset contains everything, we're done.
> @@ -507,6 +543,7 @@
> ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
>
> assert(SuperEST != EST_Delayed && SubEST != EST_Delayed &&
> + SuperEST != EST_Uninstantiated && SubEST != EST_Uninstantiated &&
> "Shouldn't see unknown exception specifications here");
>
> // It does not. If the subset contains everything, we've failed.
> @@ -726,4 +763,324 @@
> New->getLocation());
> }
>
> +static CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) {
> + Expr *E = const_cast<Expr*>(CE);
> + CanThrowResult R = CT_Cannot;
> + for (Expr::child_range I = E->children(); I && R != CT_Can; ++I)
> + R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I)));
> + return R;
> +}
> +
> +static CanThrowResult canCalleeThrow(Sema &S, const Expr *E,
> + const Decl *D,
> + bool NullThrows = true) {
> + if (!D)
> + return NullThrows ? CT_Can : CT_Cannot;
> +
> + // See if we can get a function type from the decl somehow.
> + const ValueDecl *VD = dyn_cast<ValueDecl>(D);
> + if (!VD) // If we have no clue what we're calling, assume the worst.
> + return CT_Can;
> +
> + // As an extension, we assume that __attribute__((nothrow)) functions
> don't
> + // throw.
> + if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
> + return CT_Cannot;
> +
> + QualType T = VD->getType();
> + const FunctionProtoType *FT;
> + if ((FT = T->getAs<FunctionProtoType>())) {
> + } else if (const PointerType *PT = T->getAs<PointerType>())
> + FT = PT->getPointeeType()->getAs<FunctionProtoType>();
> + else if (const ReferenceType *RT = T->getAs<ReferenceType>())
> + FT = RT->getPointeeType()->getAs<FunctionProtoType>();
> + else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
> + FT = MT->getPointeeType()->getAs<FunctionProtoType>();
> + else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
> + FT = BT->getPointeeType()->getAs<FunctionProtoType>();
> +
> + if (!FT)
> + return CT_Can;
> +
> + FT = S.ResolveExceptionSpec(E->getLocStart(), FT);
> + if (!FT)
> + return CT_Can;
> +
> + if (FT->getExceptionSpecType() == EST_Delayed) {
> + // FIXME: Try to resolve a delayed exception spec in
> ResolveExceptionSpec.
> + assert(isa<CXXConstructorDecl>(D) &&
> + "only constructor exception specs can be unknown");
> + S.Diag(E->getLocStart(), diag::err_exception_spec_unknown)
> + << E->getSourceRange();
> + return CT_Can;
> + }
> +
> + return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
> +}
> +
> +static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
> + if (DC->isTypeDependent())
> + return CT_Dependent;
> +
> + if (!DC->getTypeAsWritten()->isReferenceType())
> + return CT_Cannot;
> +
> + if (DC->getSubExpr()->isTypeDependent())
> + return CT_Dependent;
> +
> + return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
> +}
> +
> +static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
> + if (DC->isTypeOperand())
> + return CT_Cannot;
> +
> + Expr *Op = DC->getExprOperand();
> + if (Op->isTypeDependent())
> + return CT_Dependent;
> +
> + const RecordType *RT = Op->getType()->getAs<RecordType>();
> + if (!RT)
> + return CT_Cannot;
> +
> + if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
> + return CT_Cannot;
> +
> + if (Op->Classify(S.Context).isPRValue())
> + return CT_Cannot;
> +
> + return CT_Can;
> +}
> +
> +CanThrowResult Sema::canThrow(const Expr *E) {
> + // C++ [expr.unary.noexcept]p3:
> + // [Can throw] if in a potentially-evaluated context the expression
> would
> + // contain:
> + switch (E->getStmtClass()) {
> + case Expr::CXXThrowExprClass:
> + // - a potentially evaluated throw-expression
> + return CT_Can;
> +
> + case Expr::CXXDynamicCastExprClass: {
> + // - a potentially evaluated dynamic_cast expression
> dynamic_cast<T>(v),
> + // where T is a reference type, that requires a run-time check
> + CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E));
> + if (CT == CT_Can)
> + return CT;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + case Expr::CXXTypeidExprClass:
> + // - a potentially evaluated typeid expression applied to a glvalue
> + // expression whose type is a polymorphic class type
> + return canTypeidThrow(*this, cast<CXXTypeidExpr>(E));
> +
> + // - a potentially evaluated call to a function, member function,
> function
> + // pointer, or member function pointer that does not have a
> non-throwing
> + // exception-specification
> + case Expr::CallExprClass:
> + case Expr::CXXMemberCallExprClass:
> + case Expr::CXXOperatorCallExprClass:
> + case Expr::UserDefinedLiteralClass: {
> + const CallExpr *CE = cast<CallExpr>(E);
> + CanThrowResult CT;
> + if (E->isTypeDependent())
> + CT = CT_Dependent;
> + else if
> (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
> + CT = CT_Cannot;
> + else
> + CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
> + if (CT == CT_Can)
> + return CT;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + case Expr::CXXConstructExprClass:
> + case Expr::CXXTemporaryObjectExprClass: {
> + CanThrowResult CT = canCalleeThrow(*this, E,
> + cast<CXXConstructExpr>(E)->getConstructor());
> + if (CT == CT_Can)
> + return CT;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + case Expr::LambdaExprClass: {
> + const LambdaExpr *Lambda = cast<LambdaExpr>(E);
> + CanThrowResult CT = CT_Cannot;
> + for (LambdaExpr::capture_init_iterator Cap =
> Lambda->capture_init_begin(),
> + CapEnd =
> Lambda->capture_init_end();
> + Cap != CapEnd; ++Cap)
> + CT = mergeCanThrow(CT, canThrow(*Cap));
> + return CT;
> + }
> +
> + case Expr::CXXNewExprClass: {
> + CanThrowResult CT;
> + if (E->isTypeDependent())
> + CT = CT_Dependent;
> + else
> + CT = canCalleeThrow(*this, E,
> cast<CXXNewExpr>(E)->getOperatorNew());
> + if (CT == CT_Can)
> + return CT;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + case Expr::CXXDeleteExprClass: {
> + CanThrowResult CT;
> + QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType();
> + if (DTy.isNull() || DTy->isDependentType()) {
> + CT = CT_Dependent;
> + } else {
> + CT = canCalleeThrow(*this, E,
> + cast<CXXDeleteExpr>(E)->getOperatorDelete());
> + if (const RecordType *RT = DTy->getAs<RecordType>()) {
> + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
> + CT = mergeCanThrow(CT, canCalleeThrow(*this, E,
> RD->getDestructor()));
> + }
> + if (CT == CT_Can)
> + return CT;
> + }
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + case Expr::CXXBindTemporaryExprClass: {
> + // The bound temporary has to be destroyed again, which might throw.
> + CanThrowResult CT = canCalleeThrow(*this, E,
> + cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor());
> + if (CT == CT_Can)
> + return CT;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + // ObjC message sends are like function calls, but never have
> exception
> + // specs.
> + case Expr::ObjCMessageExprClass:
> + case Expr::ObjCPropertyRefExprClass:
> + case Expr::ObjCSubscriptRefExprClass:
> + return CT_Can;
> +
> + // All the ObjC literals that are implemented as calls are
> + // potentially throwing unless we decide to close off that
> + // possibility.
> + case Expr::ObjCArrayLiteralClass:
> + case Expr::ObjCDictionaryLiteralClass:
> + case Expr::ObjCNumericLiteralClass:
> + return CT_Can;
> +
> + // Many other things have subexpressions, so we have to test those.
> + // Some are simple:
> + case Expr::ConditionalOperatorClass:
> + case Expr::CompoundLiteralExprClass:
> + case Expr::CXXConstCastExprClass:
> + case Expr::CXXDefaultArgExprClass:
> + case Expr::CXXReinterpretCastExprClass:
> + case Expr::DesignatedInitExprClass:
> + case Expr::ExprWithCleanupsClass:
> + case Expr::ExtVectorElementExprClass:
> + case Expr::InitListExprClass:
> + case Expr::MemberExprClass:
> + case Expr::ObjCIsaExprClass:
> + case Expr::ObjCIvarRefExprClass:
> + case Expr::ParenExprClass:
> + case Expr::ParenListExprClass:
> + case Expr::ShuffleVectorExprClass:
> + case Expr::VAArgExprClass:
> + return canSubExprsThrow(*this, E);
> +
> + // Some might be dependent for other reasons.
> + case Expr::ArraySubscriptExprClass:
> + case Expr::BinaryOperatorClass:
> + case Expr::CompoundAssignOperatorClass:
> + case Expr::CStyleCastExprClass:
> + case Expr::CXXStaticCastExprClass:
> + case Expr::CXXFunctionalCastExprClass:
> + case Expr::ImplicitCastExprClass:
> + case Expr::MaterializeTemporaryExprClass:
> + case Expr::UnaryOperatorClass: {
> + CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot;
> + return mergeCanThrow(CT, canSubExprsThrow(*this, E));
> + }
> +
> + // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of
> worms.
> + case Expr::StmtExprClass:
> + return CT_Can;
> +
> + case Expr::ChooseExprClass:
> + if (E->isTypeDependent() || E->isValueDependent())
> + return CT_Dependent;
> + return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
> +
> + case Expr::GenericSelectionExprClass:
> + if (cast<GenericSelectionExpr>(E)->isResultDependent())
> + return CT_Dependent;
> + return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr());
> +
> + // Some expressions are always dependent.
> + case Expr::CXXDependentScopeMemberExprClass:
> + case Expr::CXXUnresolvedConstructExprClass:
> + case Expr::DependentScopeDeclRefExprClass:
> + return CT_Dependent;
> +
> + case Expr::AsTypeExprClass:
> + case Expr::BinaryConditionalOperatorClass:
> + case Expr::BlockExprClass:
> + case Expr::CUDAKernelCallExprClass:
> + case Expr::DeclRefExprClass:
> + case Expr::ObjCBridgedCastExprClass:
> + case Expr::ObjCIndirectCopyRestoreExprClass:
> + case Expr::ObjCProtocolExprClass:
> + case Expr::ObjCSelectorExprClass:
> + case Expr::OffsetOfExprClass:
> + case Expr::PackExpansionExprClass:
> + case Expr::PseudoObjectExprClass:
> + case Expr::SubstNonTypeTemplateParmExprClass:
> + case Expr::SubstNonTypeTemplateParmPackExprClass:
> + case Expr::UnaryExprOrTypeTraitExprClass:
> + case Expr::UnresolvedLookupExprClass:
> + case Expr::UnresolvedMemberExprClass:
> + // FIXME: Can any of the above throw? If so, when?
> + return CT_Cannot;
> +
> + case Expr::AddrLabelExprClass:
> + case Expr::ArrayTypeTraitExprClass:
> + case Expr::AtomicExprClass:
> + case Expr::BinaryTypeTraitExprClass:
> + case Expr::TypeTraitExprClass:
> + case Expr::CXXBoolLiteralExprClass:
> + case Expr::CXXNoexceptExprClass:
> + case Expr::CXXNullPtrLiteralExprClass:
> + case Expr::CXXPseudoDestructorExprClass:
> + case Expr::CXXScalarValueInitExprClass:
> + case Expr::CXXThisExprClass:
> + case Expr::CXXUuidofExprClass:
> + case Expr::CharacterLiteralClass:
> + case Expr::ExpressionTraitExprClass:
> + case Expr::FloatingLiteralClass:
> + case Expr::GNUNullExprClass:
> + case Expr::ImaginaryLiteralClass:
> + case Expr::ImplicitValueInitExprClass:
> + case Expr::IntegerLiteralClass:
> + case Expr::ObjCEncodeExprClass:
> + case Expr::ObjCStringLiteralClass:
> + case Expr::ObjCBoolLiteralExprClass:
> + case Expr::OpaqueValueExprClass:
> + case Expr::PredefinedExprClass:
> + case Expr::SizeOfPackExprClass:
> + case Expr::StringLiteralClass:
> + case Expr::UnaryTypeTraitExprClass:
> + // These expressions can never throw.
> + return CT_Cannot;
> +
> +#define STMT(CLASS, PARENT) case Expr::CLASS##Class:
> +#define STMT_RANGE(Base, First, Last)
> +#define LAST_STMT_RANGE(BASE, FIRST, LAST)
> +#define EXPR(CLASS, PARENT)
> +#define ABSTRACT_STMT(STMT)
> +#include "clang/AST/StmtNodes.inc"
> + case Expr::NoStmtClass:
> + llvm_unreachable("Invalid class for expression");
> + }
> + llvm_unreachable("Bogus StmtClass");
> +}
> +
> } // end namespace clang
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Apr 16 19:58:00 2012
> @@ -9773,6 +9773,13 @@
> // FIXME: Is this really right?
> if (CurContext == Func) return;
>
> + // Instantiate the exception specification for any function which is
> + // used: CodeGen will need it.
> + if (Func->getTemplateInstantiationPattern() &&
> + Func->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
> + == EST_Uninstantiated)
> + InstantiateExceptionSpec(Loc, Func);
> +
> // Implicit instantiation of function templates and member functions of
> // class templates.
> if (Func->isImplicitlyInstantiable()) {
>
> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Apr 16 19:58:00 2012
> @@ -3135,6 +3135,9 @@
> FoundAssign = true;
> const FunctionProtoType *CPT
> = Operator->getType()->getAs<FunctionProtoType>();
> + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> + if (!CPT)
> + return false;
> if (CPT->getExceptionSpecType() == EST_Delayed)
> return false;
> if (!CPT->isNothrow(Self.Context))
> @@ -3174,6 +3177,9 @@
> FoundConstructor = true;
> const FunctionProtoType *CPT
> = Constructor->getType()->getAs<FunctionProtoType>();
> + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> + if (!CPT)
> + return false;
> if (CPT->getExceptionSpecType() == EST_Delayed)
> return false;
> // FIXME: check whether evaluating default arguments can throw.
> @@ -3209,6 +3215,9 @@
> if (Constructor->isDefaultConstructor()) {
> const FunctionProtoType *CPT
> = Constructor->getType()->getAs<FunctionProtoType>();
> + CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
> + if (!CPT)
> + return false;
> if (CPT->getExceptionSpecType() == EST_Delayed)
> return false;
> // TODO: check whether evaluating default arguments can throw.
> @@ -5203,9 +5212,9 @@
>
> ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr
> *Operand,
> SourceLocation RParen) {
> + CanThrowResult CanThrow = canThrow(Operand);
> return Owned(new (Context) CXXNoexceptExpr(Context.BoolTy, Operand,
> - Operand->CanThrow(Context),
> - KeyLoc, RParen));
> + CanThrow, KeyLoc, RParen));
> }
>
> ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Apr 16 19:58:00 2012
> @@ -11150,6 +11150,7 @@
> VK_LValue,
> Found.getDecl(),
> TemplateArgs);
> + MarkDeclRefReferenced(DRE);
> DRE->setHadMultipleCandidates(ULE->getNumDecls() > 1);
> return DRE;
> }
> @@ -11178,6 +11179,7 @@
> VK_LValue,
> Found.getDecl(),
> TemplateArgs);
> + MarkDeclRefReferenced(DRE);
> DRE->setHadMultipleCandidates(MemExpr->getNumDecls() > 1);
> return DRE;
> } else {
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Apr 16 19:58:00 2012
> @@ -153,6 +153,7 @@
> bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const {
> switch (Kind) {
> case TemplateInstantiation:
> + case ExceptionSpecInstantiation:
> case DefaultTemplateArgumentInstantiation:
> case DefaultFunctionArgumentInstantiation:
> return true;
> @@ -190,6 +191,29 @@
> }
> }
>
> +Sema::InstantiatingTemplate::
> +InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
> + FunctionDecl *Entity, ExceptionSpecification,
> + SourceRange InstantiationRange)
> + : SemaRef(SemaRef),
> + SavedInNonInstantiationSFINAEContext(
> +
> SemaRef.InNonInstantiationSFINAEContext)
> +{
> + Invalid = CheckInstantiationDepth(PointOfInstantiation,
> + InstantiationRange);
> + if (!Invalid) {
> + ActiveTemplateInstantiation Inst;
> + Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
> + Inst.PointOfInstantiation = PointOfInstantiation;
> + Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
> + Inst.TemplateArgs = 0;
> + Inst.NumTemplateArgs = 0;
> + Inst.InstantiationRange = InstantiationRange;
> + SemaRef.InNonInstantiationSFINAEContext = false;
> + SemaRef.ActiveTemplateInstantiations.push_back(Inst);
> + }
> +}
> +
> Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
> SourceLocation
> PointOfInstantiation,
> TemplateDecl *Template,
> @@ -592,6 +616,13 @@
> << Active->InstantiationRange;
> break;
> }
> +
> + case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
> + Diags.Report(Active->PointOfInstantiation,
> + diag::note_template_exception_spec_instantiation_here)
> + << cast<FunctionDecl>((Decl *)Active->Entity)
> + << Active->InstantiationRange;
> + break;
> }
> }
> }
> @@ -609,6 +640,7 @@
> switch(Active->Kind) {
> case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
> case ActiveTemplateInstantiation::TemplateInstantiation:
> + case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
> // This is a template instantiation, so there is no SFINAE.
> return llvm::Optional<TemplateDeductionInfo *>();
>
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Apr 16 19:58:00
> 2012
> @@ -2215,6 +2215,194 @@
> return NewTInfo;
> }
>
> +/// Introduce the instantiated function parameters into the local
> +/// instantiation scope, and set the parameter names to those used
> +/// in the template.
> +static void addInstantiatedParametersToScope(Sema &S, FunctionDecl
> *Function,
> + const FunctionDecl
> *PatternDecl,
> + LocalInstantiationScope
> &Scope,
> + const MultiLevelTemplateArgumentList
> &TemplateArgs) {
> + unsigned FParamIdx = 0;
> + for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
> + const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
> + if (!PatternParam->isParameterPack()) {
> + // Simple case: not a parameter pack.
> + assert(FParamIdx < Function->getNumParams());
> + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> + FunctionParam->setDeclName(PatternParam->getDeclName());
> + Scope.InstantiatedLocal(PatternParam, FunctionParam);
> + ++FParamIdx;
> + continue;
> + }
> +
> + // Expand the parameter pack.
> + Scope.MakeInstantiatedLocalArgPack(PatternParam);
> + unsigned NumArgumentsInExpansion
> + = S.getNumArgumentsInExpansion(PatternParam->getType(),
> TemplateArgs);
> + for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
> + ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> + FunctionParam->setDeclName(PatternParam->getDeclName());
> + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
> + ++FParamIdx;
> + }
> + }
> +}
> +
> +static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
> + const FunctionProtoType *Proto,
> + const MultiLevelTemplateArgumentList
> &TemplateArgs) {
> + // C++11 [expr.prim.general]p3:
> + // If a declaration declares a member function or member function
> + // template of a class X, the expression this is a prvalue of type
> + // "pointer to cv-qualifier-seq X" between the optional
> cv-qualifer-seq
> + // and the end of the function-definition, member-declarator, or
> + // declarator.
> + CXXRecordDecl *ThisContext = 0;
> + unsigned ThisTypeQuals = 0;
> + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
> + ThisContext = Method->getParent();
> + ThisTypeQuals = Method->getTypeQualifiers();
> + }
> + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
> + SemaRef.getLangOpts().CPlusPlus0x);
> +
> + // The function has an exception specification or a "noreturn"
> + // attribute. Substitute into each of the exception types.
> + SmallVector<QualType, 4> Exceptions;
> + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
> + // FIXME: Poor location information!
> + if (const PackExpansionType *PackExpansion
> + = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
> + // We have a pack expansion. Instantiate it.
> + SmallVector<UnexpandedParameterPack, 2> Unexpanded;
> + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
> + Unexpanded);
> + assert(!Unexpanded.empty() &&
> + "Pack expansion without parameter packs?");
> +
> + bool Expand = false;
> + bool RetainExpansion = false;
> + llvm::Optional<unsigned> NumExpansions
> + =
> PackExpansion->getNumExpansions();
> + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
> + SourceRange(),
> + Unexpanded,
> + TemplateArgs,
> + Expand,
> + RetainExpansion,
> + NumExpansions))
> + break;
> +
> + if (!Expand) {
> + // We can't expand this pack expansion into separate arguments
> yet;
> + // just substitute into the pattern and create a new pack
> expansion
> + // type.
> + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
> + QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> + TemplateArgs,
> + New->getLocation(),
> New->getDeclName());
> + if (T.isNull())
> + break;
> +
> + T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
> + Exceptions.push_back(T);
> + continue;
> + }
> +
> + // Substitute into the pack expansion pattern for each template
> + bool Invalid = false;
> + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
> + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef,
> ArgIdx);
> +
> + QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> + TemplateArgs,
> + New->getLocation(),
> New->getDeclName());
> + if (T.isNull()) {
> + Invalid = true;
> + break;
> + }
> +
> + Exceptions.push_back(T);
> + }
> +
> + if (Invalid)
> + break;
> +
> + continue;
> + }
> +
> + QualType T
> + = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
> + New->getLocation(), New->getDeclName());
> + if (T.isNull() ||
> + SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
> + continue;
> +
> + Exceptions.push_back(T);
> + }
> + Expr *NoexceptExpr = 0;
> + if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
> + EnterExpressionEvaluationContext Unevaluated(SemaRef,
> + Sema::ConstantEvaluated);
> + ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
> + if (E.isUsable())
> + E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart());
> +
> + if (E.isUsable()) {
> + NoexceptExpr = E.take();
> + if (!NoexceptExpr->isTypeDependent() &&
> + !NoexceptExpr->isValueDependent())
> + NoexceptExpr =
> SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
> + 0, SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
> + /*AllowFold*/ false).take();
> + }
> + }
> +
> + // Rebuild the function type
> + const FunctionProtoType *NewProto
> + = New->getType()->getAs<FunctionProtoType>();
> + assert(NewProto && "Template instantiation without function
> prototype?");
> +
> + FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
> + EPI.ExceptionSpecType = Proto->getExceptionSpecType();
> + EPI.NumExceptions = Exceptions.size();
> + EPI.Exceptions = Exceptions.data();
> + EPI.NoexceptExpr = NoexceptExpr;
> +
> + New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> + NewProto->arg_type_begin(),
> + NewProto->getNumArgs(),
> + EPI));
> +}
> +
> +void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
> + FunctionDecl *Decl) {
> + FunctionDecl *Tmpl = Decl->getTemplateInstantiationPattern();
> + assert(Tmpl && "can't instantiate non-template");
> +
> + if (Decl->getType()->castAs<FunctionProtoType>()->getExceptionSpecType()
> + != EST_Uninstantiated)
> + return;
> +
> + InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl,
> +
> InstantiatingTemplate::ExceptionSpecification());
> + if (Inst)
> + return;
> +
> + // Enter the scope of this instantiation. We don't use
> + // PushDeclContext because we don't have a scope.
> + Sema::ContextRAII savedContext(*this, Decl);
> + LocalInstantiationScope Scope(*this);
> +
> + MultiLevelTemplateArgumentList TemplateArgs =
> + getTemplateInstantiationArgs(Decl, 0, /*RelativeToPrimary*/true);
> +
> + addInstantiatedParametersToScope(*this, Decl, Tmpl, Scope,
> TemplateArgs);
> +
> + const FunctionProtoType *Proto =
> Tmpl->getType()->castAs<FunctionProtoType>();
> + ::InstantiateExceptionSpec(*this, Decl, Proto, TemplateArgs);
> +}
> +
> /// \brief Initializes the common fields of an instantiation function
> /// declaration (New) from the corresponding fields of its template
> (Tmpl).
> ///
> @@ -2252,135 +2440,32 @@
> assert(Proto && "Function template without prototype?");
>
> if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) {
> - // C++11 [expr.prim.general]p3:
> - // If a declaration declares a member function or member function
> - // template of a class X, the expression this is a prvalue of type
> - // "pointer to cv-qualifier-seq X" between the optional
> cv-qualifer-seq
> - // and the end of the function-definition, member-declarator, or
> - // declarator.
> - CXXRecordDecl *ThisContext = 0;
> - unsigned ThisTypeQuals = 0;
> - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) {
> - ThisContext = Method->getParent();
> - ThisTypeQuals = Method->getTypeQualifiers();
> - }
> - Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
> - SemaRef.getLangOpts().CPlusPlus0x);
> -
> -
> - // The function has an exception specification or a "noreturn"
> - // attribute. Substitute into each of the exception types.
> - SmallVector<QualType, 4> Exceptions;
> - for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) {
> - // FIXME: Poor location information!
> - if (const PackExpansionType *PackExpansion
> - = Proto->getExceptionType(I)->getAs<PackExpansionType>()) {
> - // We have a pack expansion. Instantiate it.
> - SmallVector<UnexpandedParameterPack, 2> Unexpanded;
> -
> SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
> - Unexpanded);
> - assert(!Unexpanded.empty() &&
> - "Pack expansion without parameter packs?");
> -
> - bool Expand = false;
> - bool RetainExpansion = false;
> - llvm::Optional<unsigned> NumExpansions
> - =
> PackExpansion->getNumExpansions();
> - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
> - SourceRange(),
> - Unexpanded,
> - TemplateArgs,
> - Expand,
> - RetainExpansion,
> - NumExpansions))
> - break;
> -
> - if (!Expand) {
> - // We can't expand this pack expansion into separate arguments
> yet;
> - // just substitute into the pattern and create a new pack
> expansion
> - // type.
> - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
> - QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> - TemplateArgs,
> - New->getLocation(),
> New->getDeclName());
> - if (T.isNull())
> - break;
> -
> - T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
> - Exceptions.push_back(T);
> - continue;
> - }
> -
> - // Substitute into the pack expansion pattern for each template
> - bool Invalid = false;
> - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
> - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef,
> ArgIdx);
> -
> - QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
> - TemplateArgs,
> - New->getLocation(),
> New->getDeclName());
> - if (T.isNull()) {
> - Invalid = true;
> - break;
> - }
> -
> - Exceptions.push_back(T);
> - }
> -
> - if (Invalid)
> - break;
> -
> - continue;
> - }
> -
> - QualType T
> - = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
> - New->getLocation(), New->getDeclName());
> - if (T.isNull() ||
> - SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
> - continue;
> + FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
>
> - Exceptions.push_back(T);
> - }
> - Expr *NoexceptExpr = 0;
> - if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) {
> - EnterExpressionEvaluationContext Unevaluated(SemaRef,
> -
> Sema::ConstantEvaluated);
> - ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs);
> - if (E.isUsable())
> - E = SemaRef.CheckBooleanCondition(E.get(),
> E.get()->getLocStart());
> -
> - if (E.isUsable()) {
> - NoexceptExpr = E.take();
> - if (!NoexceptExpr->isTypeDependent() &&
> - !NoexceptExpr->isValueDependent())
> - NoexceptExpr =
> SemaRef.VerifyIntegerConstantExpression(NoexceptExpr,
> - 0,
> SemaRef.PDiag(diag::err_noexcept_needs_constant_expression),
> - /*AllowFold*/ false).take();
> - }
> + // DR1330: In C++11, defer instantiation of a non-trivial
> + // exception specification.
> + if (SemaRef.getLangOpts().CPlusPlus0x &&
> + EPI.ExceptionSpecType != EST_None &&
> + EPI.ExceptionSpecType != EST_DynamicNone &&
> + EPI.ExceptionSpecType != EST_BasicNoexcept) {
> + // Mark the function has having an uninstantiated exception
> specification.
> + const FunctionProtoType *NewProto
> + = New->getType()->getAs<FunctionProtoType>();
> + assert(NewProto && "Template instantiation without function
> prototype?");
> + EPI = NewProto->getExtProtoInfo();
> + EPI.ExceptionSpecType = EST_Uninstantiated;
> + EPI.ExceptionSpecDecl = New;
> +
> New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> +
> NewProto->arg_type_begin(),
> + NewProto->getNumArgs(),
> + EPI));
> + } else {
> + ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
> }
> -
> - // Rebuild the function type
> -
> - FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
> - EPI.ExceptionSpecType = Proto->getExceptionSpecType();
> - EPI.NumExceptions = Exceptions.size();
> - EPI.Exceptions = Exceptions.data();
> - EPI.NoexceptExpr = NoexceptExpr;
> - EPI.ExtInfo = Proto->getExtInfo();
> -
> - const FunctionProtoType *NewProto
> - = New->getType()->getAs<FunctionProtoType>();
> - assert(NewProto && "Template instantiation without function
> prototype?");
> -
> New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
> -
> NewProto->arg_type_begin(),
> - NewProto->getNumArgs(),
> - EPI));
> }
>
> - const FunctionDecl* Definition = Tmpl;
> -
> // Get the definition. Leaves the variable unchanged if undefined.
> + const FunctionDecl *Definition = Tmpl;
> Tmpl->isDefined(Definition);
>
> SemaRef.InstantiateAttrs(TemplateArgs, Definition, New,
> @@ -2538,33 +2623,8 @@
> MultiLevelTemplateArgumentList TemplateArgs =
> getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
>
> - // Introduce the instantiated function parameters into the local
> - // instantiation scope, and set the parameter names to those used
> - // in the template.
> - unsigned FParamIdx = 0;
> - for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
> - const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
> - if (!PatternParam->isParameterPack()) {
> - // Simple case: not a parameter pack.
> - assert(FParamIdx < Function->getNumParams());
> - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> - FunctionParam->setDeclName(PatternParam->getDeclName());
> - Scope.InstantiatedLocal(PatternParam, FunctionParam);
> - ++FParamIdx;
> - continue;
> - }
> -
> - // Expand the parameter pack.
> - Scope.MakeInstantiatedLocalArgPack(PatternParam);
> - unsigned NumArgumentsInExpansion
> - = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
> - for (unsigned Arg = 0; Arg < NumArgumentsInExpansion; ++Arg) {
> - ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
> - FunctionParam->setDeclName(PatternParam->getDeclName());
> - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
> - ++FParamIdx;
> - }
> - }
> + addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
> + TemplateArgs);
>
> if (PatternDecl->isDefaulted()) {
> ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
>
> Modified: cfe/trunk/lib/Sema/TreeTransform.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/TreeTransform.h (original)
> +++ cfe/trunk/lib/Sema/TreeTransform.h Mon Apr 16 19:58:00 2012
> @@ -4181,10 +4181,7 @@
> unsigned ThisTypeQuals)
> {
> // Transform the parameters and return type.
> //
> - // We instantiate in source order, with the return type first followed
> by
> - // the parameters, because users tend to expect this (even if they
> shouldn't
> - // rely on it!).
> - //
> + // We are required to instantiate the params and return type in source
> order.
> // When the function has a trailing return type, we instantiate the
> // parameters before the return type, since the return type can then
> refer
> // to the parameters themselves (via decltype, sizeof, etc.).
> @@ -4230,6 +4227,8 @@
> return QualType();
> }
>
> + // FIXME: Need to transform the exception-specification too.
> +
> QualType Result = TL.getType();
> if (getDerived().AlwaysRebuild() ||
> ResultType != T->getResultType() ||
>
> Modified: cfe/trunk/test/CXX/except/except.spec/p1.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CXX/except/except.spec/p1.cpp (original)
> +++ cfe/trunk/test/CXX/except/except.spec/p1.cpp Mon Apr 16 19:58:00 2012
> @@ -65,7 +65,7 @@
> }
>
> template<typename T>
> - void g(T x) noexcept((sizeof(T) == sizeof(int)) || f(x)) { }
> + void g(T x) noexcept((sizeof(T) == sizeof(int)) || noexcept(f(x))) { }
>
> void h() {
> g(1);
> @@ -77,5 +77,5 @@
> static int f() noexcept(1/X) { return 10; } //
> expected-error{{argument to noexcept specifier must be a constant
> expression}} expected-note{{division by zero}}
> };
>
> - void g() { A<0>::f(); } // expected-note{{in instantiation of template
> class 'PR11084::A<0>' requested here}}
> + void g() { A<0>::f(); } // expected-note{{in instantiation of exception
> specification for 'f' requested here}}
> }
>
> Added: cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp?rev=154886&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/cxx11-exception-spec.cpp Mon Apr 16 19:58:00
> 2012
> @@ -0,0 +1,18 @@
> +// RUN: %clang_cc1 -std=c++11 -verify -emit-llvm %s -o - | FileCheck %s
> +
> +template<typename T> void f() noexcept(sizeof(T) == 4);
> +
> +void g() {
> + // CHECK: declare void @_Z1fIiEvv() nounwind
> + f<int>();
> + // CHECK: declare void @_Z1fIA2_iEvv()
> + f<int[2]>();
> + // CHECK: declare void @_Z1fIfEvv() nounwind
> + void (*f1)() = &f<float>;
> + // CHECK: declare void @_Z1fIdEvv()
> + void (*f2)() = &f<double>;
> + // CHECK: declare void @_Z1fIA4_cEvv() nounwind
> + (void)&f<char[4]>;
> + // CHECK: declare void @_Z1fIcEvv()
> + (void)&f<char>;
> +}
>
> Modified: cfe/trunk/test/SemaTemplate/instantiate-declref.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-declref.cpp?rev=154886&r1=154885&r2=154886&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-declref.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/instantiate-declref.cpp Mon Apr 16
> 19:58:00 2012
> @@ -105,3 +105,13 @@
> }
> template void f(int const &); // expected-note {{requested here}}
> }
> +
> +namespace test2 {
> + template<typename T> void f() {
> + T::error; // expected-error {{no member}}
> + }
> + void g() {
> + // This counts as an odr-use, so should trigger the instantiation of
> f<int>.
> + (void)&f<int>; // expected-note {{here}}
> + }
> +}
>
> Added: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=154886&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> (added)
> +++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Mon
> Apr 16 19:58:00 2012
> @@ -0,0 +1,107 @@
> +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 %s
> +
> +// DR1330: an exception specification for a function template is only
> +// instantiated when it is needed.
> +
> +template<typename T> void f1(T*) throw(T); // expected-error{{incomplete
> type 'Incomplete' is not allowed in exception specification}}
> +struct Incomplete; // expected-note{{forward}}
> +
> +void test_f1(Incomplete *incomplete_p, int *int_p) {
> + f1(int_p);
> + f1(incomplete_p); // expected-note{{instantiation of exception spec}}
> +}
> +
> +template<typename T> struct A {
> + template<typename U> struct B {
> + static void f() noexcept(A<U>().n);
> + };
> +
> + constexpr A() : n(true) {}
> + bool n;
> +};
> +
> +static_assert(noexcept(A<int>::B<char>::f()), "");
> +
> +template<unsigned N> struct S {
> + static void recurse() noexcept(noexcept(S<N+1>::recurse())); // \
> + // expected-error {{no member named 'recurse'}} \
> + // expected-note 9{{instantiation of exception spec}}
> +};
> +decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed
> +decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
> +
> +template<> struct S<10> {};
> +void (*pFn2)() noexcept = &S<0>::recurse; // expected-note
> {{instantiation of exception spec}}
> +
> +
> +template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
> +// expected-error 16{{call to function 'go' that is neither visible}} \
> +// expected-note 16{{'go' should be declared prior to the call site}} \
> +// expected-error {{recursive template instantiation exceeded maximum
> depth of 16}} \
> +// expected-error {{use of undeclared identifier 'go'}} \
> +
> +void f() {
> + int k = go(0); // \
> + // expected-note {{in instantiation of exception specification for
> 'go<int>' requested here}}
> +}
> +
> +
> +namespace dr1330_example {
> + template <class T> struct A {
> + void f(...) throw (typename T::X); // expected-error {{'int'}}
> + void f(int);
> + };
> +
> + int main() {
> + A<int>().f(42);
> + }
> +
> + int test2() {
> + struct S {
> + template<typename T>
> + static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; }
> // \
> + // expected-note {{instantiation of exception spec}}
> + typedef decltype(f<S>()) X;
> + };
> + S().f<S>(); // ok
> + S().f<int>(); // expected-note {{instantiation of exception spec}}
> + }
> +}
> +
> +namespace core_19754_example {
> + template<typename T> T declval() noexcept;
> +
> + template<typename T, typename = decltype(T(declval<T&&>()))>
> + struct is_movable { static const bool value = true; };
> +
> + template<typename T>
> + struct wrap {
> + T val;
> + void irrelevant(wrap &p) noexcept(is_movable<T>::value);
> + };
> +
> + template<typename T>
> + struct base {
> + base() {}
> + base(const typename T::type1 &);
> + base(const typename T::type2 &);
> + };
> +
> + template<typename T>
> + struct type1 {
> + wrap<typename T::base> base;
> + };
> +
> + template<typename T>
> + struct type2 {
> + wrap<typename T::base> base;
> + };
> +
> + struct types {
> + typedef base<types> base;
> + typedef type1<types> type1;
> + typedef type2<types> type2;
> + };
> +
> + base<types> val = base<types>();
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20120418/f4c5a3ee/attachment.html>
More information about the cfe-commits
mailing list