From: Hans Wennborg Date: Thu, 18 Sep 2014 16:01:32 +0000 (+0000) Subject: Revert r217995 and follow-ups: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5032e400cdd5ba066a00d0d1391d2649bbce920e;p=clang 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::TypeLocBuilder &,clang::FunctionProtoTypeLoc,clang::CXXRecordDecl *,unsigned int,Fn)' with [ Fn=clang::Sema::SubstFunctionDeclType:: ] c:\bb-win7\ninja-clang-i686-msc17-r\llvm-project\clang\lib\sema\TreeTransform.h(4532): or 'clang::QualType clang::TreeTransform::TransformFunctionProtoType>(clang::TypeLocBuilder &,clang::FunctionProtoTypeLoc,clang::CXXRecordDecl *,unsigned int,Fn)' with [ Derived=`anonymous-namespace'::TemplateInstantiator, Fn=clang::Sema::SubstFunctionDeclType:: ] while trying to match the argument list '(clang::TypeLocBuilder, clang::FunctionProtoTypeLoc, clang::CXXRecordDecl *, unsigned int, clang::Sema::SubstFunctionDeclType::)' 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218058 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index d08abb7d97..0612231e91 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/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::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.castAs(); - - 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()) { + 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/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index d940232077..f730a26ed4 100644 --- a/include/clang/AST/Expr.h +++ b/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/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 0adb09b617..19c01e0212 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/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::TraverseLambdaExpr(LambdaExpr *S) { TRY_TO(TraverseLambdaCapture(S, C)); } - TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); - FunctionProtoTypeLoc Proto = TL.castAs(); - - 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()) { + 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/include/clang/AST/Type.h b/include/clang/AST/Type.h index 2a6ac2db30..1391586483 100644 --- a/include/clang/AST/Type.h +++ b/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 const T *Type::castAs() const { ArrayType_cannot_be_used_with_getAs at; (void) at; - if (const T *ty = dyn_cast(this)) return ty; assert(isa(CanonicalType)); + if (const T *ty = dyn_cast(this)) return ty; return cast(getUnqualifiedDesugaredType()); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index dd41418e96..3755256da9 100644 --- a/include/clang/Sema/Sema.h +++ b/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 DynamicExceptions, ArrayRef 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/lib/AST/Type.cpp b/lib/AST/Type.cpp index 7834bfda6d..35676da641 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1623,9 +1623,9 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef 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 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 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()) - return true; - return false; -} - FunctionProtoType::NoexceptResult FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { ExceptionSpecificationType est = getExceptionSpecType(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a03e308f99..006a3c49d7 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -13051,12 +13051,13 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { return false; } -void Sema::checkExceptionSpecification( - bool IsTopLevel, ExceptionSpecificationType EST, - ArrayRef DynamicExceptions, - ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, - SmallVectorImpl &Exceptions, - FunctionProtoType::ExceptionSpecInfo &ESI) { +void +Sema::checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef DynamicExceptions, + ArrayRef DynamicExceptionRanges, + Expr *NoexceptExpr, + SmallVectorImpl &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 Unexpanded; - collectUnexpandedParameterPacks(ET, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks( - DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType, - Unexpanded); - continue; - } + SmallVector 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/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4e4de5a3e7..e4963b13d6 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/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 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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 25b2802f02..f44780407b 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/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 + 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 +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()) { - // 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()) { + 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 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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index ddd47ee1e3..62a3e11ac9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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()->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(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 Exceptions; + for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { + // FIXME: Poor location information! + if (const PackExpansionType *PackExpansion + = Proto->getExceptionType(I)->getAs()) { + // We have a pack expansion. Instantiate it. + SmallVector Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && + "Pack expansion without parameter packs?"); + + bool Expand = false; + bool RetainExpansion = false; + Optional 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(), - TemplateArgs); + ::InstantiateExceptionSpec(*this, Decl, + Template->getType()->castAs(), + 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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 76649a8acb..51f36feaa4 100644 --- a/lib/Sema/SemaType.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 07ce0273e1..92baa0ebd2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -542,17 +542,10 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" - template QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, - Fn TransformExceptionSpec); - - bool TransformExceptionSpec(SourceLocation Loc, - FunctionProtoType::ExceptionSpecInfo &ESI, - SmallVectorImpl &Exceptions, - bool &Changed); + unsigned ThisTypeQuals); StmtResult TransformSEHHandler(Stmt *Handler); @@ -4519,19 +4512,15 @@ template QualType TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { - SmallVector ExceptionStorage; - return getDerived().TransformFunctionProtoType( - TLB, TL, nullptr, 0, - [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { - return TransformExceptionSpec(TL.getBeginLoc(), ESI, ExceptionStorage, - Changed); - }); -} - -template template -QualType TreeTransform::TransformFunctionProtoType( - TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, Fn TransformExceptionSpec) { + return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0); +} + +template +QualType +TreeTransform::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::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(); } @@ -4606,107 +4589,6 @@ QualType TreeTransform::TransformFunctionProtoType( return Result; } -template -bool TreeTransform::TransformExceptionSpec( - SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, - SmallVectorImpl &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()) { - Changed = true; - - // We have a pack expansion. Instantiate it. - SmallVector 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 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 QualType TreeTransform::TransformFunctionNoProtoType( TypeLocBuilder &TLB, @@ -9024,13 +8906,9 @@ TreeTransform::TransformLambdaExpr(LambdaExpr *E) { // transformed parameters. TypeLocBuilder NewCallOpTLBuilder; - SmallVector 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/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp index fa53c9f5d2..a32f37d552 100644 --- a/test/CXX/except/except.spec/p1.cpp +++ b/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 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/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index f62ef61758..a376f0e5fd 100644 --- a/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -58,13 +58,6 @@ namespace dr1330_example { S().f(); // ok S().f(); // expected-note {{instantiation of exception spec}} } - - template - struct U { - void f() noexcept(T::error); - void (g)() noexcept(T::error); - }; - U uint; // ok } namespace core_19754_example { @@ -144,37 +137,3 @@ namespace PR12763 { }; void X::g() {} // expected-note {{in instantiation of}} } - -namespace Variadic { - template void check() { static_assert(B, ""); } - template void check() { static_assert(B, ""); check(); } - - template void consume(T...); - - template void f(void (*...p)() throw (T)) { - void (*q[])() = { p... }; - consume((p(),0)...); - } - template void g(void (*...p)() noexcept (B)) { - consume((p(),0)...); - check(); - } - template void i() { - consume([]() throw(T) {} ...); - consume([]() noexcept(sizeof(T) == 4) {} ...); - } - template void j() { - consume([](void (*p)() noexcept(B)) { - void (*q)() noexcept = p; // expected-error {{not superset of source}} - } ...); - } - - void z() { - f(nullptr, nullptr, nullptr); - g(nullptr, nullptr, nullptr); - i(); - j(); - j(); // expected-note {{in instantiation of}} - } - -} diff --git a/test/SemaTemplate/instantiate-exception-spec.cpp b/test/SemaTemplate/instantiate-exception-spec.cpp index d341172228..993ee8dfae 100644 --- a/test/SemaTemplate/instantiate-exception-spec.cpp +++ b/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 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 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(0); } // expected-note {{instantiation of}}