forked from OSchip/llvm-project
Re-commit r217995 and follow-up patches (r217997, r218011, r218053). These were
reverted in r218058 because they triggered a rejects-valid bug in MSVC. Original commit message from r217995: Instantiate exception specifications when instantiating function types (other than the type of a function declaration). We previously didn't instantiate these at all! This also covers the pathological case where the only mention of a parameter pack is within the exception specification; this gives us a second way (other than alias templates) to reach the horrible state where a type contains an unexpanded pack, but its canonical type does not. llvm-svn: 219977
This commit is contained in:
parent
82e3e373b3
commit
9c04bce1f1
|
@ -878,6 +878,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
|
||||||
for (const auto &E : T->exceptions()) {
|
for (const auto &E : T->exceptions()) {
|
||||||
TRY_TO(TraverseType(E));
|
TRY_TO(TraverseType(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Expr *NE = T->getNoexceptExpr())
|
||||||
|
TRY_TO(TraverseStmt(NE));
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
|
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
|
||||||
|
@ -1086,6 +1089,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
|
||||||
for (const auto &E : T->exceptions()) {
|
for (const auto &E : T->exceptions()) {
|
||||||
TRY_TO(TraverseType(E));
|
TRY_TO(TraverseType(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Expr *NE = T->getNoexceptExpr())
|
||||||
|
TRY_TO(TraverseStmt(NE));
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
|
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
|
||||||
|
@ -2125,21 +2131,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||||
TRY_TO(TraverseLambdaCapture(S, C));
|
TRY_TO(TraverseLambdaCapture(S, C));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
|
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
||||||
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
|
||||||
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
|
||||||
// Visit the whole type.
|
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
||||||
TRY_TO(TraverseTypeLoc(TL));
|
// Visit the whole type.
|
||||||
} else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
|
TRY_TO(TraverseTypeLoc(TL));
|
||||||
if (S->hasExplicitParameters()) {
|
} else {
|
||||||
// Visit parameters.
|
if (S->hasExplicitParameters()) {
|
||||||
for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
|
// Visit parameters.
|
||||||
TRY_TO(TraverseDecl(Proto.getParam(I)));
|
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));
|
TRY_TO(TraverseLambdaBody(S));
|
||||||
|
|
|
@ -2678,20 +2678,23 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CastExpr(StmtClass SC, QualType ty, ExprValueKind VK,
|
CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, const CastKind kind,
|
||||||
const CastKind kind, Expr *op, unsigned BasePathSize) :
|
Expr *op, unsigned BasePathSize)
|
||||||
Expr(SC, ty, VK, OK_Ordinary,
|
: Expr(SC, ty, VK, OK_Ordinary,
|
||||||
// Cast expressions are type-dependent if the type is
|
// Cast expressions are type-dependent if the type is
|
||||||
// dependent (C++ [temp.dep.expr]p3).
|
// dependent (C++ [temp.dep.expr]p3).
|
||||||
ty->isDependentType(),
|
ty->isDependentType(),
|
||||||
// Cast expressions are value-dependent if the type is
|
// Cast expressions are value-dependent if the type is
|
||||||
// dependent or if the subexpression is value-dependent.
|
// dependent or if the subexpression is value-dependent.
|
||||||
ty->isDependentType() || (op && op->isValueDependent()),
|
ty->isDependentType() || (op && op->isValueDependent()),
|
||||||
(ty->isInstantiationDependentType() ||
|
(ty->isInstantiationDependentType() ||
|
||||||
(op && op->isInstantiationDependent())),
|
(op && op->isInstantiationDependent())),
|
||||||
(ty->containsUnexpandedParameterPack() ||
|
// An implicit cast expression doesn't (lexically) contain an
|
||||||
(op && op->containsUnexpandedParameterPack()))),
|
// unexpanded pack, even if its target type does.
|
||||||
Op(op) {
|
((SC != ImplicitCastExprClass &&
|
||||||
|
ty->containsUnexpandedParameterPack()) ||
|
||||||
|
(op && op->containsUnexpandedParameterPack()))),
|
||||||
|
Op(op) {
|
||||||
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
|
assert(kind != CK_Invalid && "creating cast with invalid cast kind");
|
||||||
CastExprBits.Kind = kind;
|
CastExprBits.Kind = kind;
|
||||||
setBasePathSize(BasePathSize);
|
setBasePathSize(BasePathSize);
|
||||||
|
|
|
@ -943,6 +943,9 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
|
||||||
for (const auto &E : T->exceptions()) {
|
for (const auto &E : T->exceptions()) {
|
||||||
TRY_TO(TraverseType(E));
|
TRY_TO(TraverseType(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Expr *NE = T->getNoexceptExpr())
|
||||||
|
TRY_TO(TraverseStmt(NE));
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
|
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
|
||||||
|
@ -1151,6 +1154,9 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
|
||||||
for (const auto &E : T->exceptions()) {
|
for (const auto &E : T->exceptions()) {
|
||||||
TRY_TO(TraverseType(E));
|
TRY_TO(TraverseType(E));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Expr *NE = T->getNoexceptExpr())
|
||||||
|
TRY_TO(TraverseStmt(NE));
|
||||||
})
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
|
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
|
||||||
|
@ -2147,21 +2153,29 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
|
||||||
TRY_TO(TraverseLambdaCapture(S, C));
|
TRY_TO(TraverseLambdaCapture(S, C));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S->hasExplicitParameters() || S->hasExplicitResultType()) {
|
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
||||||
TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
|
FunctionProtoTypeLoc Proto = TL.castAs<FunctionProtoTypeLoc>();
|
||||||
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
|
||||||
// Visit the whole type.
|
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
|
||||||
TRY_TO(TraverseTypeLoc(TL));
|
// Visit the whole type.
|
||||||
} else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
|
TRY_TO(TraverseTypeLoc(TL));
|
||||||
if (S->hasExplicitParameters()) {
|
} else {
|
||||||
// Visit parameters.
|
if (S->hasExplicitParameters()) {
|
||||||
for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) {
|
// Visit parameters.
|
||||||
TRY_TO(TraverseDecl(Proto.getParam(I)));
|
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));
|
TRY_TO(TraverseLambdaBody(S));
|
||||||
|
|
|
@ -3012,6 +3012,8 @@ public:
|
||||||
bool hasNoexceptExceptionSpec() const {
|
bool hasNoexceptExceptionSpec() const {
|
||||||
return isNoexceptExceptionSpec(getExceptionSpecType());
|
return isNoexceptExceptionSpec(getExceptionSpecType());
|
||||||
}
|
}
|
||||||
|
/// \brief Return whether this function has a dependent exception spec.
|
||||||
|
bool hasDependentExceptionSpec() const;
|
||||||
/// \brief Result type of getNoexceptSpec().
|
/// \brief Result type of getNoexceptSpec().
|
||||||
enum NoexceptResult {
|
enum NoexceptResult {
|
||||||
NR_NoNoexcept, ///< There is no noexcept specifier.
|
NR_NoNoexcept, ///< There is no noexcept specifier.
|
||||||
|
@ -5247,8 +5249,8 @@ template <typename T> const T *Type::castAs() const {
|
||||||
ArrayType_cannot_be_used_with_getAs<T> at;
|
ArrayType_cannot_be_used_with_getAs<T> at;
|
||||||
(void) at;
|
(void) at;
|
||||||
|
|
||||||
assert(isa<T>(CanonicalType));
|
|
||||||
if (const T *ty = dyn_cast<T>(this)) return ty;
|
if (const T *ty = dyn_cast<T>(this)) return ty;
|
||||||
|
assert(isa<T>(CanonicalType));
|
||||||
return cast<T>(getUnqualifiedDesugaredType());
|
return cast<T>(getUnqualifiedDesugaredType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4036,7 +4036,8 @@ public:
|
||||||
|
|
||||||
/// \brief Check the given exception-specification and update the
|
/// \brief Check the given exception-specification and update the
|
||||||
/// exception specification information with the results.
|
/// exception specification information with the results.
|
||||||
void checkExceptionSpecification(ExceptionSpecificationType EST,
|
void checkExceptionSpecification(bool IsTopLevel,
|
||||||
|
ExceptionSpecificationType EST,
|
||||||
ArrayRef<ParsedType> DynamicExceptions,
|
ArrayRef<ParsedType> DynamicExceptions,
|
||||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
ArrayRef<SourceRange> DynamicExceptionRanges,
|
||||||
Expr *NoexceptExpr,
|
Expr *NoexceptExpr,
|
||||||
|
@ -6675,6 +6676,8 @@ public:
|
||||||
DeclarationName Entity,
|
DeclarationName Entity,
|
||||||
CXXRecordDecl *ThisContext,
|
CXXRecordDecl *ThisContext,
|
||||||
unsigned ThisTypeQuals);
|
unsigned ThisTypeQuals);
|
||||||
|
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
||||||
|
const MultiLevelTemplateArgumentList &Args);
|
||||||
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
|
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
int indexAdjustment,
|
int indexAdjustment,
|
||||||
|
|
|
@ -1623,9 +1623,9 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
||||||
QualType *exnSlot = argSlot + NumParams;
|
QualType *exnSlot = argSlot + NumParams;
|
||||||
unsigned I = 0;
|
unsigned I = 0;
|
||||||
for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) {
|
for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) {
|
||||||
if (ExceptionType->isDependentType())
|
// Note that a dependent exception specification does *not* make
|
||||||
setDependent();
|
// a type dependent; it's not even part of the C++ type system.
|
||||||
else if (ExceptionType->isInstantiationDependentType())
|
if (ExceptionType->isInstantiationDependentType())
|
||||||
setInstantiationDependent();
|
setInstantiationDependent();
|
||||||
|
|
||||||
if (ExceptionType->containsUnexpandedParameterPack())
|
if (ExceptionType->containsUnexpandedParameterPack())
|
||||||
|
@ -1639,11 +1639,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
||||||
*noexSlot = epi.ExceptionSpec.NoexceptExpr;
|
*noexSlot = epi.ExceptionSpec.NoexceptExpr;
|
||||||
|
|
||||||
if (epi.ExceptionSpec.NoexceptExpr) {
|
if (epi.ExceptionSpec.NoexceptExpr) {
|
||||||
if (epi.ExceptionSpec.NoexceptExpr->isValueDependent()
|
if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() ||
|
||||||
|| epi.ExceptionSpec.NoexceptExpr->isTypeDependent())
|
epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
|
||||||
setDependent();
|
|
||||||
else if (epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
|
|
||||||
setInstantiationDependent();
|
setInstantiationDependent();
|
||||||
|
|
||||||
|
if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack())
|
||||||
|
setContainsUnexpandedParameterPack();
|
||||||
}
|
}
|
||||||
} else if (getExceptionSpecType() == EST_Uninstantiated) {
|
} else if (getExceptionSpecType() == EST_Uninstantiated) {
|
||||||
// Store the function decl from which we will resolve our
|
// Store the function decl from which we will resolve our
|
||||||
|
@ -1669,6 +1670,18 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FunctionProtoType::hasDependentExceptionSpec() const {
|
||||||
|
if (Expr *NE = getNoexceptExpr())
|
||||||
|
return NE->isValueDependent();
|
||||||
|
for (QualType ET : exceptions())
|
||||||
|
// A pack expansion with a non-dependent pattern is still dependent,
|
||||||
|
// because we don't know whether the pattern is in the exception spec
|
||||||
|
// or not (that depends on whether the pack has 0 expansions).
|
||||||
|
if (ET->isDependentType() || ET->getAs<PackExpansionType>())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
FunctionProtoType::NoexceptResult
|
FunctionProtoType::NoexceptResult
|
||||||
FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
|
FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
|
||||||
ExceptionSpecificationType est = getExceptionSpecType();
|
ExceptionSpecificationType est = getExceptionSpecType();
|
||||||
|
|
|
@ -13168,13 +13168,12 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void Sema::checkExceptionSpecification(
|
||||||
Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
|
bool IsTopLevel, ExceptionSpecificationType EST,
|
||||||
ArrayRef<ParsedType> DynamicExceptions,
|
ArrayRef<ParsedType> DynamicExceptions,
|
||||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr,
|
||||||
Expr *NoexceptExpr,
|
SmallVectorImpl<QualType> &Exceptions,
|
||||||
SmallVectorImpl<QualType> &Exceptions,
|
FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||||
FunctionProtoType::ExceptionSpecInfo &ESI) {
|
|
||||||
Exceptions.clear();
|
Exceptions.clear();
|
||||||
ESI.Type = EST;
|
ESI.Type = EST;
|
||||||
if (EST == EST_Dynamic) {
|
if (EST == EST_Dynamic) {
|
||||||
|
@ -13183,13 +13182,15 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
|
||||||
// FIXME: Preserve type source info.
|
// FIXME: Preserve type source info.
|
||||||
QualType ET = GetTypeFromParser(DynamicExceptions[ei]);
|
QualType ET = GetTypeFromParser(DynamicExceptions[ei]);
|
||||||
|
|
||||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
if (IsTopLevel) {
|
||||||
collectUnexpandedParameterPacks(ET, Unexpanded);
|
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||||
if (!Unexpanded.empty()) {
|
collectUnexpandedParameterPacks(ET, Unexpanded);
|
||||||
DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(),
|
if (!Unexpanded.empty()) {
|
||||||
UPPC_ExceptionType,
|
DiagnoseUnexpandedParameterPacks(
|
||||||
Unexpanded);
|
DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType,
|
||||||
continue;
|
Unexpanded);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the type is valid for an exception spec, and
|
// Check that the type is valid for an exception spec, and
|
||||||
|
@ -13208,7 +13209,8 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
|
||||||
NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
|
NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
|
||||||
Context.BoolTy) &&
|
Context.BoolTy) &&
|
||||||
"Parser should have made sure that the expression is boolean");
|
"Parser should have made sure that the expression is boolean");
|
||||||
if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
|
if (IsTopLevel && NoexceptExpr &&
|
||||||
|
DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
|
||||||
ESI.Type = EST_BasicNoexcept;
|
ESI.Type = EST_BasicNoexcept;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -720,10 +720,11 @@ static bool CheckSpecForTypesEquivalent(Sema &S,
|
||||||
/// assignment and override compatibility check. We do not check the parameters
|
/// assignment and override compatibility check. We do not check the parameters
|
||||||
/// of parameter function pointers recursively, as no sane programmer would
|
/// of parameter function pointers recursively, as no sane programmer would
|
||||||
/// even be able to write such a function type.
|
/// even be able to write such a function type.
|
||||||
bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
|
bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID,
|
||||||
const FunctionProtoType *Target, SourceLocation TargetLoc,
|
const FunctionProtoType *Target,
|
||||||
const FunctionProtoType *Source, SourceLocation SourceLoc)
|
SourceLocation TargetLoc,
|
||||||
{
|
const FunctionProtoType *Source,
|
||||||
|
SourceLocation SourceLoc) {
|
||||||
if (CheckSpecForTypesEquivalent(
|
if (CheckSpecForTypesEquivalent(
|
||||||
*this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
|
*this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(),
|
||||||
Target->getReturnType(), TargetLoc, Source->getReturnType(),
|
Target->getReturnType(), TargetLoc, Source->getReturnType(),
|
||||||
|
@ -744,23 +745,30 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
|
bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
|
||||||
{
|
|
||||||
// First we check for applicability.
|
// First we check for applicability.
|
||||||
// Target type must be a function, function pointer or function reference.
|
// Target type must be a function, function pointer or function reference.
|
||||||
const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
|
const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
|
||||||
if (!ToFunc)
|
if (!ToFunc || ToFunc->hasDependentExceptionSpec())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// SourceType must be a function or function pointer.
|
// SourceType must be a function or function pointer.
|
||||||
const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
|
const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
|
||||||
if (!FromFunc)
|
if (!FromFunc || FromFunc->hasDependentExceptionSpec())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Now we've got the correct types on both sides, check their compatibility.
|
// 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
|
// 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
|
// the exceptions of the target, and any exception specs on arguments or
|
||||||
// return types must be equivalent.
|
// 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),
|
return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs),
|
||||||
PDiag(), ToFunc,
|
PDiag(), ToFunc,
|
||||||
From->getSourceRange().getBegin(),
|
From->getSourceRange().getBegin(),
|
||||||
|
|
|
@ -791,11 +791,17 @@ namespace {
|
||||||
ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
|
ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E);
|
||||||
|
|
||||||
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
FunctionProtoTypeLoc TL);
|
FunctionProtoTypeLoc TL) {
|
||||||
|
// Call the base version; it will forward to our overridden version below.
|
||||||
|
return inherited::TransformFunctionProtoType(TLB, TL);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fn>
|
||||||
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
FunctionProtoTypeLoc TL,
|
FunctionProtoTypeLoc TL,
|
||||||
CXXRecordDecl *ThisContext,
|
CXXRecordDecl *ThisContext,
|
||||||
unsigned ThisTypeQuals);
|
unsigned ThisTypeQuals,
|
||||||
|
Fn TransformExceptionSpec);
|
||||||
|
|
||||||
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
|
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
|
||||||
int indexAdjustment,
|
int indexAdjustment,
|
||||||
|
@ -1327,21 +1333,16 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr(
|
||||||
E->getParam());
|
E->getParam());
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
template<typename Fn>
|
||||||
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,
|
QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
FunctionProtoTypeLoc TL,
|
FunctionProtoTypeLoc TL,
|
||||||
CXXRecordDecl *ThisContext,
|
CXXRecordDecl *ThisContext,
|
||||||
unsigned ThisTypeQuals) {
|
unsigned ThisTypeQuals,
|
||||||
|
Fn TransformExceptionSpec) {
|
||||||
// We need a local instantiation scope for this function prototype.
|
// We need a local instantiation scope for this function prototype.
|
||||||
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
|
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
|
||||||
return inherited::TransformFunctionProtoType(TLB, TL, ThisContext,
|
return inherited::TransformFunctionProtoType(
|
||||||
ThisTypeQuals);
|
TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
ParmVarDecl *
|
ParmVarDecl *
|
||||||
|
@ -1576,7 +1577,8 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
|
||||||
|
|
||||||
/// A form of SubstType intended specifically for instantiating the
|
/// A form of SubstType intended specifically for instantiating the
|
||||||
/// type of a FunctionDecl. Its purpose is solely to force the
|
/// type of a FunctionDecl. Its purpose is solely to force the
|
||||||
/// instantiation of default-argument expressions.
|
/// instantiation of default-argument expressions and to avoid
|
||||||
|
/// instantiating an exception-specification.
|
||||||
TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
||||||
const MultiLevelTemplateArgumentList &Args,
|
const MultiLevelTemplateArgumentList &Args,
|
||||||
SourceLocation Loc,
|
SourceLocation Loc,
|
||||||
|
@ -1599,9 +1601,17 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
||||||
|
|
||||||
QualType Result;
|
QualType Result;
|
||||||
|
|
||||||
if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
|
if (FunctionProtoTypeLoc Proto =
|
||||||
Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext,
|
TL.IgnoreParens().getAs<FunctionProtoTypeLoc>()) {
|
||||||
ThisTypeQuals);
|
// 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; });
|
||||||
} else {
|
} else {
|
||||||
Result = Instantiator.TransformType(TLB, TL);
|
Result = Instantiator.TransformType(TLB, TL);
|
||||||
}
|
}
|
||||||
|
@ -1611,6 +1621,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
||||||
return TLB.getTypeSourceInfo(Context, Result);
|
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,
|
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
int indexAdjustment,
|
int indexAdjustment,
|
||||||
|
|
|
@ -3056,7 +3056,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
|
||||||
/// Introduce the instantiated function parameters into the local
|
/// Introduce the instantiated function parameters into the local
|
||||||
/// instantiation scope, and set the parameter names to those used
|
/// instantiation scope, and set the parameter names to those used
|
||||||
/// in the template.
|
/// in the template.
|
||||||
static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
||||||
const FunctionDecl *PatternDecl,
|
const FunctionDecl *PatternDecl,
|
||||||
LocalInstantiationScope &Scope,
|
LocalInstantiationScope &Scope,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
|
@ -3067,15 +3067,22 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
||||||
// Simple case: not a parameter pack.
|
// Simple case: not a parameter pack.
|
||||||
assert(FParamIdx < Function->getNumParams());
|
assert(FParamIdx < Function->getNumParams());
|
||||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||||
|
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||||
// If the parameter's type is not dependent, update it to match the type
|
// 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
|
// 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,
|
// the pattern's type here. If the type is dependent, they can't differ,
|
||||||
// per core issue 1668.
|
// per core issue 1668. Substitute into the type from the pattern, in case
|
||||||
|
// it's instantiation-dependent.
|
||||||
// FIXME: Updating the type to work around this is at best fragile.
|
// FIXME: Updating the type to work around this is at best fragile.
|
||||||
if (!PatternDecl->getType()->isDependentType())
|
if (!PatternDecl->getType()->isDependentType()) {
|
||||||
FunctionParam->setType(PatternParam->getType());
|
QualType T = S.SubstType(PatternParam->getType(), TemplateArgs,
|
||||||
|
FunctionParam->getLocation(),
|
||||||
|
FunctionParam->getDeclName());
|
||||||
|
if (T.isNull())
|
||||||
|
return true;
|
||||||
|
FunctionParam->setType(T);
|
||||||
|
}
|
||||||
|
|
||||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
|
||||||
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
||||||
++FParamIdx;
|
++FParamIdx;
|
||||||
continue;
|
continue;
|
||||||
|
@ -3087,136 +3094,27 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
|
||||||
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
|
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
|
||||||
assert(NumArgumentsInExpansion &&
|
assert(NumArgumentsInExpansion &&
|
||||||
"should only be called when all template arguments are known");
|
"should only be called when all template arguments are known");
|
||||||
|
QualType PatternType =
|
||||||
|
PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
|
||||||
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
|
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
|
||||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||||
if (!PatternDecl->getType()->isDependentType())
|
|
||||||
FunctionParam->setType(PatternParam->getType());
|
|
||||||
|
|
||||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||||
|
if (!PatternDecl->getType()->isDependentType()) {
|
||||||
|
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg);
|
||||||
|
QualType T = S.SubstType(PatternType, TemplateArgs,
|
||||||
|
FunctionParam->getLocation(),
|
||||||
|
FunctionParam->getDeclName());
|
||||||
|
if (T.isNull())
|
||||||
|
return true;
|
||||||
|
FunctionParam->setType(T);
|
||||||
|
}
|
||||||
|
|
||||||
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
|
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
|
||||||
++FParamIdx;
|
++FParamIdx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
|
return false;
|
||||||
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())
|
|
||||||
break;
|
|
||||||
|
|
||||||
T = SemaRef.Context.getPackExpansionType(T, NumExpansions);
|
|
||||||
Exceptions.push_back(T);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Substitute into the pack expansion pattern for each template
|
|
||||||
bool Invalid = false;
|
|
||||||
for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
|
|
||||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx);
|
|
||||||
|
|
||||||
QualType T = SemaRef.SubstType(PackExpansion->getPattern(),
|
|
||||||
TemplateArgs,
|
|
||||||
New->getLocation(), New->getDeclName());
|
|
||||||
if (T.isNull()) {
|
|
||||||
Invalid = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Exceptions.push_back(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Invalid)
|
|
||||||
break;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType T
|
|
||||||
= SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs,
|
|
||||||
New->getLocation(), New->getDeclName());
|
|
||||||
if (T.isNull() ||
|
|
||||||
SemaRef.CheckSpecifiedExceptionType(T, New->getLocation()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Exceptions.push_back(T);
|
|
||||||
}
|
|
||||||
Expr *NoexceptExpr = 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionProtoType::ExceptionSpecInfo ESI;
|
|
||||||
ESI.Type = Proto->getExceptionSpecType();
|
|
||||||
ESI.Exceptions = Exceptions;
|
|
||||||
ESI.NoexceptExpr = NoexceptExpr;
|
|
||||||
|
|
||||||
SemaRef.UpdateExceptionSpec(New, ESI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||||
|
@ -3243,11 +3141,14 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||||
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
|
getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true);
|
||||||
|
|
||||||
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
|
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
|
||||||
addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs);
|
if (addInstantiatedParametersToScope(*this, Decl, Template, Scope,
|
||||||
|
TemplateArgs)) {
|
||||||
|
UpdateExceptionSpec(Decl, EST_None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
::InstantiateExceptionSpec(*this, Decl,
|
SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(),
|
||||||
Template->getType()->castAs<FunctionProtoType>(),
|
TemplateArgs);
|
||||||
TemplateArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Initializes the common fields of an instantiation function
|
/// \brief Initializes the common fields of an instantiation function
|
||||||
|
@ -3316,7 +3217,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
|
||||||
New->setType(SemaRef.Context.getFunctionType(
|
New->setType(SemaRef.Context.getFunctionType(
|
||||||
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
|
NewProto->getReturnType(), NewProto->getParamTypes(), EPI));
|
||||||
} else {
|
} else {
|
||||||
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
|
SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3506,8 +3407,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||||
MultiLevelTemplateArgumentList TemplateArgs =
|
MultiLevelTemplateArgumentList TemplateArgs =
|
||||||
getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
|
getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl);
|
||||||
|
|
||||||
addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
|
if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
|
||||||
TemplateArgs);
|
TemplateArgs))
|
||||||
|
return;
|
||||||
|
|
||||||
// If this is a constructor, instantiate the member initializers.
|
// If this is a constructor, instantiate the member initializers.
|
||||||
if (const CXXConstructorDecl *Ctor =
|
if (const CXXConstructorDecl *Ctor =
|
||||||
|
|
|
@ -2989,7 +2989,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
NoexceptExpr = FTI.NoexceptExpr;
|
NoexceptExpr = FTI.NoexceptExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
S.checkExceptionSpecification(FTI.getExceptionSpecType(),
|
S.checkExceptionSpecification(D.isFunctionDeclarationContext(),
|
||||||
|
FTI.getExceptionSpecType(),
|
||||||
DynamicExceptions,
|
DynamicExceptions,
|
||||||
DynamicExceptionRanges,
|
DynamicExceptionRanges,
|
||||||
NoexceptExpr,
|
NoexceptExpr,
|
||||||
|
|
|
@ -563,10 +563,17 @@ public:
|
||||||
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
|
QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
|
||||||
#include "clang/AST/TypeLocNodes.def"
|
#include "clang/AST/TypeLocNodes.def"
|
||||||
|
|
||||||
|
template<typename Fn>
|
||||||
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
QualType TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
FunctionProtoTypeLoc TL,
|
FunctionProtoTypeLoc TL,
|
||||||
CXXRecordDecl *ThisContext,
|
CXXRecordDecl *ThisContext,
|
||||||
unsigned ThisTypeQuals);
|
unsigned ThisTypeQuals,
|
||||||
|
Fn TransformExceptionSpec);
|
||||||
|
|
||||||
|
bool TransformExceptionSpec(SourceLocation Loc,
|
||||||
|
FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||||
|
SmallVectorImpl<QualType> &Exceptions,
|
||||||
|
bool &Changed);
|
||||||
|
|
||||||
StmtResult TransformSEHHandler(Stmt *Handler);
|
StmtResult TransformSEHHandler(Stmt *Handler);
|
||||||
|
|
||||||
|
@ -4550,15 +4557,19 @@ template<typename Derived>
|
||||||
QualType
|
QualType
|
||||||
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
FunctionProtoTypeLoc TL) {
|
FunctionProtoTypeLoc TL) {
|
||||||
return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0);
|
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 Derived> template<typename Fn>
|
||||||
QualType
|
QualType TreeTransform<Derived>::TransformFunctionProtoType(
|
||||||
TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext,
|
||||||
FunctionProtoTypeLoc TL,
|
unsigned ThisTypeQuals, Fn TransformExceptionSpec) {
|
||||||
CXXRecordDecl *ThisContext,
|
|
||||||
unsigned ThisTypeQuals) {
|
|
||||||
// Transform the parameters and return type.
|
// Transform the parameters and return type.
|
||||||
//
|
//
|
||||||
// We are required to instantiate the params and return type in source order.
|
// We are required to instantiate the params and return type in source order.
|
||||||
|
@ -4603,15 +4614,21 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
return QualType();
|
return QualType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Need to transform the exception-specification too.
|
FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo();
|
||||||
|
|
||||||
|
bool EPIChanged = false;
|
||||||
|
if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged))
|
||||||
|
return QualType();
|
||||||
|
|
||||||
|
// FIXME: Need to transform ConsumedParameters for variadic template
|
||||||
|
// expansion.
|
||||||
|
|
||||||
QualType Result = TL.getType();
|
QualType Result = TL.getType();
|
||||||
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
|
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
|
||||||
T->getNumParams() != ParamTypes.size() ||
|
T->getNumParams() != ParamTypes.size() ||
|
||||||
!std::equal(T->param_type_begin(), T->param_type_end(),
|
!std::equal(T->param_type_begin(), T->param_type_end(),
|
||||||
ParamTypes.begin())) {
|
ParamTypes.begin()) || EPIChanged) {
|
||||||
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
|
Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI);
|
||||||
T->getExtProtoInfo());
|
|
||||||
if (Result.isNull())
|
if (Result.isNull())
|
||||||
return QualType();
|
return QualType();
|
||||||
}
|
}
|
||||||
|
@ -4627,6 +4644,107 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
template<typename Derived>
|
||||||
QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
|
QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
|
||||||
TypeLocBuilder &TLB,
|
TypeLocBuilder &TLB,
|
||||||
|
@ -9005,9 +9123,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
||||||
// transformed parameters.
|
// transformed parameters.
|
||||||
|
|
||||||
TypeLocBuilder NewCallOpTLBuilder;
|
TypeLocBuilder NewCallOpTLBuilder;
|
||||||
QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder,
|
SmallVector<QualType, 4> ExceptionStorage;
|
||||||
OldCallOpFPTL,
|
QualType NewCallOpType = TransformFunctionProtoType(
|
||||||
nullptr, 0);
|
NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0,
|
||||||
|
[&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
|
||||||
|
return TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI,
|
||||||
|
ExceptionStorage, Changed);
|
||||||
|
});
|
||||||
NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
|
NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
|
||||||
NewCallOpType);
|
NewCallOpType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,5 +77,12 @@ 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}}
|
static int f() noexcept(1/X) { return 10; } // expected-error{{argument to noexcept specifier must be a constant expression}} expected-note{{division by zero}}
|
||||||
};
|
};
|
||||||
|
|
||||||
void g() { A<0>::f(); } // expected-note{{in instantiation of exception specification for 'f' requested here}}
|
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}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,13 @@ namespace dr1330_example {
|
||||||
S().f<S>(); // ok
|
S().f<S>(); // ok
|
||||||
S().f<int>(); // expected-note {{instantiation of exception spec}}
|
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 {
|
namespace core_19754_example {
|
||||||
|
@ -137,3 +144,37 @@ namespace PR12763 {
|
||||||
};
|
};
|
||||||
void X::g() {} // expected-note {{in instantiation of}}
|
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}}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -verify %s -DERRORS
|
||||||
|
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -emit-llvm-only %s
|
||||||
|
|
||||||
|
#ifdef ERRORS
|
||||||
template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}}
|
template<typename T> void f1(T*) throw(T); // expected-error{{incomplete type 'Incomplete' is not allowed in exception specification}}
|
||||||
struct Incomplete; // expected-note{{forward}}
|
struct Incomplete; // expected-note{{forward}}
|
||||||
|
|
||||||
|
@ -7,3 +9,20 @@ void test_f1(Incomplete *incomplete_p, int *int_p) {
|
||||||
f1(int_p);
|
f1(int_p);
|
||||||
f1(incomplete_p); // expected-note{{instantiation of}}
|
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}}
|
||||||
|
|
Loading…
Reference in New Issue