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
llvm-svn: 220038
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
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));
}
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);
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
for (const auto &E : T->exceptions()) {
TRY_TO(TraverseType(E));
}
-
- if (Expr *NE = T->getNoexceptExpr())
- TRY_TO(TraverseStmt(NE));
})
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
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));
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.
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());
}
/// \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,
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,
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())
*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
}
}
-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();
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) {
// 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
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;
}
/// 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(),
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(),
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<typename Fn>
+ FunctionProtoTypeLoc TL);
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
FunctionProtoTypeLoc TL,
CXXRecordDecl *ThisContext,
- unsigned ThisTypeQuals,
- Fn TransformExceptionSpec);
+ unsigned ThisTypeQuals);
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
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 *
/// 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,
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);
}
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,
/// 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) {
// 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;
= 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,
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
New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
} else {
- SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
+ ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
}
}
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 =
NoexceptExpr = FTI.NoexceptExpr;
}
- S.checkExceptionSpecification(D.isFunctionDeclarationContext(),
- FTI.getExceptionSpecType(),
+ S.checkExceptionSpecification(FTI.getExceptionSpecType(),
DynamicExceptions,
DynamicExceptionRanges,
NoexceptExpr,
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);
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.
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();
}
}
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) {
// 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);
}
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}}
}
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 {
};
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}}
- }
-
-}
-// 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}}
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}}