From: NAKAMURA Takumi Date: Fri, 17 Oct 2014 12:48:37 +0000 (+0000) Subject: Revert r219977, "Re-commit r217995 and follow-up patches (r217997, r218011, r218053... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f972c365844ca1b6baf40d1a34a29ef4d421a2b4;p=clang Revert r219977, "Re-commit r217995 and follow-up patches (r217997, r218011, r218053). These were" It broke some builders. I guess it'd be reproducible with --vg. Failing Tests (3): Clang :: CXX/except/except.spec/p1.cpp Clang :: SemaTemplate/instantiate-exception-spec-cxx11.cpp Clang :: SemaTemplate/instantiate-exception-spec.cpp git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220038 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index f7c811ee8d..6d9ac94a43 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -878,9 +878,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, {}) @@ -1089,9 +1086,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, {}) @@ -2131,29 +2125,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 afe4b0cd2b..2b2adc810a 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -2678,23 +2678,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 6ae788d6c6..2f26801f94 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -943,9 +943,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, {}) @@ -1154,9 +1151,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, {}) @@ -2153,29 +2147,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 7c8535c92e..372365452e 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4036,8 +4036,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, @@ -6676,8 +6675,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 726db9229f..3c5e80e9ba 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1624,9 +1624,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()) @@ -1640,12 +1640,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 @@ -1671,18 +1670,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 d1f337f5b9..ed15012a16 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -13168,12 +13168,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) { @@ -13182,15 +13183,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 @@ -13209,8 +13208,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 a9aae00940..9c1ffb0c65 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -791,17 +791,11 @@ namespace { ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL) { - // Call the base version; it will forward to our overridden version below. - return inherited::TransformFunctionProtoType(TLB, TL); - } - - template + FunctionProtoTypeLoc TL); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals, - Fn TransformExceptionSpec); + unsigned ThisTypeQuals); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1333,16 +1327,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 * @@ -1577,8 +1576,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, @@ -1601,17 +1599,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); } @@ -1621,26 +1611,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 cc2460c617..ec8c08ddf5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3056,7 +3056,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) { @@ -3067,22 +3067,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; @@ -3094,27 +3087,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, @@ -3141,14 +3243,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 @@ -3217,7 +3316,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); } } @@ -3407,9 +3506,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 f395e10caa..3ce9489fdd 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 75783f29e6..28890f59ce 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -563,17 +563,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); @@ -4557,19 +4550,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. @@ -4614,21 +4603,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(); } @@ -4644,107 +4627,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, @@ -9123,13 +9005,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}}