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/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index d510714..bf79e07 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3420,6 +3420,11 @@
   if (ESI.Type == EST_BasicNoexcept)
     return true;
 
+  // A noexcept(expr) specification is (possibly) canonical if expr is
+  // value-dependent.
+  if (ESI.Type == EST_DependentNoexcept)
+    return true;
+
   // A dynamic exception specification is canonical if it only contains pack
   // expansions (so we can't tell whether it's non-throwing) and all its
   // contained types are canonical.
@@ -3434,11 +3439,6 @@
     return AnyPackExpansions;
   }
 
-  // A noexcept(expr) specification is (possibly) canonical if expr is
-  // value-dependent.
-  if (ESI.Type == EST_ComputedNoexcept)
-    return ESI.NoexceptExpr && ESI.NoexceptExpr->isValueDependent();
-
   return false;
 }
 
@@ -3466,7 +3466,7 @@
     // noexcept expression, or we're just looking for a canonical type.
     // Otherwise, we're going to need to create a type
     // sugar node to hold the concrete expression.
-    if (OnlyWantCanonical || EPI.ExceptionSpec.Type != EST_ComputedNoexcept ||
+    if (OnlyWantCanonical || !isComputedNoexcept(EPI.ExceptionSpec.Type) ||
         EPI.ExceptionSpec.NoexceptExpr == FPT->getNoexceptExpr())
       return Existing;
 
@@ -3513,7 +3513,7 @@
         // 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_None: case EST_MSAny: case EST_NoexceptFalse:
         CanonicalEPI.ExceptionSpec.Type = EST_None;
         break;
 
@@ -3535,24 +3535,12 @@
         break;
       }
 
-      case EST_DynamicNone: case EST_BasicNoexcept:
+      case EST_DynamicNone: case EST_BasicNoexcept: case EST_NoexceptTrue:
         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;
+      case EST_DependentNoexcept:
+        llvm_unreachable("dependent noexcept is already canonical");
       }
     } else {
       CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo();
@@ -3577,18 +3565,10 @@
   // Instead of the exception types, there could be a noexcept
   // expression, or information used to resolve the exception
   // specification.
-  size_t Size = sizeof(FunctionProtoType) +
-                NumArgs * sizeof(QualType);
-
-  if (EPI.ExceptionSpec.Type == EST_Dynamic) {
-    Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType);
-  } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) {
-    Size += sizeof(Expr*);
-  } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) {
-    Size += 2 * sizeof(FunctionDecl*);
-  } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) {
-    Size += sizeof(FunctionDecl*);
-  }
+  size_t Size =
+      sizeof(FunctionProtoType) + NumArgs * sizeof(QualType) +
+      FunctionProtoType::getExceptionSpecSize(
+          EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
 
   // Put the ExtParameterInfos last.  If all were equal, it would make
   // more sense to put these before the exception specification, because
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 05f414e..b543991 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -441,7 +441,7 @@
                                       Proto2->getExceptionType(I)))
           return false;
       }
