P0012R1: Make exception specifications be part of the type system. This
implements the bulk of the change (modifying the type system to include
exception specifications), but not all the details just yet.
llvm-svn: 284337
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 709de43..34eced3 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3193,6 +3193,34 @@
return CanResultType;
}
+static bool isCanonicalExceptionSpecification(
+ const FunctionProtoType::ExceptionSpecInfo &ESI, bool NoexceptInType) {
+ if (ESI.Type == EST_None)
+ return true;
+ if (!NoexceptInType)
+ return false;
+
+ // C++17 onwards: exception specification is part of the type, as a simple
+ // boolean "can this function type throw".
+ if (ESI.Type == EST_BasicNoexcept)
+ return true;
+
+ // A dynamic exception specification is canonical if it only contains pack
+ // expansions (so we can't tell whether it's non-throwing).
+ if (ESI.Type == EST_Dynamic) {
+ for (QualType ET : ESI.Exceptions)
+ if (!ET->getAs<PackExpansionType>())
+ return false;
+ return true;
+ }
+
+ // A noexcept(expr) specification is canonical if expr is value-dependent.
+ if (ESI.Type == EST_ComputedNoexcept)
+ return ESI.NoexceptExpr && ESI.NoexceptExpr->isValueDependent();
+
+ return false;
+}
+
QualType
ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
@@ -3209,10 +3237,14 @@
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(FTP, 0);
+ bool NoexceptInType = getLangOpts().CPlusPlus1z;
+
+ bool IsCanonicalExceptionSpec =
+ isCanonicalExceptionSpecification(EPI.ExceptionSpec, NoexceptInType);
+
// Determine whether the type being created is already canonical or not.
- bool isCanonical =
- EPI.ExceptionSpec.Type == EST_None && isCanonicalResultType(ResultTy) &&
- !EPI.HasTrailingReturn;
+ bool isCanonical = IsCanonicalExceptionSpec &&
+ isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
@@ -3228,7 +3260,45 @@
FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
CanonicalEPI.HasTrailingReturn = false;
- CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
+
+ if (IsCanonicalExceptionSpec) {
+ // Exception spec is already OK.
+ } else if (NoexceptInType) {
+ switch (EPI.ExceptionSpec.Type) {
+ case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated:
+ // We don't know yet. It shouldn't matter what we pick here; no-one
+ // should ever look at this.
+ LLVM_FALLTHROUGH;
+ case EST_None: case EST_MSAny: case EST_Dynamic:
+ // If we get here for EST_Dynamic, there is at least one
+ // non-pack-expansion type, so this is not non-throwing.
+ CanonicalEPI.ExceptionSpec.Type = EST_None;
+ break;
+
+ case EST_DynamicNone: case EST_BasicNoexcept:
+ CanonicalEPI.ExceptionSpec.Type = EST_BasicNoexcept;
+ break;
+
+ case EST_ComputedNoexcept:
+ llvm::APSInt Value(1);
+ auto *E = CanonicalEPI.ExceptionSpec.NoexceptExpr;
+ if (!E || !E->isIntegerConstantExpr(Value, *this, nullptr,
+ /*IsEvaluated*/false)) {
+ // This noexcept specification is invalid.
+ // FIXME: Should this be able to happen?
+ CanonicalEPI.ExceptionSpec.Type = EST_None;
+ break;
+ }
+
+ CanonicalEPI.ExceptionSpec.Type =
+ Value.getBoolValue() ? EST_BasicNoexcept : EST_None;
+ break;
+ }
+ assert(isCanonicalExceptionSpecification(CanonicalEPI.ExceptionSpec,
+ NoexceptInType));
+ } else {
+ CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
+ }
// Adjust the canonical function result type.
CanQualType CanResultTy = getCanonicalFunctionResultType(ResultTy);