Track the result of evaluating a computed noexcept specification on the
FunctionProtoType.
We previously re-evaluated the expression each time we wanted to know whether
the type is noexcept or not. We now evaluate the expression exactly once.
This is not quite "no functional change": it fixes a crasher bug during AST
deserialization where we would try to evaluate the noexcept specification in a
situation where we have not deserialized sufficient portions of the AST to
permit such evaluation.
llvm-svn: 331428
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 95ea841..1d56fc8 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4381,7 +4381,7 @@
const FunctionProtoType *CPT =
Operator->getType()->getAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
- if (!CPT || !CPT->isNothrow(C))
+ if (!CPT || !CPT->isNothrow())
return false;
}
}
@@ -4629,7 +4629,7 @@
const FunctionProtoType *CPT =
Destructor->getType()->getAs<FunctionProtoType>();
CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
- if (!CPT || !CPT->isNothrow(C))
+ if (!CPT || !CPT->isNothrow())
return false;
}
}
@@ -4722,7 +4722,7 @@
return false;
// TODO: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(C) || CPT->getNumParams() > 1)
+ if (!CPT->isNothrow() || CPT->getNumParams() > 1)
return false;
}
}
@@ -4761,7 +4761,7 @@
return false;
// FIXME: check whether evaluating default arguments can throw.
// For now, we'll be conservative and assume that they can throw.
- if (!CPT->isNothrow(C) || CPT->getNumParams() > 0)
+ if (!CPT->isNothrow() || CPT->getNumParams() > 0)
return false;
}
}
@@ -5909,27 +5909,23 @@
if (EST2 == EST_None) return ESI2;
if (EST1 == EST_MSAny) return ESI1;
if (EST2 == EST_MSAny) return ESI2;
+ if (EST1 == EST_NoexceptFalse) return ESI1;
+ if (EST2 == EST_NoexceptFalse) return ESI2;
// If either of them is non-throwing, the result is the other.
if (EST1 == EST_DynamicNone) return ESI2;
if (EST2 == EST_DynamicNone) return ESI1;
if (EST1 == EST_BasicNoexcept) return ESI2;
if (EST2 == EST_BasicNoexcept) return ESI1;
+ if (EST1 == EST_NoexceptTrue) return ESI2;
+ if (EST2 == EST_NoexceptTrue) return ESI1;
- // If either of them is a non-value-dependent computed noexcept, that
- // determines the result.
- if (EST2 == EST_ComputedNoexcept && ESI2.NoexceptExpr &&
- !ESI2.NoexceptExpr->isValueDependent())
- return !ESI2.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI2 : ESI1;
- if (EST1 == EST_ComputedNoexcept && ESI1.NoexceptExpr &&
- !ESI1.NoexceptExpr->isValueDependent())
- return !ESI1.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI1 : ESI2;
// If we're left with value-dependent computed noexcept expressions, we're
// stuck. Before C++17, we can just drop the exception specification entirely,
// since it's not actually part of the canonical type. And this should never
// happen in C++17, because it would mean we were computing the composite
// pointer type of dependent types, which should never happen.
- if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) {
+ if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
assert(!S.getLangOpts().CPlusPlus17 &&
"computing composite pointer type of dependent types");
return FunctionProtoType::ExceptionSpecInfo();
@@ -5942,7 +5938,9 @@
case EST_DynamicNone:
case EST_MSAny:
case EST_BasicNoexcept:
- case EST_ComputedNoexcept:
+ case EST_DependentNoexcept:
+ case EST_NoexceptFalse:
+ case EST_NoexceptTrue:
llvm_unreachable("handled above");
case EST_Dynamic: {