-    } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) {
+    } else if (isComputedNoexcept(Proto1->getExceptionSpecType())) {
       if (!IsStructurallyEquivalent(Context, Proto1->getNoexceptExpr(),
                                     Proto2->getNoexceptExpr()))
         return false;
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index b2c5303..c6c9d85 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -672,7 +672,7 @@
       Proto += ")";
     } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) {
       Proto += " noexcept";
-      if (FT->getExceptionSpecType() == EST_ComputedNoexcept) {
+      if (isComputedNoexcept(FT->getExceptionSpecType())) {
         Proto += "(";
         llvm::raw_string_ostream EOut(Proto);
         FT->getNoexceptExpr()->printPretty(EOut, nullptr, SubPolicy,
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index eb2e8c5..3a204c2 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -169,8 +169,8 @@
 }
 
 bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const {
-  return getOperatorNew()->getType()->castAs<FunctionProtoType>()->isNothrow(
-             Ctx) &&
+  return getOperatorNew()->getType()->castAs<FunctionProtoType>()
+                                          ->isNothrow() &&
          !getOperatorNew()->isReservedGlobalPlacementOperator();
 }
 
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 610400d..1a656b57 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2702,7 +2702,7 @@
   // Mangle instantiation-dependent exception-specification, if present,
   // per cxx-abi-dev proposal on 2016-10-11.
   if (T->hasInstantiationDependentExceptionSpec()) {
-    if (T->getExceptionSpecType() == EST_ComputedNoexcept) {
+    if (isComputedNoexcept(T->getExceptionSpecType())) {
       Out << "DO";
       mangleExpression(T->getNoexceptExpr());
       Out << "E";
@@ -2713,7 +2713,7 @@
         mangleType(ExceptTy);
       Out << "E";
     }
-  } else if (T->isNothrow(getASTContext())) {
+  } else if (T->isNothrow()) {
     Out << "Do";
   }
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 571dc2a..93c3f63 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2800,19 +2800,21 @@
 
       exnSlot[I++] = ExceptionType;
     }
-  } else if (getExceptionSpecType() == EST_ComputedNoexcept) {
+  } else if (isComputedNoexcept(getExceptionSpecType())) {
+    assert(epi.ExceptionSpec.NoexceptExpr && "computed noexcept with no expr");
+    assert((getExceptionSpecType() == EST_DependentNoexcept) ==
+           epi.ExceptionSpec.NoexceptExpr->isValueDependent());
+
     // Store the noexcept expression and context.
     auto **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams);
     *noexSlot = epi.ExceptionSpec.NoexceptExpr;
 
-    if (epi.ExceptionSpec.NoexceptExpr) {
-      if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() ||
-          epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
-        setInstantiationDependent();
+    if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() ||
+        epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent())
+      setInstantiationDependent();
 
-      if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack())
-        setContainsUnexpandedParameterPack();
-    }
+    if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack();
   } else if (getExceptionSpecType() == EST_Uninstantiated) {
     // Store the function decl from which we will resolve our
     // exception specification.
@@ -2832,7 +2834,7 @@
   // then it's a dependent type. This only happens in C++17 onwards.
   if (isCanonicalUnqualified()) {
     if (getExceptionSpecType() == EST_Dynamic ||
-        getExceptionSpecType() == EST_ComputedNoexcept) {
+        getExceptionSpecType() == EST_DependentNoexcept) {
       assert(hasDependentExceptionSpec() && "type should not be canonical");
       setDependent();
     }
@@ -2870,52 +2872,36 @@
   return false;
 }
 
-FunctionProtoType::NoexceptResult
-FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
-  ExceptionSpecificationType est = getExceptionSpecType();
-  if (est == EST_BasicNoexcept)
-    return NR_Nothrow;
+CanThrowResult FunctionProtoType::canThrow() const {
+  switch (getExceptionSpecType()) {
+  case EST_Unparsed:
+  case EST_Unevaluated:
+  case EST_Uninstantiated:
+    llvm_unreachable("should not call this with unresolved exception specs");
 
-  if (est != EST_ComputedNoexcept)
-    return NR_NoNoexcept;
-
-  Expr *noexceptExpr = getNoexceptExpr();
-  if (!noexceptExpr)
-    return NR_BadNoexcept;
-  if (noexceptExpr->isValueDependent())
-    return NR_Dependent;
-
-  llvm::APSInt value;
-  bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, nullptr,
-                                                   /*evaluated*/false);
-  (void)isICE;
-  assert(isICE && "AST should not contain bad noexcept expressions.");
-
-  return value.getBoolValue() ? NR_Nothrow : NR_Throw;
-}
-
-CanThrowResult FunctionProtoType::canThrow(const ASTContext &Ctx) const {
-  ExceptionSpecificationType EST = getExceptionSpecType();
-  assert(EST != EST_Unevaluated && EST != EST_Uninstantiated);
-  if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
+  case EST_DynamicNone:
+  case EST_BasicNoexcept:
+  case EST_NoexceptTrue:
     return CT_Cannot;
 
-  if (EST == EST_Dynamic) {
+  case EST_None:
+  case EST_MSAny:
+  case EST_NoexceptFalse:
+    return CT_Can;
+
+  case EST_Dynamic:
     // A dynamic exception specification is throwing unless every exception
     // type is an (unexpanded) pack expansion type.
     for (unsigned I = 0, N = NumExceptions; I != N; ++I)
       if (!getExceptionType(I)->getAs<PackExpansionType>())
         return CT_Can;
     return CT_Dependent;
+
+  case EST_DependentNoexcept:
+    return CT_Dependent;
   }
 
-  if (EST != EST_ComputedNoexcept)
-    return CT_Can;
-
-  NoexceptResult NR = getNoexceptSpec(Ctx);
-  if (NR == NR_Dependent)
-    return CT_Dependent;
-  return NR == NR_Nothrow ? CT_Cannot : CT_Can;
+  llvm_unreachable("unexpected exception specification kind");
 }
 
 bool FunctionProtoType::isTemplateVariadic() const {
@@ -2965,8 +2951,7 @@
   if (epi.ExceptionSpec.Type == EST_Dynamic) {
     for (QualType Ex : epi.ExceptionSpec.Exceptions)
       ID.AddPointer(Ex.getAsOpaquePtr());
-  } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept &&
-             epi.ExceptionSpec.NoexceptExpr) {
+  } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) {
     epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical);
   } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
              epi.ExceptionSpec.Type == EST_Unevaluated) {
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index c99148e..c278dc9 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -672,7 +672,9 @@
     OS << ')';
   } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
     OS << " noexcept";
-    if (getExceptionSpecType() == EST_ComputedNoexcept) {
+    // FIXME:Is it useful to print out the expression for a non-dependent
+    // noexcept specification?
+    if (isComputedNoexcept(getExceptionSpecType())) {
       OS << '(';
       if (getNoexceptExpr())
         getNoexceptExpr()->printPretty(OS, nullptr, Policy);