diff options
| author | Hans Wennborg <hans@hanshq.net> | 2014-09-18 16:01:32 +0000 |
|---|---|---|
| committer | Hans Wennborg <hans@hanshq.net> | 2014-09-18 16:01:32 +0000 |
| commit | e113c20c1d8834383c89ee395eb37887cd3919fe (patch) | |
| tree | 9e6775c2d4e655b622ca637dcaa6b430324240a5 /clang | |
| parent | 6462f948847dc54ad498cb899fc8ec216a810bbd (diff) | |
| download | bcm5719-llvm-e113c20c1d8834383c89ee395eb37887cd3919fe.tar.gz bcm5719-llvm-e113c20c1d8834383c89ee395eb37887cd3919fe.zip | |
Revert r217995 and follow-ups:
r218053: Use exceptions() instead of getNumExceptions()/getExceptionType() to avoid
r218011: Work around MSVC parser bug by putting redundant braces around the body of
r217997: Skip parens when detecting whether we're instantiating a function declaration.
r217995: Instantiate exception specifications when instantiating function types (other
The Windows build was broken for 16 hours and no one had any good ideas of how to
fix it. Reverting for now to make the builders green. See the cfe-commits thread [1] for
more info.
This was the build error (from [2]):
C:\bb-win7\ninja-clang-i686-msc17-R\llvm-project\clang\lib\Sema\SemaTemplateInstantiate.cpp(1590) : error C2668: '`anonymous-namespace'::TemplateInstantiator::TransformFunctionProtoType' : ambiguous call to overloaded function
C:\bb-win7\ninja-clang-i686-msc17-R\llvm-project\clang\lib\Sema\SemaTemplateInstantiate.cpp(1313): could be 'clang::QualType `anonymous-namespace'::TemplateInstantiator::TransformFunctionProtoType<clang::Sema::SubstFunctionDeclType::<lambda_756edcbe7bd5c7584849a6e3a1491735>>(clang::TypeLocBuilder &,clang::FunctionProtoTypeLoc,clang::CXXRecordDecl *,unsigned int,Fn)'
with
[
Fn=clang::Sema::SubstFunctionDeclType::<lambda_756edcbe7bd5c7584849a6e3a1491735>
]
c:\bb-win7\ninja-clang-i686-msc17-r\llvm-project\clang\lib\sema\TreeTransform.h(4532): or 'clang::QualType clang::TreeTransform<Derived>::TransformFunctionProtoType<clang::Sema::SubstFunctionDeclType::<lambda_756edcbe7bd5c7584849a6e3a1491735>>(clang::TypeLocBuilder &,clang::FunctionProtoTypeLoc,clang::CXXRecordDecl *,unsigned int,Fn)'
with
[
Derived=`anonymous-namespace'::TemplateInstantiator,
Fn=clang::Sema::SubstFunctionDeclType::<lambda_756edcbe7bd5c7584849a6e3a1491735>
]
while trying to match the argument list '(clang::TypeLocBuilder, clang::FunctionProtoTypeLoc, clang::CXXRecordDecl *, unsigned int, clang::Sema::SubstFunctionDeclType::<lambda_756edcbe7bd5c7584849a6e3a1491735>)'
1. http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20140915/115011.html
2. http://bb.pgr.jp/builders/ninja-clang-i686-msc17-R/builds/10515/steps/build_clang_tools_1/logs/stdio
llvm-svn: 218058
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/AST/DataRecursiveASTVisitor.h | 40 | ||||
| -rw-r--r-- | clang/include/clang/AST/Expr.h | 31 | ||||
| -rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 40 | ||||
| -rw-r--r-- | clang/include/clang/AST/Type.h | 4 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 5 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 27 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 32 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 24 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 60 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 168 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/TreeTransform.h | 156 | ||||
| -rw-r--r-- | clang/test/CXX/except/except.spec/p1.cpp | 9 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp | 41 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/instantiate-exception-spec.cpp | 21 |
15 files changed, 242 insertions, 419 deletions
diff --git a/clang/include/clang/AST/DataRecursiveASTVisitor.h b/clang/include/clang/AST/DataRecursiveASTVisitor.h index d08abb7d975..0612231e915 100644 --- a/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -876,9 +876,6 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) @@ -1087,9 +1084,6 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) @@ -2129,29 +2123,21 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); - - if (S->hasExplicitParameters() && S->hasExplicitResultType()) { - // Visit the whole type. - TRY_TO(TraverseTypeLoc(TL)); - } else { - if (S->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { - TRY_TO(TraverseDecl(Proto.getParam(I))); + if (S->hasExplicitParameters() || S->hasExplicitResultType()) { + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getParam(I))); + } + } else { + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); } - } else if (S->hasExplicitResultType()) { - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); } - - auto *T = Proto.getTypePtr(); - for (const auto &E : T->exceptions()) { - TRY_TO(TraverseType(E)); - } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); } TRY_TO(TraverseLambdaBody(S)); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index d940232077d..f730a26ed42 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2673,23 +2673,20 @@ private: } protected: - CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind, - Expr *op, unsigned BasePathSize) - : Expr(SC, ty, VK, OK_Ordinary, - // Cast expressions are type-dependent if the type is - // dependent (C++ [temp.dep.expr]p3). - ty->isDependentType(), - // Cast expressions are value-dependent if the type is - // dependent or if the subexpression is value-dependent. - ty->isDependentType() || (op && op->isValueDependent()), - (ty->isInstantiationDependentType() || - (op && op->isInstantiationDependent())), - // An implicit cast expression doesn't (lexically) contain an - // unexpanded pack, even if its target type does. - ((SC != ImplicitCastExprClass && - ty->containsUnexpandedParameterPack()) || - (op && op->containsUnexpandedParameterPack()))), - Op(op) { + CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + const CastKind kind, Expr *op, unsigned BasePathSize) : + Expr(SC, ty, VK, OK_Ordinary, + // Cast expressions are type-dependent if the type is + // dependent (C++ [temp.dep.expr]p3). + ty->isDependentType(), + // Cast expressions are value-dependent if the type is + // dependent or if the subexpression is value-dependent. + ty->isDependentType() || (op && op->isValueDependent()), + (ty->isInstantiationDependentType() || + (op && op->isInstantiationDependent())), + (ty->containsUnexpandedParameterPack() || + (op && op->containsUnexpandedParameterPack()))), + Op(op) { assert(kind != CK_Invalid && "creating cast with invalid cast kind"); CastExprBits.Kind = kind; setBasePathSize(BasePathSize); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 0adb09b617d..19c01e0212f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -941,9 +941,6 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPE(UnresolvedUsingType, {}) @@ -1152,9 +1149,6 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, { for (const auto &E : T->exceptions()) { TRY_TO(TraverseType(E)); } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); }) DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {}) @@ -2151,29 +2145,21 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>(); - - if (S->hasExplicitParameters() && S->hasExplicitResultType()) { - // Visit the whole type. - TRY_TO(TraverseTypeLoc(TL)); - } else { - if (S->hasExplicitParameters()) { - // Visit parameters. - for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { - TRY_TO(TraverseDecl(Proto.getParam(I))); + if (S->hasExplicitParameters() || S->hasExplicitResultType()) { + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getParam(I))); + } + } else { + TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); } - } else if (S->hasExplicitResultType()) { - TRY_TO(TraverseTypeLoc(Proto.getReturnLoc())); - } - - auto *T = Proto.getTypePtr(); - for (const auto &E : T->exceptions()) { - TRY_TO(TraverseType(E)); } - - if (Expr *NE = T->getNoexceptExpr()) - TRY_TO(TraverseStmt(NE)); } TRY_TO(TraverseLambdaBody(S)); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 2a6ac2db30d..13915864831 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3012,8 +3012,6 @@ public: bool hasNoexceptExceptionSpec() const { return isNoexceptExceptionSpec(getExceptionSpecType()); } - /// \brief Return whether this function has a dependent exception spec. - bool hasDependentExceptionSpec() const; /// \brief Result type of getNoexceptSpec(). enum NoexceptResult { NR_NoNoexcept, ///< There is no noexcept specifier. @@ -5249,8 +5247,8 @@ template <typename T> const T *Type::castAs() const { ArrayType_cannot_be_used_with_getAs<T> at; (void) at; - if (const T *ty = dyn_cast<T>(this)) return ty; assert(isa<T>(CanonicalType)); + if (const T *ty = dyn_cast<T>(this)) return ty; return cast<T>(getUnqualifiedDesugaredType()); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index dd41418e96d..3755256da96 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4025,8 +4025,7 @@ public: /// \brief Check the given exception-specification and update the /// exception specification information with the results. - void checkExceptionSpecification(bool IsTopLevel, - ExceptionSpecificationType EST, + void checkExceptionSpecification(ExceptionSpecificationType EST, ArrayRef<ParsedType> DynamicExceptions, ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr, @@ -6653,8 +6652,6 @@ public: DeclarationName Entity, CXXRecordDecl *ThisContext, unsigned ThisTypeQuals); - void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, - const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 7834bfda6da..35676da641d 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1623,9 +1623,9 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, QualType *exnSlot = argSlot + NumParams; unsigned I = 0; for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) { - // Note that a dependent exception specification does *not* make - // a type dependent; it's not even part of the C++ type system. - if (ExceptionType->isInstantiationDependentType()) + if (ExceptionType->isDependentType()) + setDependent(); + else if (ExceptionType->isInstantiationDependentType()) setInstantiationDependent(); if (ExceptionType->containsUnexpandedParameterPack()) @@ -1639,12 +1639,11 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, *noexSlot = epi.ExceptionSpec.NoexceptExpr; if (epi.ExceptionSpec.NoexceptExpr) { - if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || - epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) + if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() + || epi.ExceptionSpec.NoexceptExpr->isTypeDependent()) + setDependent(); + else if (epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) setInstantiationDependent(); - - if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); } } else if (getExceptionSpecType() == EST_Uninstantiated) { // Store the function decl from which we will resolve our @@ -1670,18 +1669,6 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } } -bool FunctionProtoType::hasDependentExceptionSpec() const { - if (Expr *NE = getNoexceptExpr()) - return NE->isValueDependent(); - for (QualType ET : exceptions()) - // A pack expansion with a non-dependent pattern is still dependent, - // because we don't know whether the pattern is in the exception spec - // or not (that depends on whether the pack has 0 expansions). - if (ET->isDependentType() || ET->getAs<PackExpansionType>()) - return true; - return false; -} - FunctionProtoType::NoexceptResult FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { ExceptionSpecificationType est = getExceptionSpecType(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a03e308f99b..006a3c49d7c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13051,12 +13051,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { return false; } -void Sema::checkExceptionSpecification( - bool IsTopLevel, ExceptionSpecificationType EST, - ArrayRef<ParsedType> DynamicExceptions, - ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr, - SmallVectorImpl<QualType> &Exceptions, - FunctionProtoType::ExceptionSpecInfo &ESI) { +void +Sema::checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr, + SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExceptionSpecInfo &ESI) { Exceptions.clear(); ESI.Type = EST; if (EST == EST_Dynamic) { @@ -13065,15 +13066,13 @@ void Sema::checkExceptionSpecification( // FIXME: Preserve type source info. QualType ET = GetTypeFromParser(DynamicExceptions[ei]); - if (IsTopLevel) { - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - collectUnexpandedParameterPacks(ET, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks( - DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType, - Unexpanded); - continue; - } + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(ET, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), + UPPC_ExceptionType, + Unexpanded); + continue; } // Check that the type is valid for an exception spec, and @@ -13092,8 +13091,7 @@ void Sema::checkExceptionSpecification( NoexceptExpr->getType()->getCanonicalTypeUnqualified() == Context.BoolTy) && "Parser should have made sure that the expression is boolean"); - if (IsTopLevel && NoexceptExpr && - DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { ESI.Type = EST_BasicNoexcept; return; } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 4e4de5a3e7f..e4963b13d64 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -720,11 +720,10 @@ static bool CheckSpecForTypesEquivalent(Sema &S, /// assignment and override compatibility check. We do not check the parameters /// of parameter function pointers recursively, as no sane programmer would /// even be able to write such a function type. -bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, - const FunctionProtoType *Target, - SourceLocation TargetLoc, - const FunctionProtoType *Source, - SourceLocation SourceLoc) { +bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, + const FunctionProtoType *Target, SourceLocation TargetLoc, + const FunctionProtoType *Source, SourceLocation SourceLoc) +{ if (CheckSpecForTypesEquivalent( *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(), Target->getReturnType(), TargetLoc, Source->getReturnType(), @@ -745,30 +744,23 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, return false; } -bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { +bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) +{ // First we check for applicability. // Target type must be a function, function pointer or function reference. const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); - if (!ToFunc || ToFunc->hasDependentExceptionSpec()) + if (!ToFunc) return false; // SourceType must be a function or function pointer. const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); - if (!FromFunc || FromFunc->hasDependentExceptionSpec()) + if (!FromFunc) return false; // Now we've got the correct types on both sides, check their compatibility. // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. - // - // FIXME: If there is a nested dependent exception specification, we should - // not be checking it here. This is fine: - // template<typename T> void f() { - // void (*p)(void (*) throw(T)); - // void (*q)(void (*) throw(int)) = p; - // } - // ... because it might be instantiated with T=int. return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), PDiag(), ToFunc, From->getSourceRange().getBegin(), diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 25b2802f029..f44780407ba 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -788,14 +788,12 @@ namespace { /// pack. ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); - // Pull in the base class overload; it just forwards to our function. - using inherited::TransformFunctionProtoType; - template<typename Fn> + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, - Fn TransformExceptionSpec); + unsigned ThisTypeQuals); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1309,16 +1307,21 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( E->getParam()); } -template<typename Fn> +QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL) { + // We need a local instantiation scope for this function prototype. + LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return inherited::TransformFunctionProtoType(TLB, TL); +} + QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, - Fn TransformExceptionSpec) { + unsigned ThisTypeQuals) { // We need a local instantiation scope for this function prototype. LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType( - TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec); + return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, + ThisTypeQuals); } ParmVarDecl * @@ -1553,8 +1556,7 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { /// A form of SubstType intended specifically for instantiating the /// type of a FunctionDecl. Its purpose is solely to force the -/// instantiation of default-argument expressions and to avoid -/// instantiating an exception-specification. +/// instantiation of default-argument expressions. TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, @@ -1577,17 +1579,9 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, QualType Result; - if (FunctionProtoTypeLoc Proto = - TL.IgnoreParens().getAs<FunctionProtoTypeLoc>()) { - // Instantiate the type, other than its exception specification. The - // exception specification is instantiated in InitFunctionInstantiation - // once we've built the FunctionDecl. - // FIXME: Set the exception specification to EST_Uninstantiated here, - // instead of rebuilding the function type again later. - Result = Instantiator.TransformFunctionProtoType( - TLB, Proto, ThisContext, ThisTypeQuals, - [](FunctionProtoType::ExceptionSpecInfo &ESI, - bool &Changed) { return false; }); + if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { + Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext, + ThisTypeQuals); } else { Result = Instantiator.TransformType(TLB, TL); } @@ -1597,26 +1591,6 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return TLB.getTypeSourceInfo(Context, Result); } -void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, - const MultiLevelTemplateArgumentList &Args) { - FunctionProtoType::ExceptionSpecInfo ESI = - Proto->getExtProtoInfo().ExceptionSpec; - assert(ESI.Type != EST_Uninstantiated); - - TemplateInstantiator Instantiator(*this, Args, New->getLocation(), - New->getDeclName()); - - SmallVector<QualType, 4> ExceptionStorage; - bool Changed = false; - if (Instantiator.TransformExceptionSpec( - New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI, - ExceptionStorage, Changed)) - // On error, recover by dropping the exception specification. - ESI.Type = EST_None; - - UpdateExceptionSpec(New, ESI); -} - ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ddd47ee1e3c..62a3e11ac9a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2988,7 +2988,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. -static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, +static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -2999,22 +2999,15 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, // Simple case: not a parameter pack. assert(FParamIdx < Function->getNumParams()); ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - FunctionParam->setDeclName(PatternParam->getDeclName()); // If the parameter's type is not dependent, update it to match the type // in the pattern. They can differ in top-level cv-qualifiers, and we want // the pattern's type here. If the type is dependent, they can't differ, - // per core issue 1668. Substitute into the type from the pattern, in case - // it's instantiation-dependent. + // per core issue 1668. // FIXME: Updating the type to work around this is at best fragile. - if (!PatternDecl->getType()->isDependentType()) { - QualType T = S.SubstType(PatternParam->getType(), TemplateArgs, - FunctionParam->getLocation(), - FunctionParam->getDeclName()); - if (T.isNull()) - return true; - FunctionParam->setType(T); - } + if (!PatternDecl->getType()->isDependentType()) + FunctionParam->setType(PatternParam->getType()); + FunctionParam->setDeclName(PatternParam->getDeclName()); Scope.InstantiatedLocal(PatternParam, FunctionParam); ++FParamIdx; continue; @@ -3026,27 +3019,136 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); assert(NumArgumentsInExpansion && "should only be called when all template arguments are known"); - QualType PatternType = - PatternParam->getType()->castAs<PackExpansionType>()->getPattern(); for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + if (!PatternDecl->getType()->isDependentType()) + FunctionParam->setType(PatternParam->getType()); + FunctionParam->setDeclName(PatternParam->getDeclName()); - if (!PatternDecl->getType()->isDependentType()) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); - QualType T = S.SubstType(PatternType, TemplateArgs, - FunctionParam->getLocation(), - FunctionParam->getDeclName()); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; + } + } +} + +static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New, + const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &TemplateArgs) { + assert(Proto->getExceptionSpecType() != EST_Uninstantiated); + + // 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 = nullptr; + unsigned ThisTypeQuals = 0; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getTypeQualifiers(); + } + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals, + SemaRef.getLangOpts().CPlusPlus11); + + // 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; + 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()) - return true; - FunctionParam->setType(T); + break; + + T = SemaRef.Context.getPackExpansionType(T, NumExpansions); + Exceptions.push_back(T); + continue; } - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; + // 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 = nullptr; + 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.get(); + if (!NoexceptExpr->isTypeDependent() && + !NoexceptExpr->isValueDependent()) + NoexceptExpr + = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, + nullptr, diag::err_noexcept_needs_constant_expression, + /*AllowFold*/ false).get(); } } - return false; + FunctionProtoType::ExceptionSpecInfo ESI; + ESI.Type = Proto->getExceptionSpecType(); + ESI.Exceptions = Exceptions; + ESI.NoexceptExpr = NoexceptExpr; + + SemaRef.UpdateExceptionSpec(New, ESI); } void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, @@ -3073,14 +3175,11 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); FunctionDecl *Template = Proto->getExceptionSpecTemplate(); - if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, - TemplateArgs)) { - UpdateExceptionSpec(Decl, EST_None); - return; - } + addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs); - SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(), - TemplateArgs); + ::InstantiateExceptionSpec(*this, Decl, + Template->getType()->castAs<FunctionProtoType>(), + TemplateArgs); } /// \brief Initializes the common fields of an instantiation function @@ -3149,7 +3248,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, New->setType(SemaRef.Context.getFunctionType( NewProto->getReturnType(), NewProto->getParamTypes(), EPI)); } else { - SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs); + ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs); } } @@ -3339,9 +3438,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); - if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, - TemplateArgs)) - return; + addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs); // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 76649a8acb6..51f36feaa46 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2989,8 +2989,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, NoexceptExpr = FTI.NoexceptExpr; } - S.checkExceptionSpecification(D.isFunctionDeclarationContext(), - FTI.getExceptionSpecType(), + S.checkExceptionSpecification(FTI.getExceptionSpecType(), DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 07ce0273e1e..92baa0ebd22 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -542,17 +542,10 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" - template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, - Fn TransformExceptionSpec); - - bool TransformExceptionSpec(SourceLocation Loc, - FunctionProtoType::ExceptionSpecInfo &ESI, - SmallVectorImpl<QualType> &Exceptions, - bool &Changed); + unsigned ThisTypeQuals); StmtResult TransformSEHHandler(Stmt *Handler); @@ -4519,19 +4512,15 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { - SmallVector<QualType, 4> ExceptionStorage; - return getDerived().TransformFunctionProtoType( - TLB, TL, nullptr, 0, - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return TransformExceptionSpec(TL.getBeginLoc(), ESI, ExceptionStorage, - Changed); - }); -} - -template<typename Derived> template<typename Fn> -QualType TreeTransform<Derived>::TransformFunctionProtoType( - TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, Fn TransformExceptionSpec) { + return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0); +} + +template<typename Derived> +QualType +TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals) { // Transform the parameters and return type. // // We are required to instantiate the params and return type in source order. @@ -4576,21 +4565,15 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( return QualType(); } - FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); - - bool EPIChanged = false; - if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged)) - return QualType(); - - // FIXME: Need to transform ConsumedParameters for variadic template - // expansion. + // FIXME: Need to transform the exception-specification too. QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || T->getNumParams() != ParamTypes.size() || !std::equal(T->param_type_begin(), T->param_type_end(), - ParamTypes.begin()) || EPIChanged) { - Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI); + ParamTypes.begin())) { + Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, + T->getExtProtoInfo()); if (Result.isNull()) return QualType(); } @@ -4607,107 +4590,6 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( } template<typename Derived> -bool TreeTransform<Derived>::TransformExceptionSpec( - SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, - SmallVectorImpl<QualType> &Exceptions, bool &Changed) { - assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated); - - // Instantiate a dynamic noexcept expression, if any. - if (ESI.Type == EST_ComputedNoexcept) { - EnterExpressionEvaluationContext Unevaluated(getSema(), - Sema::ConstantEvaluated); - ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); - if (NoexceptExpr.isInvalid()) - return true; - - NoexceptExpr = getSema().CheckBooleanCondition( - NoexceptExpr.get(), NoexceptExpr.get()->getLocStart()); - if (NoexceptExpr.isInvalid()) - return true; - - if (!NoexceptExpr.get()->isValueDependent()) { - NoexceptExpr = getSema().VerifyIntegerConstantExpression( - NoexceptExpr.get(), nullptr, - diag::err_noexcept_needs_constant_expression, - /*AllowFold*/false); - if (NoexceptExpr.isInvalid()) - return true; - } - - if (ESI.NoexceptExpr != NoexceptExpr.get()) - Changed = true; - ESI.NoexceptExpr = NoexceptExpr.get(); - } - - if (ESI.Type != EST_Dynamic) - return false; - - // Instantiate a dynamic exception specification's type. - for (QualType T : ESI.Exceptions) { - if (const PackExpansionType *PackExpansion = - T->getAs<PackExpansionType>()) { - Changed = true; - - // We have a pack expansion. Instantiate it. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); - - // Determine whether the set of unexpanded parameter packs can and - // should - // be expanded. - bool Expand = false; - bool RetainExpansion = false; - Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); - // FIXME: Track the location of the ellipsis (and track source location - // information for the types in the exception specification in general). - if (getDerived().TryExpandParameterPacks( - Loc, SourceRange(), Unexpanded, Expand, - RetainExpansion, NumExpansions)) - return true; - - 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(getSema(), -1); - QualType U = getDerived().TransformType(PackExpansion->getPattern()); - if (U.isNull()) - return true; - - U = SemaRef.Context.getPackExpansionType(U, NumExpansions); - Exceptions.push_back(U); - continue; - } - - // Substitute into the pack expansion pattern for each slice of the - // pack. - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); - - QualType U = getDerived().TransformType(PackExpansion->getPattern()); - if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) - return true; - - Exceptions.push_back(U); - } - } else { - QualType U = getDerived().TransformType(T); - if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) - return true; - if (T != U) - Changed = true; - - Exceptions.push_back(U); - } - } - - ESI.Exceptions = Exceptions; - return false; -} - -template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( TypeLocBuilder &TLB, FunctionNoProtoTypeLoc TL) { @@ -9024,13 +8906,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // transformed parameters. TypeLocBuilder NewCallOpTLBuilder; - SmallVector<QualType, 4> ExceptionStorage; - QualType NewCallOpType = TransformFunctionProtoType( - NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0, - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, - ExceptionStorage, Changed); - }); + QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, + OldCallOpFPTL, + nullptr, 0); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } diff --git a/clang/test/CXX/except/except.spec/p1.cpp b/clang/test/CXX/except/except.spec/p1.cpp index fa53c9f5d23..a32f37d5520 100644 --- a/clang/test/CXX/except/except.spec/p1.cpp +++ b/clang/test/CXX/except/except.spec/p1.cpp @@ -77,12 +77,5 @@ namespace PR11084 { static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}} }; - template<int X> void f() { - int (*p)() noexcept(1/X); // 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 exception specification for 'f'}} - f<0>(); // expected-note{{in instantiation of function template specialization}} - } + void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}} } diff --git a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index f62ef61758a..a376f0e5fd5 100644 --- a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -58,13 +58,6 @@ namespace dr1330_example { S().f<S>(); // ok S().f<int>(); // expected-note {{instantiation of exception spec}} } - - template<typename T> - struct U { - void f() noexcept(T::error); - void (g)() noexcept(T::error); - }; - U<int> uint; // ok } namespace core_19754_example { @@ -144,37 +137,3 @@ namespace PR12763 { }; void X::g() {} // expected-note {{in instantiation of}} } - -namespace Variadic { - template<bool B> void check() { static_assert(B, ""); } - template<bool B, bool B2, bool ...Bs> void check() { static_assert(B, ""); check<B2, Bs...>(); } - - template<typename ...T> void consume(T...); - - template<typename ...T> void f(void (*...p)() throw (T)) { - void (*q[])() = { p... }; - consume((p(),0)...); - } - template<bool ...B> void g(void (*...p)() noexcept (B)) { - consume((p(),0)...); - check<noexcept(p()) == B ...>(); - } - template<typename ...T> void i() { - consume([]() throw(T) {} ...); - consume([]() noexcept(sizeof(T) == 4) {} ...); - } - template<bool ...B> void j() { - consume([](void (*p)() noexcept(B)) { - void (*q)() noexcept = p; // expected-error {{not superset of source}} - } ...); - } - - void z() { - f<int, char, double>(nullptr, nullptr, nullptr); - g<true, false, true>(nullptr, nullptr, nullptr); - i<int, long, short>(); - j<true, true>(); - j<true, false>(); // expected-note {{in instantiation of}} - } - -} diff --git a/clang/test/SemaTemplate/instantiate-exception-spec.cpp b/clang/test/SemaTemplate/instantiate-exception-spec.cpp index d3411722283..993ee8dfae1 100644 --- a/clang/test/SemaTemplate/instantiate-exception-spec.cpp +++ b/clang/test/SemaTemplate/instantiate-exception-spec.cpp @@ -1,7 +1,5 @@ -// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -verify %s -DERRORS -// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -emit-llvm-only %s +// RUN: %clang_cc1 -fsyntax-only -verify %s -#ifdef ERRORS template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}} struct Incomplete; // expected-note{{forward}} @@ -9,20 +7,3 @@ void test_f1(Incomplete *incomplete_p, int *int_p) { f1(int_p); f1(incomplete_p); // expected-note{{instantiation of}} } -#endif - -template<typename T> void f(void (*p)() throw(T)) { -#ifdef ERRORS - void (*q)() throw(char) = p; // expected-error {{target exception spec}} - - extern void (*p2)() throw(T); - void (*q2)() throw(char) = p2; // expected-error {{target exception spec}} - - extern void (*p3)() throw(char); - void (*q3)() throw(T) = p3; // expected-error {{target exception spec}} - - void (*q4)() throw(T) = p2; // ok -#endif - p(); -} -void g() { f<int>(0); } // expected-note {{instantiation of}} |

