[clang] [clang] Introduce `SemaExceptionSpec` (PR #92653)
Vlad Serebrennikov via cfe-commits
cfe-commits at lists.llvm.org
Sun May 19 03:15:45 PDT 2024
https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/92653
>From 06f2555364684dc7a6af10f4870523265235abe6 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 18 May 2024 17:49:06 +0300
Subject: [PATCH 1/2] [clang] Introduce `SemaExceptionSpec`
---
clang/include/clang/Sema/Sema.h | 187 ++-------
clang/include/clang/Sema/SemaExceptionSpec.h | 187 +++++++++
clang/lib/Parse/ParseCXXInlineMethods.cpp | 3 +-
clang/lib/Parse/ParseDecl.cpp | 3 +-
clang/lib/Parse/ParseDeclCXX.cpp | 3 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 3 +-
clang/lib/Sema/Sema.cpp | 12 +-
clang/lib/Sema/SemaCoroutine.cpp | 3 +-
clang/lib/Sema/SemaDecl.cpp | 13 +-
clang/lib/Sema/SemaDeclCXX.cpp | 215 +---------
clang/lib/Sema/SemaExceptionSpec.cpp | 392 ++++++++++++++----
clang/lib/Sema/SemaExpr.cpp | 5 +-
clang/lib/Sema/SemaExprCXX.cpp | 25 +-
clang/lib/Sema/SemaExprMember.cpp | 3 +-
clang/lib/Sema/SemaInit.cpp | 5 +-
clang/lib/Sema/SemaOverload.cpp | 7 +-
clang/lib/Sema/SemaTemplate.cpp | 5 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 30 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 +-
clang/lib/Sema/SemaType.cpp | 11 +-
clang/lib/Sema/TreeTransform.h | 7 +-
21 files changed, 638 insertions(+), 490 deletions(-)
create mode 100644 clang/include/clang/Sema/SemaExceptionSpec.h
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d4d4a82525a02..95a54014cf672 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -169,6 +169,7 @@ class PseudoObjectExpr;
class QualType;
class SemaCodeCompletion;
class SemaCUDA;
+class SemaExceptionSpec;
class SemaHLSL;
class SemaObjC;
class SemaOpenACC;
@@ -461,29 +462,28 @@ class Sema final : public SemaBase {
// 9. Declarations (SemaDecl.cpp)
// 10. Declaration Attribute Handling (SemaDeclAttr.cpp)
// 11. C++ Declarations (SemaDeclCXX.cpp)
- // 12. C++ Exception Specifications (SemaExceptionSpec.cpp)
- // 13. Expressions (SemaExpr.cpp)
- // 14. C++ Expressions (SemaExprCXX.cpp)
- // 15. Member Access Expressions (SemaExprMember.cpp)
- // 16. Initializers (SemaInit.cpp)
- // 17. C++ Lambda Expressions (SemaLambda.cpp)
- // 18. Name Lookup (SemaLookup.cpp)
- // 19. Modules (SemaModule.cpp)
- // 20. C++ Overloading (SemaOverload.cpp)
- // 21. Pseudo-Object (SemaPseudoObject.cpp)
- // 22. Statements (SemaStmt.cpp)
- // 23. `inline asm` Statement (SemaStmtAsm.cpp)
- // 24. Statement Attribute Handling (SemaStmtAttr.cpp)
- // 25. C++ Templates (SemaTemplate.cpp)
- // 26. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
- // 27. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
- // 28. C++ Template Declaration Instantiation
+ // 12. Expressions (SemaExpr.cpp)
+ // 13. C++ Expressions (SemaExprCXX.cpp)
+ // 14. Member Access Expressions (SemaExprMember.cpp)
+ // 15. Initializers (SemaInit.cpp)
+ // 16. C++ Lambda Expressions (SemaLambda.cpp)
+ // 17. Name Lookup (SemaLookup.cpp)
+ // 18. Modules (SemaModule.cpp)
+ // 19. C++ Overloading (SemaOverload.cpp)
+ // 20. Pseudo-Object (SemaPseudoObject.cpp)
+ // 21. Statements (SemaStmt.cpp)
+ // 22. `inline asm` Statement (SemaStmtAsm.cpp)
+ // 23. Statement Attribute Handling (SemaStmtAttr.cpp)
+ // 24. C++ Templates (SemaTemplate.cpp)
+ // 25. C++ Template Argument Deduction (SemaTemplateDeduction.cpp)
+ // 26. C++ Template Instantiation (SemaTemplateInstantiate.cpp)
+ // 27. C++ Template Declaration Instantiation
// (SemaTemplateInstantiateDecl.cpp)
- // 29. C++ Variadic Templates (SemaTemplateVariadic.cpp)
- // 30. Constraints and Concepts (SemaConcept.cpp)
- // 31. Types (SemaType.cpp)
- // 32. FixIt Helpers (SemaFixItUtils.cpp)
- // 33. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
+ // 28. C++ Variadic Templates (SemaTemplateVariadic.cpp)
+ // 29. Constraints and Concepts (SemaConcept.cpp)
+ // 30. Types (SemaType.cpp)
+ // 31. FixIt Helpers (SemaFixItUtils.cpp)
+ // 32. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
/// \name Semantic Analysis
/// Implementations are in Sema.cpp
@@ -994,6 +994,11 @@ class Sema final : public SemaBase {
return *CUDAPtr;
}
+ SemaExceptionSpec &ExceptionSpec() {
+ assert(ExceptionSpecPtr);
+ return *ExceptionSpecPtr;
+ }
+
SemaHLSL &HLSL() {
assert(HLSLPtr);
return *HLSLPtr;
@@ -1051,6 +1056,7 @@ class Sema final : public SemaBase {
std::unique_ptr<SemaCodeCompletion> CodeCompletionPtr;
std::unique_ptr<SemaCUDA> CUDAPtr;
+ std::unique_ptr<SemaExceptionSpec> ExceptionSpecPtr;
std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaObjC> ObjCPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
@@ -4048,25 +4054,6 @@ class Sema final : public SemaBase {
/// Evaluate the implicit exception specification for a defaulted
/// special member function.
void EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD);
-
- /// Check the given exception-specification and update the
- /// exception specification information with the results.
- void checkExceptionSpecification(bool IsTopLevel,
- ExceptionSpecificationType EST,
- ArrayRef<ParsedType> DynamicExceptions,
- ArrayRef<SourceRange> DynamicExceptionRanges,
- Expr *NoexceptExpr,
- SmallVectorImpl<QualType> &Exceptions,
- FunctionProtoType::ExceptionSpecInfo &ESI);
-
- /// Add an exception-specification to the given member or friend function
- /// (or function template). The exception-specification was parsed
- /// after the function itself was declared.
- void actOnDelayedExceptionSpecification(
- Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
- ArrayRef<ParsedType> DynamicExceptions,
- ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr);
-
class InheritedConstructorInfo;
/// Determine if a special member function should have a deleted
@@ -4105,12 +4092,6 @@ class Sema final : public SemaBase {
void DefineImplicitDestructor(SourceLocation CurrentLocation,
CXXDestructorDecl *Destructor);
- /// Build an exception spec for destructors that don't have one.
- ///
- /// C++11 says that user-defined destructors with no exception spec get one
- /// that looks as if the destructor was implicitly declared.
- void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor);
-
/// Define the specified inheriting constructor.
void DefineInheritingConstructor(SourceLocation UseLoc,
CXXConstructorDecl *Constructor);
@@ -4346,11 +4327,6 @@ class Sema final : public SemaBase {
void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
bool DefinitionRequired = false);
- /// Mark the exception specifications of all virtual member functions
- /// in the given class as needed.
- void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
- const CXXRecordDecl *RD);
-
/// MarkVirtualMembersReferenced - Will mark all members of the given
/// CXXRecordDecl referenced.
void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD,
@@ -4437,7 +4413,6 @@ class Sema final : public SemaBase {
bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD,
CXXSpecialMemberKind CSM,
SourceLocation DefaultLoc);
- void CheckDelayedMemberExceptionSpecs();
/// Kinds of defaulted comparison operator functions.
enum class DefaultedComparisonKind : unsigned char {
@@ -4588,7 +4563,6 @@ class Sema final : public SemaBase {
SmallVector<CXXRecordDecl *, 4> DelayedDllExportClasses;
SmallVector<CXXMethodDecl *, 4> DelayedDllExportMemberFunctions;
- void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
/// Helpers for dealing with blocks and functions.
@@ -4836,84 +4810,6 @@ class Sema final : public SemaBase {
//
//
- /// \name C++ Exception Specifications
- /// Implementations are in SemaExceptionSpec.cpp
- ///@{
-
-public:
- /// All the overriding functions seen during a class definition
- /// that had their exception spec checks delayed, plus the overridden
- /// function.
- SmallVector<std::pair<const CXXMethodDecl *, const CXXMethodDecl *>, 2>
- DelayedOverridingExceptionSpecChecks;
-
- /// All the function redeclarations seen during a class definition that had
- /// their exception spec checks delayed, plus the prior declaration they
- /// should be checked against. Except during error recovery, the new decl
- /// should always be a friend declaration, as that's the only valid way to
- /// redeclare a special member before its class is complete.
- SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 2>
- DelayedEquivalentExceptionSpecChecks;
-
- /// Determine if we're in a case where we need to (incorrectly) eagerly
- /// parse an exception specification to work around a libstdc++ bug.
- bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D);
-
- /// Check the given noexcept-specifier, convert its expression, and compute
- /// the appropriate ExceptionSpecificationType.
- ExprResult ActOnNoexceptSpec(Expr *NoexceptExpr,
- ExceptionSpecificationType &EST);
-
- CanThrowResult canThrow(const Stmt *E);
- /// Determine whether the callee of a particular function call can throw.
- /// E, D and Loc are all optional.
- static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
- SourceLocation Loc = SourceLocation());
- const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
- const FunctionProtoType *FPT);
- void UpdateExceptionSpec(FunctionDecl *FD,
- const FunctionProtoType::ExceptionSpecInfo &ESI);
- bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range);
- bool CheckDistantExceptionSpec(QualType T);
- bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
- bool CheckEquivalentExceptionSpec(const FunctionProtoType *Old,
- SourceLocation OldLoc,
- const FunctionProtoType *New,
- SourceLocation NewLoc);
- bool CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
- const PartialDiagnostic &NoteID,
- const FunctionProtoType *Old,
- SourceLocation OldLoc,
- const FunctionProtoType *New,
- SourceLocation NewLoc);
- bool handlerCanCatch(QualType HandlerType, QualType ExceptionType);
- bool CheckExceptionSpecSubset(
- const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,
- const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,
- const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,
- SourceLocation SuperLoc, const FunctionProtoType *Subset,
- bool SkipSubsetFirstParameter, SourceLocation SubLoc);
- bool CheckParamExceptionSpec(
- const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID,
- const FunctionProtoType *Target, bool SkipTargetFirstParameter,
- SourceLocation TargetLoc, const FunctionProtoType *Source,
- bool SkipSourceFirstParameter, SourceLocation SourceLoc);
-
- bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
-
- /// CheckOverridingFunctionExceptionSpec - Checks whether the exception
- /// spec is a subset of base spec.
- bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
- const CXXMethodDecl *Old);
-
- ///@}
-
- //
- //
- // -------------------------------------------------------------------------
- //
- //
-
/// \name Expressions
/// Implementations are in SemaExpr.cpp
///@{
@@ -10654,33 +10550,6 @@ class Sema final : public SemaBase {
int ParsingClassDepth = 0;
- class SavePendingParsedClassStateRAII {
- public:
- SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); }
-
- ~SavePendingParsedClassStateRAII() {
- assert(S.DelayedOverridingExceptionSpecChecks.empty() &&
- "there shouldn't be any pending delayed exception spec checks");
- assert(S.DelayedEquivalentExceptionSpecChecks.empty() &&
- "there shouldn't be any pending delayed exception spec checks");
- swapSavedState();
- }
-
- private:
- Sema &S;
- decltype(DelayedOverridingExceptionSpecChecks)
- SavedOverridingExceptionSpecChecks;
- decltype(DelayedEquivalentExceptionSpecChecks)
- SavedEquivalentExceptionSpecChecks;
-
- void swapSavedState() {
- SavedOverridingExceptionSpecChecks.swap(
- S.DelayedOverridingExceptionSpecChecks);
- SavedEquivalentExceptionSpecChecks.swap(
- S.DelayedEquivalentExceptionSpecChecks);
- }
- };
-
///@}
//
diff --git a/clang/include/clang/Sema/SemaExceptionSpec.h b/clang/include/clang/Sema/SemaExceptionSpec.h
new file mode 100644
index 0000000000000..17d505e977889
--- /dev/null
+++ b/clang/include/clang/Sema/SemaExceptionSpec.h
@@ -0,0 +1,187 @@
+//===--- SemaExceptionSpec.h --- C++ exception specification ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares routines for C++ exception specification testing.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMAEXCEPTIONSPEC_H
+#define LLVM_CLANG_SEMA_SEMAEXCEPTIONSPEC_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/SemaBase.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include <utility>
+
+namespace clang {
+class SemaExceptionSpec : public SemaBase {
+public:
+ SemaExceptionSpec(Sema &S);
+
+ /// All the overriding functions seen during a class definition
+ /// that had their exception spec checks delayed, plus the overridden
+ /// function.
+ SmallVector<std::pair<const CXXMethodDecl *, const CXXMethodDecl *>, 2>
+ DelayedOverridingExceptionSpecChecks;
+
+ /// All the function redeclarations seen during a class definition that had
+ /// their exception spec checks delayed, plus the prior declaration they
+ /// should be checked against. Except during error recovery, the new decl
+ /// should always be a friend declaration, as that's the only valid way to
+ /// redeclare a special member before its class is complete.
+ SmallVector<std::pair<FunctionDecl *, FunctionDecl *>, 2>
+ DelayedEquivalentExceptionSpecChecks;
+
+ /// Determine if we're in a case where we need to (incorrectly) eagerly
+ /// parse an exception specification to work around a libstdc++ bug.
+ bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D);
+
+ /// Check the given noexcept-specifier, convert its expression, and compute
+ /// the appropriate ExceptionSpecificationType.
+ ExprResult ActOnNoexceptSpec(Expr *NoexceptExpr,
+ ExceptionSpecificationType &EST);
+
+ CanThrowResult canThrow(const Stmt *E);
+ /// Determine whether the callee of a particular function call can throw.
+ /// E, D and Loc are all optional.
+ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+ SourceLocation Loc = SourceLocation());
+ const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
+ const FunctionProtoType *FPT);
+ void UpdateExceptionSpec(FunctionDecl *FD,
+ const FunctionProtoType::ExceptionSpecInfo &ESI);
+ bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range);
+ bool CheckDistantExceptionSpec(QualType T);
+ bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
+ bool CheckEquivalentExceptionSpec(const FunctionProtoType *Old,
+ SourceLocation OldLoc,
+ const FunctionProtoType *New,
+ SourceLocation NewLoc);
+ bool CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+ const PartialDiagnostic &NoteID,
+ const FunctionProtoType *Old,
+ SourceLocation OldLoc,
+ const FunctionProtoType *New,
+ SourceLocation NewLoc);
+ bool handlerCanCatch(QualType HandlerType, QualType ExceptionType);
+ bool CheckExceptionSpecSubset(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,
+ const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,
+ const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,
+ SourceLocation SuperLoc, const FunctionProtoType *Subset,
+ bool SkipSubsetFirstParameter, SourceLocation SubLoc);
+ bool CheckParamExceptionSpec(
+ const PartialDiagnostic &NestedDiagID, const PartialDiagnostic &NoteID,
+ const FunctionProtoType *Target, bool SkipTargetFirstParameter,
+ SourceLocation TargetLoc, const FunctionProtoType *Source,
+ bool SkipSourceFirstParameter, SourceLocation SourceLoc);
+
+ bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType);
+
+ /// CheckOverridingFunctionExceptionSpec - Checks whether the exception
+ /// spec is a subset of base spec.
+ bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
+
+ void CheckDelayedMemberExceptionSpecs();
+
+ /// Helper class that collects exception specifications for
+ /// implicitly-declared special member functions.
+ class ImplicitExceptionSpecification {
+ // Pointer to allow copying
+ Sema *Self;
+ // We order exception specifications thus:
+ // noexcept is the most restrictive, but is only used in C++11.
+ // throw() comes next.
+ // Then a throw(collected exceptions)
+ // Finally no specification, which is expressed as noexcept(false).
+ // throw(...) is used instead if any called function uses it.
+ ExceptionSpecificationType ComputedEST;
+ llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen;
+ SmallVector<QualType, 4> Exceptions;
+
+ void ClearExceptions() {
+ ExceptionsSeen.clear();
+ Exceptions.clear();
+ }
+
+ public:
+ explicit ImplicitExceptionSpecification(Sema &Self);
+
+ /// Get the computed exception specification type.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ assert(!isComputedNoexcept(ComputedEST) &&
+ "noexcept(expr) should not be a possible result");
+ return ComputedEST;
+ }
+
+ /// The number of exceptions in the exception specification.
+ unsigned size() const { return Exceptions.size(); }
+
+ /// The set of exceptions in the exception specification.
+ const QualType *data() const { return Exceptions.data(); }
+
+ /// Integrate another called method into the collected data.
+ void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method);
+
+ /// Integrate an invoked expression into the collected data.
+ void CalledExpr(Expr *E) { CalledStmt(E); }
+
+ /// Integrate an invoked statement into the collected data.
+ void CalledStmt(Stmt *S);
+
+ /// Overwrite an EPI's exception specification with this
+ /// computed exception specification.
+ FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const;
+ };
+
+ /// Check the given exception-specification and update the
+ /// exception specification information with the results.
+ void checkExceptionSpecification(bool IsTopLevel,
+ ExceptionSpecificationType EST,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges,
+ Expr *NoexceptExpr,
+ SmallVectorImpl<QualType> &Exceptions,
+ FunctionProtoType::ExceptionSpecInfo &ESI);
+
+ /// Add an exception-specification to the given member or friend function
+ /// (or function template). The exception-specification was parsed
+ /// after the function itself was declared.
+ void actOnDelayedExceptionSpecification(
+ Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr);
+
+ /// Build an exception spec for destructors that don't have one.
+ ///
+ /// C++11 says that user-defined destructors with no exception spec get one
+ /// that looks as if the destructor was implicitly declared.
+ void AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor);
+
+ /// Mark the exception specifications of all virtual member functions
+ /// in the given class as needed.
+ void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
+ const CXXRecordDecl *RD);
+
+ void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMAEXCEPTIONSPEC_H
\ No newline at end of file
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 943ce0fdde3a3..ccff9db1238a0 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -17,6 +17,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaExceptionSpec.h"
using namespace clang;
@@ -539,7 +540,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
// Attach the exception-specification to the method.
- Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
+ Actions.ExceptionSpec().actOnDelayedExceptionSpecification(LM.Method, EST,
SpecificationRange,
DynamicExceptions,
DynamicExceptionRanges,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 8405b44685ae4..b1c4f68ac4901 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -29,6 +29,7 @@
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaCodeCompletion.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
#include "llvm/ADT/SmallSet.h"
@@ -7531,7 +7532,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// delayed (even if this is a friend declaration).
bool Delayed = D.getContext() == DeclaratorContext::Member &&
D.isFunctionDeclaratorAFunctionDeclaration();
- if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) &&
+ if (Delayed && Actions.ExceptionSpec().isLibstdcxxEagerExceptionSpecHack(D) &&
GetLookAheadToken(0).is(tok::kw_noexcept) &&
GetLookAheadToken(1).is(tok::l_paren) &&
GetLookAheadToken(2).is(tok::kw_noexcept) &&
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5eaec2b621e6f..e51252cdeddb3 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -28,6 +28,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCodeCompletion.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/TimeProfiler.h"
#include <optional>
@@ -4139,7 +4140,7 @@ ExceptionSpecificationType Parser::tryParseExceptionSpecification(
T.consumeClose();
if (!NoexceptExpr.isInvalid()) {
NoexceptExpr =
- Actions.ActOnNoexceptSpec(NoexceptExpr.get(), NoexceptType);
+ Actions.ExceptionSpec().ActOnNoexceptSpec(NoexceptExpr.get(), NoexceptType);
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
NoexceptType = EST_BasicNoexcept;
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index b9d0b59ef1db7..3e1ec7a378acd 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -43,6 +43,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
@@ -331,7 +332,7 @@ static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
QualType Caught = Catch->getCaughtType();
if (Caught.isNull() || // catch (...) catches everything
!E->getSubExpr() || // throw; is considered cuaght by any handler
- S.handlerCanCatch(Caught, E->getSubExpr()->getType()))
+ S.ExceptionSpec().handlerCanCatch(Caught, E->getSubExpr()->getType()))
// Exception doesn't escape via this path.
break;
} else {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index f847c49920cf3..dc8547d36a641 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -44,6 +44,7 @@
#include "clang/Sema/SemaCUDA.h"
#include "clang/Sema/SemaCodeCompletion.h"
#include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
@@ -206,6 +207,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CodeCompletionPtr(
std::make_unique<SemaCodeCompletion>(*this, CodeCompleter)),
CUDAPtr(std::make_unique<SemaCUDA>(*this)),
+ ExceptionSpecPtr(std::make_unique<SemaExceptionSpec>(*this)),
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
ObjCPtr(std::make_unique<SemaObjC>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
@@ -1140,7 +1142,7 @@ void Sema::ActOnEndOfTranslationUnit() {
if (LateTemplateParserCleanup)
LateTemplateParserCleanup(OpaqueParser);
- CheckDelayedMemberExceptionSpecs();
+ ExceptionSpec().CheckDelayedMemberExceptionSpecs();
} else {
// If we are building a TU prefix for serialization, it is safe to transfer
// these over, even though they are not parsed. The end of the TU should be
@@ -1164,8 +1166,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// All delayed member exception specs should be checked or we end up accepting
// incompatible declarations.
- assert(DelayedOverridingExceptionSpecChecks.empty());
- assert(DelayedEquivalentExceptionSpecChecks.empty());
+ assert(ExceptionSpec().DelayedOverridingExceptionSpecChecks.empty());
+ assert(ExceptionSpec().DelayedEquivalentExceptionSpecChecks.empty());
// All dllexport classes should have been processed already.
assert(DelayedDllExportClasses.empty());
@@ -2190,7 +2192,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) {
if (!Result.isInvalid()) {
Result = S.MaybeCreateExprWithCleanups(Result);
Expr *Init = Result.getAs<Expr>();
- S.Context.setBlockVarCopyInit(VD, Init, S.canThrow(Init));
+ S.Context.setBlockVarCopyInit(VD, Init, S.ExceptionSpec().canThrow(Init));
}
// The destructor's exception specification is needed when IRGen generates
@@ -2198,7 +2200,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) {
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (CXXDestructorDecl *DD = RD->getDestructor()) {
auto *FPT = DD->getType()->castAs<FunctionProtoType>();
- S.ResolveExceptionSpec(Loc, FPT);
+ S.ExceptionSpec().ResolveExceptionSpec(Loc, FPT);
}
}
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 81334c817b2af..41eb97a391857 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -25,6 +25,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallSet.h"
@@ -614,7 +615,7 @@ static void checkNoThrow(Sema &S, const Stmt *E,
auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
// In the case of dtor, the call to dtor is implicit and hence we should
// pass nullptr to canCalleeThrow.
- if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
+ if (SemaExceptionSpec::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// co_await promise.final_suspend() could end up calling
// __builtin_coro_resume for symmetric transfer if await_suspend()
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f2b9202255cd4..2d9fd6a3a614d 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -46,6 +46,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
@@ -4036,7 +4037,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,
// types again after this. Because this updates the type, we do this before
// any of the other checks below, which may update the "de facto" NewQType
// but do not necessarily update the type of New.
- if (CheckEquivalentExceptionSpec(Old, New))
+ if (ExceptionSpec().CheckEquivalentExceptionSpec(Old, New))
return true;
// C++11 [dcl.attr.noreturn]p1:
@@ -4415,7 +4416,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
return;
} else if (Context.hasSameType(New->getType(), Old->getType())) {
// These could still be something that needs exception specs checked.
- return MergeVarDeclExceptionSpecs(New, Old);
+ return ExceptionSpec().MergeVarDeclExceptionSpecs(New, Old);
}
// C++ [basic.link]p10:
// [...] the types specified by all declarations referring to a given
@@ -8995,7 +8996,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
MD->addOverriddenMethod(BaseMD);
CheckOverridingFunctionReturnType(MD, BaseMD);
CheckOverridingFunctionAttributes(MD, BaseMD);
- CheckOverridingFunctionExceptionSpec(MD, BaseMD);
+ ExceptionSpec().CheckOverridingFunctionExceptionSpec(MD, BaseMD);
CheckIfOverriddenFunctionIsMarkedFinal(MD, BaseMD);
}
@@ -9365,7 +9366,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// now. FIXME: It'd be nice to be able to create the right type to start
// with, but the type needs to reference the destructor declaration.
if (SemaRef.getLangOpts().CPlusPlus11)
- SemaRef.AdjustDestructorExceptionSpec(NewDD);
+ SemaRef.ExceptionSpec().AdjustDestructorExceptionSpec(NewDD);
IsVirtualOkay = true;
return NewDD;
@@ -11331,7 +11332,7 @@ bool Sema::areMultiversionVariantFunctionsCompatible(
if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC())
return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << LanguageLinkage;
- if (CheckEquivalentExceptionSpec(
+ if (ExceptionSpec().CheckEquivalentExceptionSpec(
OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(),
NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation()))
return true;
@@ -15812,7 +15813,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// Ensure that the function's exception specification is instantiated.
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
- ResolveExceptionSpec(D->getLocation(), FPT);
+ ExceptionSpec().ResolveExceptionSpec(D->getLocation(), FPT);
// dllimport cannot be applied to non-inline function definitions.
if (FD->hasAttr<DLLImportAttr>() && !FD->isInlined() &&
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8225381985052..8e7f07d7efedf 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -43,6 +43,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
@@ -191,7 +192,7 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc,
const FunctionProtoType *Proto
= Method->getType()->getAs<FunctionProtoType>();
- Proto = Self->ResolveExceptionSpec(CallLoc, Proto);
+ Proto = Self->ExceptionSpec().ResolveExceptionSpec(CallLoc, Proto);
if (!Proto)
return;
@@ -276,7 +277,7 @@ void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) {
// implicit definition. For now, we assume that any non-nothrow expression can
// throw any exception.
- if (Self->canThrow(S))
+ if (Self->ExceptionSpec().canThrow(S))
ComputedEST = EST_None;
}
@@ -1607,48 +1608,6 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
DD->setInvalidDecl();
}
-/// Merge the exception specifications of two variable declarations.
-///
-/// This is called when there's a redeclaration of a VarDecl. The function
-/// checks if the redeclaration might have an exception specification and
-/// validates compatibility and merges the specs if necessary.
-void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
- // Shortcut if exceptions are disabled.
- if (!getLangOpts().CXXExceptions)
- return;
-
- assert(Context.hasSameType(New->getType(), Old->getType()) &&
- "Should only be called if types are otherwise the same.");
-
- QualType NewType = New->getType();
- QualType OldType = Old->getType();
-
- // We're only interested in pointers and references to functions, as well
- // as pointers to member functions.
- if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
- NewType = R->getPointeeType();
- OldType = OldType->castAs<ReferenceType>()->getPointeeType();
- } else if (const PointerType *P = NewType->getAs<PointerType>()) {
- NewType = P->getPointeeType();
- OldType = OldType->castAs<PointerType>()->getPointeeType();
- } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
- NewType = M->getPointeeType();
- OldType = OldType->castAs<MemberPointerType>()->getPointeeType();
- }
-
- if (!NewType->isFunctionProtoType())
- return;
-
- // There's lots of special cases for functions. For function pointers, system
- // libraries are hopefully not as broken so that we don't need these
- // workarounds.
- if (CheckEquivalentExceptionSpec(
- OldType->getAs<FunctionProtoType>(), Old->getLocation(),
- NewType->getAs<FunctionProtoType>(), New->getLocation())) {
- New->setInvalidDecl();
- }
-}
-
/// CheckCXXDefaultArguments - Verify that the default arguments for a
/// function declaration are well-formed according to C++
/// [dcl.fct.default].
@@ -7681,7 +7640,7 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD) {
auto ESI = IES.getExceptionSpec();
// Update the type of the special member to use it.
- UpdateExceptionSpec(FD, ESI);
+ ExceptionSpec().UpdateExceptionSpec(FD, ESI);
}
void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) {
@@ -9221,7 +9180,7 @@ void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
// The exception specification is needed because we are defining the
// function. Note that this will reuse the body we just built.
- ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
if (ASTMutationListener *L = getASTMutationListener())
L->CompletedImplicitDefinition(FD);
@@ -9271,24 +9230,6 @@ ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc,
return ExceptSpec;
}
-void Sema::CheckDelayedMemberExceptionSpecs() {
- decltype(DelayedOverridingExceptionSpecChecks) Overriding;
- decltype(DelayedEquivalentExceptionSpecChecks) Equivalent;
-
- std::swap(Overriding, DelayedOverridingExceptionSpecChecks);
- std::swap(Equivalent, DelayedEquivalentExceptionSpecChecks);
-
- // Perform any deferred checking of exception specifications for virtual
- // destructors.
- for (auto &Check : Overriding)
- CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
-
- // Perform any deferred checking of exception specifications for befriended
- // special members.
- for (auto &Check : Equivalent)
- CheckEquivalentExceptionSpec(Check.second, Check.first);
-}
-
namespace {
/// CRTP base class for visiting operations performed by a special member
/// function (or inherited constructor).
@@ -14112,7 +14053,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
Constructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -14139,7 +14080,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
// Perform any delayed checks on exception specifications.
- CheckDelayedMemberExceptionSpecs();
+ ExceptionSpec().CheckDelayedMemberExceptionSpecs();
}
/// Find or create the fake constructor we synthesize to model constructing an
@@ -14252,7 +14193,7 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
Constructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -14401,7 +14342,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
Destructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -14452,8 +14393,8 @@ void Sema::ActOnFinishCXXMemberDecls() {
// If the context is an invalid C++ class, just suppress these checks.
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
if (Record->isInvalidDecl()) {
- DelayedOverridingExceptionSpecChecks.clear();
- DelayedEquivalentExceptionSpecChecks.clear();
+ ExceptionSpec().DelayedOverridingExceptionSpecChecks.clear();
+ ExceptionSpec().DelayedEquivalentExceptionSpecChecks.clear();
return;
}
checkForMultipleExportedDefaultConstructors(*this, Record);
@@ -14490,37 +14431,6 @@ void Sema::referenceDLLExportedClassMethods() {
}
}
-void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
- assert(getLangOpts().CPlusPlus11 &&
- "adjusting dtor exception specs was introduced in c++11");
-
- if (Destructor->isDependentContext())
- return;
-
- // C++11 [class.dtor]p3:
- // A declaration of a destructor that does not have an exception-
- // specification is implicitly considered to have the same exception-
- // specification as an implicit declaration.
- const auto *DtorType = Destructor->getType()->castAs<FunctionProtoType>();
- if (DtorType->hasExceptionSpec())
- return;
-
- // Replace the destructor's type, building off the existing one. Fortunately,
- // the only thing of interest in the destructor type is its extended info.
- // The return and arguments are fixed.
- FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
- EPI.ExceptionSpec.Type = EST_Unevaluated;
- EPI.ExceptionSpec.SourceDecl = Destructor;
- Destructor->setType(
- Context.getFunctionType(Context.VoidTy, std::nullopt, EPI));
-
- // FIXME: If the destructor has a body that could throw, and the newly created
- // spec doesn't allow exceptions, we should emit a warning, because this
- // change in behavior can break conforming C++03 programs at runtime.
- // However, we don't have a body or an exception specification yet, so it
- // needs to be done somewhere else.
-}
-
namespace {
/// An abstract base class for all helper classes used in building the
// copy/move operators. These classes serve as factory functions and help us
@@ -15104,7 +15014,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
CopyAssignOperator->getType()->castAs<FunctionProtoType>());
// Add a context note for diagnostics produced after this point.
@@ -15501,7 +15411,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
MoveAssignOperator->getType()->castAs<FunctionProtoType>());
// Add a context note for diagnostics produced after this point.
@@ -15814,7 +15724,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
CopyConstructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -15953,7 +15863,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ResolveExceptionSpec(CurrentLocation,
+ ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
MoveConstructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -18781,7 +18691,7 @@ bool Sema::DefineUsedVTables() {
// if we are not providing an authoritative form of the vtable in this TU.
// We may choose to emit it available_externally anyway.
if (!DefineVTable) {
- MarkVirtualMemberExceptionSpecsNeeded(Loc, Class);
+ ExceptionSpec().MarkVirtualMemberExceptionSpecsNeeded(Loc, Class);
continue;
}
@@ -18811,13 +18721,6 @@ bool Sema::DefineUsedVTables() {
return DefinedAnything;
}
-void Sema::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
- const CXXRecordDecl *RD) {
- for (const auto *I : RD->methods())
- if (I->isVirtual() && !I->isPureVirtual())
- ResolveExceptionSpec(Loc, I->getType()->castAs<FunctionProtoType>());
-}
-
void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
const CXXRecordDecl *RD,
bool ConstexprOnly) {
@@ -19074,92 +18977,6 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
return false;
}
-void Sema::checkExceptionSpecification(
- bool IsTopLevel, 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) {
- Exceptions.reserve(DynamicExceptions.size());
- for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) {
- // 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;
- }
- }
-
- // Check that the type is valid for an exception spec, and
- // drop it if not.
- if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei]))
- Exceptions.push_back(ET);
- }
- ESI.Exceptions = Exceptions;
- return;
- }
-
- if (isComputedNoexcept(EST)) {
- assert((NoexceptExpr->isTypeDependent() ||
- NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
- Context.BoolTy) &&
- "Parser should have made sure that the expression is boolean");
- if (IsTopLevel && DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
- ESI.Type = EST_BasicNoexcept;
- return;
- }
-
- ESI.NoexceptExpr = NoexceptExpr;
- return;
- }
-}
-
-void Sema::actOnDelayedExceptionSpecification(
- Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
- ArrayRef<ParsedType> DynamicExceptions,
- ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr) {
- if (!D)
- return;
-
- // Dig out the function we're referring to.
- if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
- D = FTD->getTemplatedDecl();
-
- FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (!FD)
- return;
-
- // Check the exception specification.
- llvm::SmallVector<QualType, 4> Exceptions;
- FunctionProtoType::ExceptionSpecInfo ESI;
- checkExceptionSpecification(/*IsTopLevel=*/true, EST, DynamicExceptions,
- DynamicExceptionRanges, NoexceptExpr, Exceptions,
- ESI);
-
- // Update the exception specification on the function type.
- Context.adjustExceptionSpec(FD, ESI, /*AsWritten=*/true);
-
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->isStatic())
- checkThisInStaticMemberFunctionExceptionSpec(MD);
-
- if (MD->isVirtual()) {
- // Check overrides, which we previously had to delay.
- for (const CXXMethodDecl *O : MD->overridden_methods())
- CheckOverridingFunctionExceptionSpec(MD, O);
- }
- }
-}
-
/// HandleMSProperty - Analyze a __delcspec(property) field of a C++ class.
///
MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 41bf273d12f2f..d8548ba8cbc79 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
@@ -19,6 +19,9 @@
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/EnterExpressionEvaluationContext.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include <optional>
@@ -42,8 +45,8 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T)
/// we're in such a case and turns off delay-parsing of exception
/// specifications. Libstdc++ 6.1 (released 2016-04-27) appears to have
/// resolved it as side-effect of commit ddb63209a8d (2015-06-05).
-bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
- auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
+bool SemaExceptionSpec::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
+ auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext);
// All the problem cases are member functions named "swap" within class
// templates declared directly within namespace std or std::__debug or
@@ -67,7 +70,7 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
}
// Only apply this hack within a system header.
- if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc()))
+ if (!SemaRef.Context.getSourceManager().isInSystemHeader(D.getBeginLoc()))
return false;
return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
@@ -79,9 +82,9 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
.Default(false);
}
-ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr,
+ExprResult SemaExceptionSpec::ActOnNoexceptSpec(Expr *NoexceptExpr,
ExceptionSpecificationType &EST) {
-
+ ASTContext &Context = getASTContext();
if (NoexceptExpr->isTypeDependent() ||
NoexceptExpr->containsUnexpandedParameterPack()) {
EST = EST_DependentNoexcept;
@@ -89,8 +92,8 @@ ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr,
}
llvm::APSInt Result;
- ExprResult Converted = CheckConvertedConstantExpression(
- NoexceptExpr, Context.BoolTy, Result, CCEK_Noexcept);
+ ExprResult Converted = SemaRef.CheckConvertedConstantExpression(
+ NoexceptExpr, Context.BoolTy, Result, Sema::CCEK_Noexcept);
if (Converted.isInvalid()) {
EST = EST_NoexceptFalse;
@@ -118,7 +121,7 @@ ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr,
///
/// \param[in,out] T The exception type. This will be decayed to a pointer type
/// when the input is an array or a function type.
-bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
+bool SemaExceptionSpec::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
// C++11 [except.spec]p2:
// A type cv T, "array of T", or "function returning T" denoted
// in an exception-specification is adjusted to type T, "pointer to T", or
@@ -126,9 +129,9 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
//
// We also apply this rule in C++98.
if (T->isArrayType())
- T = Context.getArrayDecayedType(T);
+ T = SemaRef.Context.getArrayDecayedType(T);
else if (T->isFunctionType())
- T = Context.getPointerType(T);
+ T = SemaRef.Context.getPointerType(T);
int Kind = 0;
QualType PointeeT = T;
@@ -169,7 +172,7 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
}
if (!(PointeeT->isRecordType() &&
PointeeT->castAs<RecordType>()->isBeingDefined()) &&
- RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
+ SemaRef.RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
// WebAssembly reference types can't be used in exception specifications.
@@ -192,7 +195,7 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
/// to member to a function with an exception specification. This means that
/// it is invalid to add another level of indirection.
-bool Sema::CheckDistantExceptionSpec(QualType T) {
+bool SemaExceptionSpec::CheckDistantExceptionSpec(QualType T) {
// C++17 removes this rule in favor of putting exception specifications into
// the type system.
if (getLangOpts().CPlusPlus17)
@@ -213,7 +216,7 @@ bool Sema::CheckDistantExceptionSpec(QualType T) {
}
const FunctionProtoType *
-Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
+SemaExceptionSpec::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
if (FPT->getExceptionSpecType() == EST_Unparsed) {
Diag(Loc, diag::err_exception_spec_not_parsed);
return nullptr;
@@ -232,9 +235,9 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
// Compute or instantiate the exception specification now.
if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
- EvaluateImplicitExceptionSpec(Loc, SourceDecl);
+ SemaRef.EvaluateImplicitExceptionSpec(Loc, SourceDecl);
else
- InstantiateExceptionSpec(Loc, SourceDecl);
+ SemaRef.InstantiateExceptionSpec(Loc, SourceDecl);
const FunctionProtoType *Proto =
SourceDecl->getType()->castAs<FunctionProtoType>();
@@ -246,15 +249,15 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
}
void
-Sema::UpdateExceptionSpec(FunctionDecl *FD,
+SemaExceptionSpec::UpdateExceptionSpec(FunctionDecl *FD,
const FunctionProtoType::ExceptionSpecInfo &ESI) {
// If we've fully resolved the exception specification, notify listeners.
if (!isUnresolvedExceptionSpec(ESI.Type))
- if (auto *Listener = getASTMutationListener())
+ if (auto *Listener = SemaRef.getASTMutationListener())
Listener->ResolvedExceptionSpec(FD);
for (FunctionDecl *Redecl : FD->redecls())
- Context.adjustExceptionSpec(Redecl, ESI);
+ SemaRef.Context.adjustExceptionSpec(Redecl, ESI);
}
static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) {
@@ -296,7 +299,7 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
return !Ty->hasExceptionSpec();
}
-bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Just completely ignore this under -fno-exceptions prior to C++17.
// In C++17 onwards, the exception specification is part of the type and
// we will diagnose mismatches anyway, so it's better to check for them here.
@@ -326,7 +329,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Check the types as written: they must match before any exception
// specification adjustment is applied.
if (!CheckEquivalentExceptionSpecImpl(
- *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
+ SemaRef, SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::note_previous_declaration),
Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
&MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
@@ -362,10 +365,10 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Likewise if the old function is a builtin.
if (MissingEmptyExceptionSpecification &&
(Old->getLocation().isInvalid() ||
- Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
+ SemaRef.Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
Old->getBuiltinID()) &&
Old->isExternC()) {
- New->setType(Context.getFunctionType(
+ New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(),
NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));
return false;
@@ -392,7 +395,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
} else {
// Update the type of the function with the appropriate exception
// specification.
- New->setType(Context.getFunctionType(
+ New->setType(SemaRef.Context.getFunctionType(
NewProto->getReturnType(), NewProto->getParamTypes(),
NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
}
@@ -437,7 +440,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
else
OS << ", ";
- OS << E.getAsString(getPrintingPolicy());
+ OS << E.getAsString(SemaRef.getPrintingPolicy());
}
OS << ")";
break;
@@ -452,7 +455,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
case EST_NoexceptTrue:
OS << "noexcept(";
assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
- OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
+ OldProto->getNoexceptExpr()->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
OS << ")";
break;
case EST_NoThrow:
@@ -473,7 +476,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// location when there is a trailing return type.
if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>())
if (!FTLoc.getTypePtr()->hasTrailingReturn())
- FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());
+ FixItLoc = SemaRef.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
}
if (FixItLoc.isInvalid())
@@ -495,7 +498,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
/// exception specifications. Exception specifications are equivalent if
/// they allow exactly the same set of exception types. It does not matter how
/// that is achieved. See C++ [except.spec]p2.
-bool Sema::CheckEquivalentExceptionSpec(
+bool SemaExceptionSpec::CheckEquivalentExceptionSpec(
const FunctionProtoType *Old, SourceLocation OldLoc,
const FunctionProtoType *New, SourceLocation NewLoc) {
if (!getLangOpts().CXXExceptions)
@@ -505,7 +508,7 @@ bool Sema::CheckEquivalentExceptionSpec(
if (getLangOpts().MSVCCompat)
DiagID = diag::ext_mismatched_exception_spec;
bool Result = CheckEquivalentExceptionSpecImpl(
- *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
+ SemaRef, SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
// In Microsoft mode, mismatching exception specifications just cause a warning.
@@ -533,10 +536,10 @@ static bool CheckEquivalentExceptionSpecImpl(
if (MissingEmptyExceptionSpecification)
*MissingEmptyExceptionSpecification = false;
- Old = S.ResolveExceptionSpec(NewLoc, Old);
+ Old = S.ExceptionSpec().ResolveExceptionSpec(NewLoc, Old);
if (!Old)
return false;
- New = S.ResolveExceptionSpec(NewLoc, New);
+ New = S.ExceptionSpec().ResolveExceptionSpec(NewLoc, New);
if (!New)
return false;
@@ -671,7 +674,7 @@ static bool CheckEquivalentExceptionSpecImpl(
return true;
}
-bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
+bool SemaExceptionSpec::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
const PartialDiagnostic &NoteID,
const FunctionProtoType *Old,
SourceLocation OldLoc,
@@ -679,11 +682,12 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
SourceLocation NewLoc) {
if (!getLangOpts().CXXExceptions)
return false;
- return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,
+ return CheckEquivalentExceptionSpecImpl(SemaRef, DiagID, NoteID, Old, OldLoc,
New, NewLoc);
}
-bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
+bool SemaExceptionSpec::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
+ ASTContext &Context = getASTContext();
// [except.handle]p3:
// A handler is a match for an exception object of type E if:
@@ -717,9 +721,9 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
QualType Result;
// FIXME: Should we treat the exception as catchable if a lifetime
// conversion is required?
- if (IsQualificationConversion(ExceptionType, HandlerType, false,
+ if (SemaRef.IsQualificationConversion(ExceptionType, HandlerType, false,
LifetimeConv) ||
- IsFunctionConversion(ExceptionType, HandlerType, Result))
+ SemaRef.IsFunctionConversion(ExceptionType, HandlerType, Result))
return true;
// -- a standard pointer conversion [...]
@@ -747,21 +751,21 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
return false;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
- if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||
+ if (!SemaRef.IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(HandlerType)))
return false;
// Do this check from a context without privileges.
- switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,
+ switch (SemaRef.CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,
Paths.front(),
/*Diagnostic*/ 0,
/*ForceCheck*/ true,
/*ForceUnprivileged*/ true)) {
- case AR_accessible: return true;
- case AR_inaccessible: return false;
- case AR_dependent:
+ case Sema::AR_accessible: return true;
+ case Sema::AR_inaccessible: return false;
+ case Sema::AR_dependent:
llvm_unreachable("access check dependent for unprivileged context");
- case AR_delayed:
+ case Sema::AR_delayed:
llvm_unreachable("access check delayed in non-declaration");
}
llvm_unreachable("unexpected access check result");
@@ -770,7 +774,7 @@ bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
/// CheckExceptionSpecSubset - Check whether the second function type's
/// exception specification is a subset (or equivalent) of the first function
/// type. This is used by override and pointer assignment checks.
-bool Sema::CheckExceptionSpecSubset(
+bool SemaExceptionSpec::CheckExceptionSpecSubset(
const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,
const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,
const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,
@@ -886,7 +890,7 @@ CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
if (!SFunc)
return false;
- return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
+ return S.ExceptionSpec().CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
SFunc, SourceLoc);
}
@@ -895,7 +899,7 @@ CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
/// 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(
+bool SemaExceptionSpec::CheckParamExceptionSpec(
const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
const FunctionProtoType *Target, bool SkipTargetFirstParameter,
SourceLocation TargetLoc, const FunctionProtoType *Source,
@@ -903,7 +907,7 @@ bool Sema::CheckParamExceptionSpec(
auto RetDiag = DiagID;
RetDiag << 0;
if (CheckSpecForTypesEquivalent(
- *this, RetDiag, PDiag(),
+ SemaRef, RetDiag, SemaRef.PDiag(),
Target->getReturnType(), TargetLoc, Source->getReturnType(),
SourceLoc))
return true;
@@ -917,7 +921,7 @@ bool Sema::CheckParamExceptionSpec(
auto ParamDiag = DiagID;
ParamDiag << 1;
if (CheckSpecForTypesEquivalent(
- *this, ParamDiag, PDiag(),
+ SemaRef, ParamDiag, SemaRef.PDiag(),
Target->getParamType(i + (SkipTargetFirstParameter ? 1 : 0)),
TargetLoc, Source->getParamType(SkipSourceFirstParameter ? 1 : 0),
SourceLoc))
@@ -926,7 +930,7 @@ bool Sema::CheckParamExceptionSpec(
return false;
}
-bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
+bool SemaExceptionSpec::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);
@@ -960,14 +964,14 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
// void (*q)(void (*) throw(int)) = p;
// }
// ... because it might be instantiated with T=int.
- return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),
- PDiag(), ToFunc, 0,
+ return CheckExceptionSpecSubset(SemaRef.PDiag(DiagID), SemaRef.PDiag(NestedDiagID), SemaRef.PDiag(),
+ SemaRef.PDiag(), ToFunc, 0,
From->getSourceRange().getBegin(), FromFunc,
0, SourceLocation()) &&
!getLangOpts().CPlusPlus17;
}
-bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
+bool SemaExceptionSpec::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
// If the new exception specification hasn't been parsed yet, skip the check.
// We'll get called again once it's been parsed.
@@ -993,9 +997,9 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
if (getLangOpts().MSVCCompat)
DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(
- PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ),
- PDiag(diag::note_overridden_virtual_function),
- PDiag(diag::ext_override_exception_spec),
+ SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::err_deep_exception_specs_differ),
+ SemaRef.PDiag(diag::note_overridden_virtual_function),
+ SemaRef.PDiag(diag::ext_override_exception_spec),
Old->getType()->castAs<FunctionProtoType>(),
Old->hasCXXExplicitFunctionObjectParameter(), Old->getLocation(),
New->getType()->castAs<FunctionProtoType>(),
@@ -1007,14 +1011,14 @@ static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
for (const Stmt *SubStmt : S->children()) {
if (!SubStmt)
continue;
- R = mergeCanThrow(R, Self.canThrow(SubStmt));
+ R = mergeCanThrow(R, Self.ExceptionSpec().canThrow(SubStmt));
if (R == CT_Can)
break;
}
return R;
}
-CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
+CanThrowResult SemaExceptionSpec::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
SourceLocation Loc) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
@@ -1062,7 +1066,7 @@ CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
return CT_Can;
if (Loc.isValid() || (Loc.isInvalid() && E))
- FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
+ FT = S.ExceptionSpec().ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
@@ -1075,7 +1079,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
// Initialization might throw.
if (!VD->isUsableInConstantExpressions(Self.Context))
if (const Expr *Init = VD->getInit())
- CT = mergeCanThrow(CT, Self.canThrow(Init));
+ CT = mergeCanThrow(CT, Self.ExceptionSpec().canThrow(Init));
// Destructor might throw.
if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) {
@@ -1083,7 +1087,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
if (auto *Dtor = RD->getDestructor()) {
CT = mergeCanThrow(
- CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ CT, SemaExceptionSpec::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
}
}
}
@@ -1131,7 +1135,7 @@ static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
return CT_Can;
}
-CanThrowResult Sema::canThrow(const Stmt *S) {
+CanThrowResult SemaExceptionSpec::canThrow(const Stmt *S) {
// C++ [expr.unary.noexcept]p3:
// [Can throw] if in a potentially-evaluated context the expression would
// contain:
@@ -1153,13 +1157,13 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
CanThrowResult CT = canDynamicCastThrow(CE);
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, CE));
}
case Expr::CXXTypeidExprClass:
// - a potentially evaluated typeid expression applied to a glvalue
// expression whose type is a polymorphic class type
- return canTypeidThrow(*this, cast<CXXTypeidExpr>(S));
+ return canTypeidThrow(SemaRef, cast<CXXTypeidExpr>(S));
// - a potentially evaluated call to a function, member function, function
// pointer, or member function pointer that does not have a non-throwing
@@ -1175,10 +1179,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
CT = CT_Cannot;
else
- CT = canCalleeThrow(*this, CE, CE->getCalleeDecl());
+ CT = canCalleeThrow(SemaRef, CE, CE->getCalleeDecl());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, CE));
}
case Expr::CXXConstructExprClass:
@@ -1187,15 +1191,15 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// FIXME: Properly determine whether a variably-modified type can throw.
if (CE->getType()->isVariablyModifiedType())
return CT_Can;
- CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor());
+ CanThrowResult CT = canCalleeThrow(SemaRef, CE, CE->getConstructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, CE));
}
case Expr::CXXInheritedCtorInitExprClass: {
auto *ICIE = cast<CXXInheritedCtorInitExpr>(S);
- return canCalleeThrow(*this, ICIE, ICIE->getConstructor());
+ return canCalleeThrow(SemaRef, ICIE, ICIE->getConstructor());
}
case Expr::LambdaExprClass: {
@@ -1215,10 +1219,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
if (NE->isTypeDependent())
CT = CT_Dependent;
else
- CT = canCalleeThrow(*this, NE, NE->getOperatorNew());
+ CT = canCalleeThrow(SemaRef, NE, NE->getOperatorNew());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, NE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, NE));
}
case Expr::CXXDeleteExprClass: {
@@ -1228,27 +1232,27 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
- CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
+ CT = canCalleeThrow(SemaRef, DE, DE->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
const CXXDestructorDecl *DD = RD->getDestructor();
if (DD)
- CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
+ CT = mergeCanThrow(CT, canCalleeThrow(SemaRef, DE, DD));
}
if (CT == CT_Can)
return CT;
}
- return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, DE));
}
case Expr::CXXBindTemporaryExprClass: {
auto *BTE = cast<CXXBindTemporaryExpr>(S);
// The bound temporary has to be destroyed again, which might throw.
CanThrowResult CT =
- canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor());
+ canCalleeThrow(SemaRef, BTE, BTE->getTemporary()->getDestructor());
if (CT == CT_Can)
return CT;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, BTE));
}
case Expr::PseudoObjectExprClass: {
@@ -1300,7 +1304,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::ConvertVectorExprClass:
case Expr::VAArgExprClass:
case Expr::CXXParenListInitExprClass:
- return canSubStmtsThrow(*this, S);
+ return canSubStmtsThrow(SemaRef, S);
case Expr::CompoundLiteralExprClass:
case Expr::CXXConstCastExprClass:
@@ -1310,7 +1314,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// FIXME: Properly determine whether a variably-modified type can throw.
if (cast<Expr>(S)->getType()->isVariablyModifiedType())
return CT_Can;
- return canSubStmtsThrow(*this, S);
+ return canSubStmtsThrow(SemaRef, S);
// Some might be dependent for other reasons.
case Expr::ArraySubscriptExprClass:
@@ -1333,7 +1337,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
return CT_Can;
CanThrowResult CT =
cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot;
- return mergeCanThrow(CT, canSubStmtsThrow(*this, S));
+ return mergeCanThrow(CT, canSubStmtsThrow(SemaRef, S));
}
case Expr::CXXDefaultArgExprClass:
@@ -1530,13 +1534,13 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::SEHTryStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
- return canSubStmtsThrow(*this, S);
+ return canSubStmtsThrow(SemaRef, S);
case Stmt::DeclStmtClass: {
CanThrowResult CT = CT_Cannot;
for (const Decl *D : cast<DeclStmt>(S)->decls()) {
if (auto *VD = dyn_cast<VarDecl>(D))
- CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD));
+ CT = mergeCanThrow(CT, canVarDeclThrow(SemaRef, VD));
// FIXME: Properly determine whether a variably-modified type can throw.
if (auto *TND = dyn_cast<TypedefNameDecl>(D))
@@ -1560,7 +1564,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
// For 'if constexpr', consider only the non-discarded case.
// FIXME: We should add a DiscardedStmt marker to the AST.
- if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
+ if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(SemaRef.Context))
return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
CanThrowResult Then = canThrow(IS->getThen());
@@ -1581,7 +1585,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1);
if (!FinalHandler->getExceptionDecl())
return canThrow(FinalHandler->getHandlerBlock());
- return canSubStmtsThrow(*this, S);
+ return canSubStmtsThrow(SemaRef, S);
}
case Stmt::ObjCAtThrowStmtClass:
@@ -1615,4 +1619,230 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
llvm_unreachable("Bogus StmtClass");
}
+SemaExceptionSpec::SemaExceptionSpec(Sema &S) : SemaBase(S) {}
+
+void SemaExceptionSpec::CheckDelayedMemberExceptionSpecs() {
+ decltype(SemaExceptionSpec::DelayedOverridingExceptionSpecChecks) Overriding;
+ decltype(SemaExceptionSpec::DelayedEquivalentExceptionSpecChecks) Equivalent;
+
+ std::swap(Overriding, DelayedOverridingExceptionSpecChecks);
+ std::swap(Equivalent, DelayedEquivalentExceptionSpecChecks);
+
+ // Perform any deferred checking of exception specifications for virtual
+ // destructors.
+ for (auto &Check : Overriding)
+ CheckOverridingFunctionExceptionSpec(Check.first, Check.second);
+
+ // Perform any deferred checking of exception specifications for befriended
+ // special members.
+ for (auto &Check : Equivalent)
+ CheckEquivalentExceptionSpec(Check.second, Check.first);
+}
+
+/// RAII object to register a defaulted function as having its exception
+/// specification computed.
+struct ComputingExceptionSpec {
+ Sema &S;
+
+ ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc)
+ : S(S) {
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
+ Ctx.PointOfInstantiation = Loc;
+ Ctx.Entity = FD;
+ S.pushCodeSynthesisContext(Ctx);
+ }
+ ~ComputingExceptionSpec() {
+ S.popCodeSynthesisContext();
+ }
+};
+
+void SemaExceptionSpec::checkExceptionSpecification(
+ bool IsTopLevel, 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) {
+ Exceptions.reserve(DynamicExceptions.size());
+ for (unsigned ei = 0, ee = DynamicExceptions.size(); ei != ee; ++ei) {
+ // FIXME: Preserve type source info.
+ QualType ET = SemaRef.GetTypeFromParser(DynamicExceptions[ei]);
+
+ if (IsTopLevel) {
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(ET, Unexpanded);
+ if (!Unexpanded.empty()) {
+ SemaRef.DiagnoseUnexpandedParameterPacks(
+ DynamicExceptionRanges[ei].getBegin(), Sema::UPPC_ExceptionType,
+ Unexpanded);
+ continue;
+ }
+ }
+
+ // Check that the type is valid for an exception spec, and
+ // drop it if not.
+ if (!CheckSpecifiedExceptionType(ET, DynamicExceptionRanges[ei]))
+ Exceptions.push_back(ET);
+ }
+ ESI.Exceptions = Exceptions;
+ return;
+ }
+
+ if (isComputedNoexcept(EST)) {
+ assert((NoexceptExpr->isTypeDependent() ||
+ NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
+ SemaRef.Context.BoolTy) &&
+ "Parser should have made sure that the expression is boolean");
+ if (IsTopLevel && SemaRef.DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
+ ESI.Type = EST_BasicNoexcept;
+ return;
+ }
+
+ ESI.NoexceptExpr = NoexceptExpr;
+ return;
+ }
+}
+
+void SemaExceptionSpec::actOnDelayedExceptionSpecification(
+ Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange,
+ ArrayRef<ParsedType> DynamicExceptions,
+ ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr) {
+ if (!D)
+ return;
+
+ // Dig out the function we're referring to.
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ D = FTD->getTemplatedDecl();
+
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD)
+ return;
+
+ // Check the exception specification.
+ llvm::SmallVector<QualType, 4> Exceptions;
+ FunctionProtoType::ExceptionSpecInfo ESI;
+ checkExceptionSpecification(/*IsTopLevel=*/true, EST, DynamicExceptions,
+ DynamicExceptionRanges, NoexceptExpr, Exceptions,
+ ESI);
+
+ // Update the exception specification on the function type.
+ SemaRef.Context.adjustExceptionSpec(FD, ESI, /*AsWritten=*/true);
+
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (MD->isStatic())
+ SemaRef.checkThisInStaticMemberFunctionExceptionSpec(MD);
+
+ if (MD->isVirtual()) {
+ // Check overrides, which we previously had to delay.
+ for (const CXXMethodDecl *O : MD->overridden_methods())
+ CheckOverridingFunctionExceptionSpec(MD, O);
+ }
+ }
+}
+
+void SemaExceptionSpec::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
+ assert(getLangOpts().CPlusPlus11 &&
+ "adjusting dtor exception specs was introduced in c++11");
+
+ if (Destructor->isDependentContext())
+ return;
+
+ // C++11 [class.dtor]p3:
+ // A declaration of a destructor that does not have an exception-
+ // specification is implicitly considered to have the same exception-
+ // specification as an implicit declaration.
+ const auto *DtorType = Destructor->getType()->castAs<FunctionProtoType>();
+ if (DtorType->hasExceptionSpec())
+ return;
+
+ // Replace the destructor's type, building off the existing one. Fortunately,
+ // the only thing of interest in the destructor type is its extended info.
+ // The return and arguments are fixed.
+ FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = Destructor;
+ Destructor->setType(
+ SemaRef.Context.getFunctionType(SemaRef.Context.VoidTy, std::nullopt, EPI));
+
+ // FIXME: If the destructor has a body that could throw, and the newly created
+ // spec doesn't allow exceptions, we should emit a warning, because this
+ // change in behavior can break conforming C++03 programs at runtime.
+ // However, we don't have a body or an exception specification yet, so it
+ // needs to be done somewhere else.
+}
+
+void SemaExceptionSpec::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
+ const CXXRecordDecl *RD) {
+ for (const auto *I : RD->methods())
+ if (I->isVirtual() && !I->isPureVirtual())
+ ResolveExceptionSpec(Loc, I->getType()->castAs<FunctionProtoType>());
+}
+
+/// Merge the exception specifications of two variable declarations.
+///
+/// This is called when there's a redeclaration of a VarDecl. The function
+/// checks if the redeclaration might have an exception specification and
+/// validates compatibility and merges the specs if necessary.
+void SemaExceptionSpec::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
+ // Shortcut if exceptions are disabled.
+ if (!getLangOpts().CXXExceptions)
+ return;
+
+ assert(SemaRef.Context.hasSameType(New->getType(), Old->getType()) &&
+ "Should only be called if types are otherwise the same.");
+
+ QualType NewType = New->getType();
+ QualType OldType = Old->getType();
+
+ // We're only interested in pointers and references to functions, as well
+ // as pointers to member functions.
+ if (const ReferenceType *R = NewType->getAs<ReferenceType>()) {
+ NewType = R->getPointeeType();
+ OldType = OldType->castAs<ReferenceType>()->getPointeeType();
+ } else if (const PointerType *P = NewType->getAs<PointerType>()) {
+ NewType = P->getPointeeType();
+ OldType = OldType->castAs<PointerType>()->getPointeeType();
+ } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) {
+ NewType = M->getPointeeType();
+ OldType = OldType->castAs<MemberPointerType>()->getPointeeType();
+ }
+
+ if (!NewType->isFunctionProtoType())
+ return;
+
+ // There's lots of special cases for functions. For function pointers, system
+ // libraries are hopefully not as broken so that we don't need these
+ // workarounds.
+ if (CheckEquivalentExceptionSpec(
+ OldType->getAs<FunctionProtoType>(), Old->getLocation(),
+ NewType->getAs<FunctionProtoType>(), New->getLocation())) {
+ New->setInvalidDecl();
+ }
+}
+
+SemaExceptionSpec::ImplicitExceptionSpecification::ImplicitExceptionSpecification(Sema &Self)
+ : Self(&Self), ComputedEST(EST_BasicNoexcept) {
+ if (!Self.getLangOpts().CPlusPlus11)
+ ComputedEST = EST_DynamicNone;
+}
+
+FunctionProtoType::ExceptionSpecInfo SemaExceptionSpec::ImplicitExceptionSpecification::getExceptionSpec() const {
+ FunctionProtoType::ExceptionSpecInfo ESI;
+ ESI.Type = getExceptionSpecType();
+ if (ESI.Type == EST_Dynamic) {
+ ESI.Exceptions = Exceptions;
+ } else if (ESI.Type == EST_None) {
+ /// C++11 [except.spec]p14:
+ /// The exception-specification is noexcept(false) if the set of
+ /// potential exceptions of the special member function contains "any"
+ ESI.Type = EST_NoexceptFalse;
+ ESI.NoexceptExpr =
+ Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get();
+ }
+ return ESI;
+}
+
} // end namespace clang
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5ecfdee21f09d..29e467802134e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -50,6 +50,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
@@ -2311,7 +2312,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
// computation rather than computing a new body.
if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- if (const auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT))
+ if (const auto *NewFPT = ExceptionSpec().ResolveExceptionSpec(NameInfo.getLoc(), FPT))
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
}
}
@@ -18198,7 +18199,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// exception specification for a different reason.
const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>();
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
- ResolveExceptionSpec(Loc, FPT);
+ ExceptionSpec().ResolveExceptionSpec(Loc, FPT);
// A callee could be called by a host function then by a device function.
// If we only try recording once, we will miss recording the use on device
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e4601f7d6c47d..0107e6f5a93fe 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -39,6 +39,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaLambda.h"
#include "clang/Sema/SemaObjC.h"
@@ -4500,7 +4501,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case AA_Returning:
case AA_Sending:
case AA_Passing_CFAudited:
- if (CheckExceptionSpecCompatibility(From, ToType))
+ if (ExceptionSpec().CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
break;
@@ -4673,7 +4674,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
CXXCastPath BasePath;
if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
- if (CheckExceptionSpecCompatibility(From, ToType))
+ if (ExceptionSpec().CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
// We may not have been able to figure out what this member pointer resolved
@@ -4932,7 +4933,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Function_Conversion:
// If both sides are functions (or pointers/references to them), there could
// be incompatible exception declarations.
- if (CheckExceptionSpecCompatibility(From, ToType))
+ if (ExceptionSpec().CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
From = ImpCastExprToType(From, ToType, CK_NoOp, VK_PRValue,
@@ -5189,7 +5190,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
if((Operator->*IsDesiredOp)()) {
FoundOperator = true;
auto *CPT = Operator->getType()->castAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ CPT = Self.ExceptionSpec().ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT || !CPT->isNothrow())
return false;
}
@@ -5454,7 +5455,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return false;
if (UTT == UTT_IsNothrowDestructible) {
auto *CPT = Destructor->getType()->castAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ CPT = Self.ExceptionSpec().ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT || !CPT->isNothrow())
return false;
}
@@ -5542,7 +5543,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (Constructor->isCopyConstructor(FoundTQs)) {
FoundConstructor = true;
auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ CPT = Self.ExceptionSpec().ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
// TODO: check whether evaluating default arguments can throw.
@@ -5580,7 +5581,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
if (Constructor->isDefaultConstructor()) {
FoundConstructor = true;
auto *CPT = Constructor->getType()->castAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ CPT = Self.ExceptionSpec().ResolveExceptionSpec(KeyLoc, CPT);
if (!CPT)
return false;
// FIXME: check whether evaluating default arguments can throw.
@@ -5825,7 +5826,7 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind,
}
if (Kind == clang::TT_IsNothrowConstructible)
- return S.canThrow(Result.get()) == CT_Cannot;
+ return S.ExceptionSpec().canThrow(Result.get()) == CT_Cannot;
if (Kind == clang::TT_IsTriviallyConstructible) {
// Under Objective-C ARC and Weak, if the destination has non-trivial
@@ -6038,7 +6039,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
if (BTT != BTT_IsNothrowConvertible)
return true;
- return Self.canThrow(Result.get()) == CT_Cannot;
+ return Self.ExceptionSpec().canThrow(Result.get()) == CT_Cannot;
}
case BTT_IsAssignable:
@@ -6102,7 +6103,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
return true;
if (BTT == BTT_IsNothrowAssignable)
- return Self.canThrow(Result.get()) == CT_Cannot;
+ return Self.ExceptionSpec().canThrow(Result.get()) == CT_Cannot;
if (BTT == BTT_IsTriviallyAssignable) {
// Under Objective-C ARC and Weak, if the destination has non-trivial
@@ -8394,7 +8395,7 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context);
}
- CanThrowResult CanThrow = canThrow(Operand);
+ CanThrowResult CanThrow = ExceptionSpec().canThrow(Operand);
return new (Context)
CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen);
}
@@ -9317,7 +9318,7 @@ Sema::BuildExprRequirement(
if (E->isInstantiationDependent() || E->getType()->isPlaceholderType() ||
ReturnTypeRequirement.isDependent())
Status = concepts::ExprRequirement::SS_Dependent;
- else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can)
+ else if (NoexceptLoc.isValid() && ExceptionSpec().canThrow(E) == CanThrowResult::CT_Can)
Status = concepts::ExprRequirement::SS_NoexceptNotMet;
else if (ReturnTypeRequirement.isSubstitutionFailure())
Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure;
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 9aa60204bf29d..1843b28441c7c 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -20,6 +20,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
@@ -960,7 +961,7 @@ MemberExpr *Sema::BuildMemberExpr(
// selected member of a set of overloaded functions
if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
+ if (auto *NewFPT = ExceptionSpec().ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
}
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 353e911c5cc33..ce306021d505b 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -27,6 +27,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "llvm/ADT/APInt.h"
@@ -8865,7 +8866,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
- if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
+ if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
// We don't check for e.g. function pointers here, since address
@@ -8889,7 +8890,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
assert(CurInit.get()->isPRValue() && "not a temporary");
// Check exception specifications
- if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
+ if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
QualType MTETy = Step->Type;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 2eb25237a0de6..b2a43034866db 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -32,6 +32,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/Template.h"
@@ -82,7 +83,7 @@ static ExprResult CreateFunctionRefExpr(
S.MarkDeclRefReferenced(DRE, Base);
if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- S.ResolveExceptionSpec(Loc, FPT);
+ S.ExceptionSpec().ResolveExceptionSpec(Loc, FPT);
DRE->setType(Fn->getType());
}
}
@@ -12813,7 +12814,7 @@ static bool completeFunctionType(Sema &S, FunctionDecl *FD, SourceLocation Loc,
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
if (S.getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
- !S.ResolveExceptionSpec(Loc, FPT))
+ !S.ExceptionSpec().ResolveExceptionSpec(Loc, FPT))
return true;
return false;
@@ -13267,7 +13268,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
Fn = Resolver.getMatchingFunctionDecl();
assert(Fn);
if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
- ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT);
+ ExceptionSpec().ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT);
FoundResult = *Resolver.getMatchingFunctionAccessPair();
if (Complain) {
if (Resolver.IsStaticMemberFunctionFromBoundPointer())
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4937cce4621f0..9dd8fcd3c6ef4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -34,6 +34,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -10418,7 +10419,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// we have selected the primary template so we can check whether it matches.
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
- !ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
+ !ExceptionSpec().ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
return true;
FunctionTemplateSpecializationInfo *SpecInfo
@@ -11615,7 +11616,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::err_mismatched_exception_spec_explicit_instantiation;
if (getLangOpts().MicrosoftExt)
DiagID = diag::ext_mismatched_exception_spec_explicit_instantiation;
- bool Result = CheckEquivalentExceptionSpec(
+ bool Result = ExceptionSpec().CheckEquivalentExceptionSpec(
PDiag(DiagID) << Specialization->getType(),
PDiag(diag::note_explicit_instantiation_here),
Specialization->getType()->getAs<FunctionProtoType>(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 07626058c7977..3803bb272d1a7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -32,6 +32,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaConcept.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -3018,7 +3019,7 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
// On error, recover by dropping the exception specification.
ESI.Type = EST_None;
- UpdateExceptionSpec(New, ESI);
+ ExceptionSpec().UpdateExceptionSpec(New, ESI);
}
namespace {
@@ -3494,6 +3495,33 @@ namespace clang {
}
}
+class SavePendingParsedClassStateRAII {
+public:
+ SavePendingParsedClassStateRAII(Sema &S) : S(S) { swapSavedState(); }
+
+ ~SavePendingParsedClassStateRAII() {
+ assert(S.ExceptionSpec().DelayedOverridingExceptionSpecChecks.empty() &&
+ "there shouldn't be any pending delayed exception spec checks");
+ assert(S.ExceptionSpec().DelayedEquivalentExceptionSpecChecks.empty() &&
+ "there shouldn't be any pending delayed exception spec checsks");
+ swapSavedState();
+ }
+
+private:
+ Sema &S;
+ decltype(SemaExceptionSpec::DelayedOverridingExceptionSpecChecks)
+ SavedOverridingExceptionSpecChecks;
+ decltype(SemaExceptionSpec::DelayedEquivalentExceptionSpecChecks)
+ SavedEquivalentExceptionSpecChecks;
+
+ void swapSavedState() {
+ SavedOverridingExceptionSpecChecks.swap(
+ S.ExceptionSpec().DelayedOverridingExceptionSpecChecks);
+ SavedEquivalentExceptionSpecChecks.swap(
+ S.ExceptionSpec().DelayedEquivalentExceptionSpecChecks);
+ }
+};
+
/// Instantiate the definition of a class from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 381d79b2fcd46..6eed03a48a8c6 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -27,6 +27,7 @@
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
@@ -4685,14 +4686,14 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
if (Inst.isInvalid()) {
// We hit the instantiation depth limit. Clear the exception specification
// so that our callers don't have to cope with EST_Uninstantiated.
- UpdateExceptionSpec(Decl, EST_None);
+ ExceptionSpec().UpdateExceptionSpec(Decl, EST_None);
return;
}
if (Inst.isAlreadyInstantiating()) {
// This exception specification indirectly depends on itself. Reject.
// FIXME: Corresponding rule in the standard?
Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl;
- UpdateExceptionSpec(Decl, EST_None);
+ ExceptionSpec().UpdateExceptionSpec(Decl, EST_None);
return;
}
@@ -4712,7 +4713,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
// the template.
FunctionDecl *Template = Proto->getExceptionSpecTemplate();
if (addInstantiatedParametersToScope(Decl, Template, Scope, TemplateArgs)) {
- UpdateExceptionSpec(Decl, EST_None);
+ ExceptionSpec().UpdateExceptionSpec(Decl, EST_None);
return;
}
@@ -4817,7 +4818,7 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
return true;
if (isa<CXXDestructorDecl>(New) && SemaRef.getLangOpts().CPlusPlus11)
- SemaRef.AdjustDestructorExceptionSpec(cast<CXXDestructorDecl>(New));
+ SemaRef.ExceptionSpec().AdjustDestructorExceptionSpec(cast<CXXDestructorDecl>(New));
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten())
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ef0b6b701a52c..9d1abaed09651 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -34,6 +34,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaCUDA.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenMP.h"
@@ -2727,7 +2728,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
DeclarationName Entity) {
// Verify that we're not building a pointer to pointer to function with
// exception specification.
- if (CheckDistantExceptionSpec(T)) {
+ if (ExceptionSpec().CheckDistantExceptionSpec(T)) {
Diag(Loc, diag::err_distant_exception_spec);
return QualType();
}
@@ -4706,7 +4707,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -4742,7 +4743,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Reference: {
// Verify that we're not building a reference to pointer to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -4756,7 +4757,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Array: {
// Verify that we're not building an array of pointers to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -5256,7 +5257,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
NoexceptExpr = FTI.NoexceptExpr;
}
- S.checkExceptionSpecification(D.isFunctionDeclarationContext(),
+ S.ExceptionSpec().checkExceptionSpecification(D.isFunctionDeclarationContext(),
FTI.getExceptionSpecType(),
DynamicExceptions,
DynamicExceptionRanges,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 29444f0edc2ae..85ee495ea9fc0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -38,6 +38,7 @@
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/SemaExceptionSpec.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaObjC.h"
#include "clang/Sema/SemaOpenACC.h"
@@ -6309,7 +6310,7 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
ExceptionSpecificationType EST = ESI.Type;
NoexceptExpr =
- getSema().ActOnNoexceptSpec(NoexceptExpr.get(), EST);
+ getSema().ExceptionSpec().ActOnNoexceptSpec(NoexceptExpr.get(), EST);
if (NoexceptExpr.isInvalid())
return true;
@@ -6367,14 +6368,14 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
QualType U = getDerived().TransformType(PackExpansion->getPattern());
- if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc))
+ if (U.isNull() || SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
return true;
Exceptions.push_back(U);
}
} else {
QualType U = getDerived().TransformType(T);
- if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc))
+ if (U.isNull() || SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
return true;
if (T != U)
Changed = true;
>From 21d5282848b54ca55e8e9672c1f2007616cde702 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 18 May 2024 17:50:33 +0300
Subject: [PATCH 2/2] Run clang-format
---
clang/lib/Parse/ParseCXXInlineMethods.cpp | 10 +-
clang/lib/Parse/ParseDecl.cpp | 3 +-
clang/lib/Parse/ParseDeclCXX.cpp | 4 +-
clang/lib/Sema/AnalysisBasedWarnings.cpp | 5 +-
clang/lib/Sema/SemaCoroutine.cpp | 3 +-
clang/lib/Sema/SemaDeclCXX.cpp | 33 ++--
clang/lib/Sema/SemaExceptionSpec.cpp | 148 ++++++++++--------
clang/lib/Sema/SemaExpr.cpp | 3 +-
clang/lib/Sema/SemaExprCXX.cpp | 3 +-
clang/lib/Sema/SemaExprMember.cpp | 3 +-
clang/lib/Sema/SemaInit.cpp | 6 +-
clang/lib/Sema/SemaTemplate.cpp | 3 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 4 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 +-
clang/lib/Sema/SemaType.cpp | 20 +--
clang/lib/Sema/TreeTransform.h | 6 +-
16 files changed, 142 insertions(+), 115 deletions(-)
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index ccff9db1238a0..7623ea1d1492e 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -540,12 +540,10 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
// Attach the exception-specification to the method.
- Actions.ExceptionSpec().actOnDelayedExceptionSpecification(LM.Method, EST,
- SpecificationRange,
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr.isUsable()?
- NoexceptExpr.get() : nullptr);
+ Actions.ExceptionSpec().actOnDelayedExceptionSpecification(
+ LM.Method, EST, SpecificationRange, DynamicExceptions,
+ DynamicExceptionRanges,
+ NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr);
// There could be leftover tokens (e.g. because of an error).
// Skip through until we reach the original token position.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index b1c4f68ac4901..9870e43f5b1fe 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7532,7 +7532,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// delayed (even if this is a friend declaration).
bool Delayed = D.getContext() == DeclaratorContext::Member &&
D.isFunctionDeclaratorAFunctionDeclaration();
- if (Delayed && Actions.ExceptionSpec().isLibstdcxxEagerExceptionSpecHack(D) &&
+ if (Delayed &&
+ Actions.ExceptionSpec().isLibstdcxxEagerExceptionSpecHack(D) &&
GetLookAheadToken(0).is(tok::kw_noexcept) &&
GetLookAheadToken(1).is(tok::l_paren) &&
GetLookAheadToken(2).is(tok::kw_noexcept) &&
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index e51252cdeddb3..8a44ec41cd07e 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -4139,8 +4139,8 @@ ExceptionSpecificationType Parser::tryParseExceptionSpecification(
T.consumeClose();
if (!NoexceptExpr.isInvalid()) {
- NoexceptExpr =
- Actions.ExceptionSpec().ActOnNoexceptSpec(NoexceptExpr.get(), NoexceptType);
+ NoexceptExpr = Actions.ExceptionSpec().ActOnNoexceptSpec(
+ NoexceptExpr.get(), NoexceptType);
NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation());
} else {
NoexceptType = EST_BasicNoexcept;
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 3e1ec7a378acd..1226cfe7ed10d 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -330,9 +330,10 @@ static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock,
if (auto *Catch =
dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) {
QualType Caught = Catch->getCaughtType();
- if (Caught.isNull() || // catch (...) catches everything
+ if (Caught.isNull() || // catch (...) catches everything
!E->getSubExpr() || // throw; is considered cuaght by any handler
- S.ExceptionSpec().handlerCanCatch(Caught, E->getSubExpr()->getType()))
+ S.ExceptionSpec().handlerCanCatch(Caught,
+ E->getSubExpr()->getType()))
// Exception doesn't escape via this path.
break;
} else {
diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp
index 41eb97a391857..2113ac7681090 100644
--- a/clang/lib/Sema/SemaCoroutine.cpp
+++ b/clang/lib/Sema/SemaCoroutine.cpp
@@ -615,7 +615,8 @@ static void checkNoThrow(Sema &S, const Stmt *E,
auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) {
// In the case of dtor, the call to dtor is implicit and hence we should
// pass nullptr to canCalleeThrow.
- if (SemaExceptionSpec::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) {
+ if (SemaExceptionSpec::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E),
+ D)) {
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// co_await promise.final_suspend() could end up calling
// __builtin_coro_resume for symmetric transfer if await_suspend()
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 8e7f07d7efedf..aead70268d470 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -9180,7 +9180,8 @@ void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD,
// The exception specification is needed because we are defining the
// function. Note that this will reuse the body we just built.
- ExceptionSpec().ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ UseLoc, FD->getType()->castAs<FunctionProtoType>());
if (ASTMutationListener *L = getASTMutationListener())
L->CompletedImplicitDefinition(FD);
@@ -14053,8 +14054,8 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- Constructor->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation, Constructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
// Add a context note for diagnostics produced after this point.
@@ -14193,8 +14194,8 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- Constructor->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation, Constructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
// Add a context note for diagnostics produced after this point.
@@ -14342,8 +14343,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- Destructor->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation, Destructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
// Add a context note for diagnostics produced after this point.
@@ -15014,8 +15015,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- CopyAssignOperator->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation,
+ CopyAssignOperator->getType()->castAs<FunctionProtoType>());
// Add a context note for diagnostics produced after this point.
Scope.addContextNote(CurrentLocation);
@@ -15411,8 +15413,9 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- MoveAssignOperator->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation,
+ MoveAssignOperator->getType()->castAs<FunctionProtoType>());
// Add a context note for diagnostics produced after this point.
Scope.addContextNote(CurrentLocation);
@@ -15724,8 +15727,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- CopyConstructor->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation, CopyConstructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
// Add a context note for diagnostics produced after this point.
@@ -15863,8 +15866,8 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
// The exception specification is needed because we are defining the
// function.
- ExceptionSpec().ResolveExceptionSpec(CurrentLocation,
- MoveConstructor->getType()->castAs<FunctionProtoType>());
+ ExceptionSpec().ResolveExceptionSpec(
+ CurrentLocation, MoveConstructor->getType()->castAs<FunctionProtoType>());
MarkVTableUsed(CurrentLocation, ClassDecl);
// Add a context note for diagnostics produced after this point.
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index d8548ba8cbc79..a276b9ad3917f 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -82,8 +82,9 @@ bool SemaExceptionSpec::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
.Default(false);
}
-ExprResult SemaExceptionSpec::ActOnNoexceptSpec(Expr *NoexceptExpr,
- ExceptionSpecificationType &EST) {
+ExprResult
+SemaExceptionSpec::ActOnNoexceptSpec(Expr *NoexceptExpr,
+ ExceptionSpecificationType &EST) {
ASTContext &Context = getASTContext();
if (NoexceptExpr->isTypeDependent() ||
NoexceptExpr->containsUnexpandedParameterPack()) {
@@ -121,7 +122,8 @@ ExprResult SemaExceptionSpec::ActOnNoexceptSpec(Expr *NoexceptExpr,
///
/// \param[in,out] T The exception type. This will be decayed to a pointer type
/// when the input is an array or a function type.
-bool SemaExceptionSpec::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
+bool SemaExceptionSpec::CheckSpecifiedExceptionType(QualType &T,
+ SourceRange Range) {
// C++11 [except.spec]p2:
// A type cv T, "array of T", or "function returning T" denoted
// in an exception-specification is adjusted to type T, "pointer to T", or
@@ -172,7 +174,8 @@ bool SemaExceptionSpec::CheckSpecifiedExceptionType(QualType &T, SourceRange Ran
}
if (!(PointeeT->isRecordType() &&
PointeeT->castAs<RecordType>()->isBeingDefined()) &&
- SemaRef.RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
+ SemaRef.RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind,
+ Range))
return ReturnValueOnError;
// WebAssembly reference types can't be used in exception specifications.
@@ -216,7 +219,8 @@ bool SemaExceptionSpec::CheckDistantExceptionSpec(QualType T) {
}
const FunctionProtoType *
-SemaExceptionSpec::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
+SemaExceptionSpec::ResolveExceptionSpec(SourceLocation Loc,
+ const FunctionProtoType *FPT) {
if (FPT->getExceptionSpecType() == EST_Unparsed) {
Diag(Loc, diag::err_exception_spec_not_parsed);
return nullptr;
@@ -248,9 +252,8 @@ SemaExceptionSpec::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoT
return Proto;
}
-void
-SemaExceptionSpec::UpdateExceptionSpec(FunctionDecl *FD,
- const FunctionProtoType::ExceptionSpecInfo &ESI) {
+void SemaExceptionSpec::UpdateExceptionSpec(
+ FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI) {
// If we've fully resolved the exception specification, notify listeners.
if (!isUnresolvedExceptionSpec(ESI.Type))
if (auto *Listener = SemaRef.getASTMutationListener())
@@ -299,7 +302,8 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
return !Ty->hasExceptionSpec();
}
-bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
+bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old,
+ FunctionDecl *New) {
// Just completely ignore this under -fno-exceptions prior to C++17.
// In C++17 onwards, the exception specification is part of the type and
// we will diagnose mismatches anyway, so it's better to check for them here.
@@ -329,11 +333,12 @@ bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old, Function
// Check the types as written: they must match before any exception
// specification adjustment is applied.
if (!CheckEquivalentExceptionSpecImpl(
- SemaRef, SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::note_previous_declaration),
- Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
- &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
- /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
+ SemaRef, SemaRef.PDiag(DiagID),
+ SemaRef.PDiag(diag::note_previous_declaration),
+ Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
+ New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
+ &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
+ /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
// C++11 [except.spec]p4 [DR1492]:
// If a declaration of a function has an implicit
// exception-specification, other declarations of the function shall
@@ -365,7 +370,8 @@ bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old, Function
// Likewise if the old function is a builtin.
if (MissingEmptyExceptionSpecification &&
(Old->getLocation().isInvalid() ||
- SemaRef.Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
+ SemaRef.Context.getSourceManager().isInSystemHeader(
+ Old->getLocation()) ||
Old->getBuiltinID()) &&
Old->isExternC()) {
New->setType(SemaRef.Context.getFunctionType(
@@ -455,7 +461,8 @@ bool SemaExceptionSpec::CheckEquivalentExceptionSpec(FunctionDecl *Old, Function
case EST_NoexceptTrue:
OS << "noexcept(";
assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
- OldProto->getNoexceptExpr()->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+ OldProto->getNoexceptExpr()->printPretty(OS, nullptr,
+ SemaRef.getPrintingPolicy());
OS << ")";
break;
case EST_NoThrow:
@@ -508,8 +515,8 @@ bool SemaExceptionSpec::CheckEquivalentExceptionSpec(
if (getLangOpts().MSVCCompat)
DiagID = diag::ext_mismatched_exception_spec;
bool Result = CheckEquivalentExceptionSpecImpl(
- SemaRef, SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::note_previous_declaration),
- Old, OldLoc, New, NewLoc);
+ SemaRef, SemaRef.PDiag(DiagID),
+ SemaRef.PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc);
// In Microsoft mode, mismatching exception specifications just cause a warning.
if (getLangOpts().MSVCCompat)
@@ -674,19 +681,18 @@ static bool CheckEquivalentExceptionSpecImpl(
return true;
}
-bool SemaExceptionSpec::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
- const PartialDiagnostic &NoteID,
- const FunctionProtoType *Old,
- SourceLocation OldLoc,
- const FunctionProtoType *New,
- SourceLocation NewLoc) {
+bool SemaExceptionSpec::CheckEquivalentExceptionSpec(
+ const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
+ const FunctionProtoType *Old, SourceLocation OldLoc,
+ const FunctionProtoType *New, SourceLocation NewLoc) {
if (!getLangOpts().CXXExceptions)
return false;
return CheckEquivalentExceptionSpecImpl(SemaRef, DiagID, NoteID, Old, OldLoc,
New, NewLoc);
}
-bool SemaExceptionSpec::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
+bool SemaExceptionSpec::handlerCanCatch(QualType HandlerType,
+ QualType ExceptionType) {
ASTContext &Context = getASTContext();
// [except.handle]p3:
// A handler is a match for an exception object of type E if:
@@ -722,7 +728,7 @@ bool SemaExceptionSpec::handlerCanCatch(QualType HandlerType, QualType Exception
// FIXME: Should we treat the exception as catchable if a lifetime
// conversion is required?
if (SemaRef.IsQualificationConversion(ExceptionType, HandlerType, false,
- LifetimeConv) ||
+ LifetimeConv) ||
SemaRef.IsFunctionConversion(ExceptionType, HandlerType, Result))
return true;
@@ -751,18 +757,21 @@ bool SemaExceptionSpec::handlerCanCatch(QualType HandlerType, QualType Exception
return false;
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
- if (!SemaRef.IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||
+ if (!SemaRef.IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType,
+ Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(HandlerType)))
return false;
// Do this check from a context without privileges.
- switch (SemaRef.CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,
- Paths.front(),
- /*Diagnostic*/ 0,
- /*ForceCheck*/ true,
- /*ForceUnprivileged*/ true)) {
- case Sema::AR_accessible: return true;
- case Sema::AR_inaccessible: return false;
+ switch (SemaRef.CheckBaseClassAccess(SourceLocation(), HandlerType,
+ ExceptionType, Paths.front(),
+ /*Diagnostic*/ 0,
+ /*ForceCheck*/ true,
+ /*ForceUnprivileged*/ true)) {
+ case Sema::AR_accessible:
+ return true;
+ case Sema::AR_inaccessible:
+ return false;
case Sema::AR_dependent:
llvm_unreachable("access check dependent for unprivileged context");
case Sema::AR_delayed:
@@ -890,8 +899,8 @@ CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
if (!SFunc)
return false;
- return S.ExceptionSpec().CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
- SFunc, SourceLoc);
+ return S.ExceptionSpec().CheckEquivalentExceptionSpec(
+ DiagID, NoteID, TFunc, TargetLoc, SFunc, SourceLoc);
}
/// CheckParamExceptionSpec - Check if the parameter and return types of the
@@ -906,10 +915,9 @@ bool SemaExceptionSpec::CheckParamExceptionSpec(
bool SkipSourceFirstParameter, SourceLocation SourceLoc) {
auto RetDiag = DiagID;
RetDiag << 0;
- if (CheckSpecForTypesEquivalent(
- SemaRef, RetDiag, SemaRef.PDiag(),
- Target->getReturnType(), TargetLoc, Source->getReturnType(),
- SourceLoc))
+ if (CheckSpecForTypesEquivalent(SemaRef, RetDiag, SemaRef.PDiag(),
+ Target->getReturnType(), TargetLoc,
+ Source->getReturnType(), SourceLoc))
return true;
// We shouldn't even be testing this unless the arguments are otherwise
@@ -930,7 +938,8 @@ bool SemaExceptionSpec::CheckParamExceptionSpec(
return false;
}
-bool SemaExceptionSpec::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
+bool SemaExceptionSpec::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);
@@ -964,15 +973,16 @@ bool SemaExceptionSpec::CheckExceptionSpecCompatibility(Expr *From, QualType ToT
// void (*q)(void (*) throw(int)) = p;
// }
// ... because it might be instantiated with T=int.
- return CheckExceptionSpecSubset(SemaRef.PDiag(DiagID), SemaRef.PDiag(NestedDiagID), SemaRef.PDiag(),
+ return CheckExceptionSpecSubset(SemaRef.PDiag(DiagID),
+ SemaRef.PDiag(NestedDiagID), SemaRef.PDiag(),
SemaRef.PDiag(), ToFunc, 0,
From->getSourceRange().getBegin(), FromFunc,
0, SourceLocation()) &&
!getLangOpts().CPlusPlus17;
}
-bool SemaExceptionSpec::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
- const CXXMethodDecl *Old) {
+bool SemaExceptionSpec::CheckOverridingFunctionExceptionSpec(
+ const CXXMethodDecl *New, const CXXMethodDecl *Old) {
// If the new exception specification hasn't been parsed yet, skip the check.
// We'll get called again once it's been parsed.
if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
@@ -997,7 +1007,8 @@ bool SemaExceptionSpec::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl
if (getLangOpts().MSVCCompat)
DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(
- SemaRef.PDiag(DiagID), SemaRef.PDiag(diag::err_deep_exception_specs_differ),
+ SemaRef.PDiag(DiagID),
+ SemaRef.PDiag(diag::err_deep_exception_specs_differ),
SemaRef.PDiag(diag::note_overridden_virtual_function),
SemaRef.PDiag(diag::ext_override_exception_spec),
Old->getType()->castAs<FunctionProtoType>(),
@@ -1018,8 +1029,9 @@ static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
return R;
}
-CanThrowResult SemaExceptionSpec::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
- SourceLocation Loc) {
+CanThrowResult SemaExceptionSpec::canCalleeThrow(Sema &S, const Expr *E,
+ const Decl *D,
+ SourceLocation Loc) {
// As an extension, we assume that __attribute__((nothrow)) functions don't
// throw.
if (isa_and_nonnull<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
@@ -1066,7 +1078,8 @@ CanThrowResult SemaExceptionSpec::canCalleeThrow(Sema &S, const Expr *E, const D
return CT_Can;
if (Loc.isValid() || (Loc.isInvalid() && E))
- FT = S.ExceptionSpec().ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
+ FT = S.ExceptionSpec().ResolveExceptionSpec(
+ Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
if (!FT)
return CT_Can;
@@ -1086,8 +1099,8 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
if (auto *RD =
VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
if (auto *Dtor = RD->getDestructor()) {
- CT = mergeCanThrow(
- CT, SemaExceptionSpec::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
+ CT = mergeCanThrow(CT, SemaExceptionSpec::canCalleeThrow(
+ Self, nullptr, Dtor, VD->getLocation()));
}
}
}
@@ -1564,7 +1577,8 @@ CanThrowResult SemaExceptionSpec::canThrow(const Stmt *S) {
// For 'if constexpr', consider only the non-discarded case.
// FIXME: We should add a DiscardedStmt marker to the AST.
- if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(SemaRef.Context))
+ if (std::optional<const Stmt *> Case =
+ IS->getNondiscardedCase(SemaRef.Context))
return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
CanThrowResult Then = canThrow(IS->getThen());
@@ -1644,17 +1658,14 @@ void SemaExceptionSpec::CheckDelayedMemberExceptionSpecs() {
struct ComputingExceptionSpec {
Sema &S;
- ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc)
- : S(S) {
+ ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc) : S(S) {
Sema::CodeSynthesisContext Ctx;
Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation;
Ctx.PointOfInstantiation = Loc;
Ctx.Entity = FD;
S.pushCodeSynthesisContext(Ctx);
}
- ~ComputingExceptionSpec() {
- S.popCodeSynthesisContext();
- }
+ ~ComputingExceptionSpec() { S.popCodeSynthesisContext(); }
};
void SemaExceptionSpec::checkExceptionSpecification(
@@ -1694,7 +1705,7 @@ void SemaExceptionSpec::checkExceptionSpecification(
if (isComputedNoexcept(EST)) {
assert((NoexceptExpr->isTypeDependent() ||
NoexceptExpr->getType()->getCanonicalTypeUnqualified() ==
- SemaRef.Context.BoolTy) &&
+ SemaRef.Context.BoolTy) &&
"Parser should have made sure that the expression is boolean");
if (IsTopLevel && SemaRef.DiagnoseUnexpandedParameterPack(NoexceptExpr)) {
ESI.Type = EST_BasicNoexcept;
@@ -1743,7 +1754,8 @@ void SemaExceptionSpec::actOnDelayedExceptionSpecification(
}
}
-void SemaExceptionSpec::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) {
+void SemaExceptionSpec::AdjustDestructorExceptionSpec(
+ CXXDestructorDecl *Destructor) {
assert(getLangOpts().CPlusPlus11 &&
"adjusting dtor exception specs was introduced in c++11");
@@ -1764,8 +1776,8 @@ void SemaExceptionSpec::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destruc
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpec.Type = EST_Unevaluated;
EPI.ExceptionSpec.SourceDecl = Destructor;
- Destructor->setType(
- SemaRef.Context.getFunctionType(SemaRef.Context.VoidTy, std::nullopt, EPI));
+ Destructor->setType(SemaRef.Context.getFunctionType(SemaRef.Context.VoidTy,
+ std::nullopt, EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -1774,8 +1786,8 @@ void SemaExceptionSpec::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destruc
// needs to be done somewhere else.
}
-void SemaExceptionSpec::MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc,
- const CXXRecordDecl *RD) {
+void SemaExceptionSpec::MarkVirtualMemberExceptionSpecsNeeded(
+ SourceLocation Loc, const CXXRecordDecl *RD) {
for (const auto *I : RD->methods())
if (I->isVirtual() && !I->isPureVirtual())
ResolveExceptionSpec(Loc, I->getType()->castAs<FunctionProtoType>());
@@ -1817,19 +1829,21 @@ void SemaExceptionSpec::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
// libraries are hopefully not as broken so that we don't need these
// workarounds.
if (CheckEquivalentExceptionSpec(
- OldType->getAs<FunctionProtoType>(), Old->getLocation(),
- NewType->getAs<FunctionProtoType>(), New->getLocation())) {
+ OldType->getAs<FunctionProtoType>(), Old->getLocation(),
+ NewType->getAs<FunctionProtoType>(), New->getLocation())) {
New->setInvalidDecl();
}
}
-SemaExceptionSpec::ImplicitExceptionSpecification::ImplicitExceptionSpecification(Sema &Self)
- : Self(&Self), ComputedEST(EST_BasicNoexcept) {
+SemaExceptionSpec::ImplicitExceptionSpecification::
+ ImplicitExceptionSpecification(Sema &Self)
+ : Self(&Self), ComputedEST(EST_BasicNoexcept) {
if (!Self.getLangOpts().CPlusPlus11)
ComputedEST = EST_DynamicNone;
}
-FunctionProtoType::ExceptionSpecInfo SemaExceptionSpec::ImplicitExceptionSpecification::getExceptionSpec() const {
+FunctionProtoType::ExceptionSpecInfo
+SemaExceptionSpec::ImplicitExceptionSpecification::getExceptionSpec() const {
FunctionProtoType::ExceptionSpecInfo ESI;
ESI.Type = getExceptionSpecType();
if (ESI.Type == EST_Dynamic) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 29e467802134e..b6cfc4106fe06 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2312,7 +2312,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
// computation rather than computing a new body.
if (const auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- if (const auto *NewFPT = ExceptionSpec().ResolveExceptionSpec(NameInfo.getLoc(), FPT))
+ if (const auto *NewFPT =
+ ExceptionSpec().ResolveExceptionSpec(NameInfo.getLoc(), FPT))
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
}
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 0107e6f5a93fe..8ef346b4c3d63 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9318,7 +9318,8 @@ Sema::BuildExprRequirement(
if (E->isInstantiationDependent() || E->getType()->isPlaceholderType() ||
ReturnTypeRequirement.isDependent())
Status = concepts::ExprRequirement::SS_Dependent;
- else if (NoexceptLoc.isValid() && ExceptionSpec().canThrow(E) == CanThrowResult::CT_Can)
+ else if (NoexceptLoc.isValid() &&
+ ExceptionSpec().canThrow(E) == CanThrowResult::CT_Can)
Status = concepts::ExprRequirement::SS_NoexceptNotMet;
else if (ReturnTypeRequirement.isSubstitutionFailure())
Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure;
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 1843b28441c7c..e97a7007af53f 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -961,7 +961,8 @@ MemberExpr *Sema::BuildMemberExpr(
// selected member of a set of overloaded functions
if (auto *FPT = Ty->getAs<FunctionProtoType>()) {
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
- if (auto *NewFPT = ExceptionSpec().ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT))
+ if (auto *NewFPT = ExceptionSpec().ResolveExceptionSpec(
+ MemberNameInfo.getLoc(), FPT))
E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers()));
}
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index ce306021d505b..a4bd5ca1981b7 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -8866,7 +8866,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
// Reference binding does not have any corresponding ASTs.
// Check exception specifications
- if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(), DestType))
+ if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(),
+ DestType))
return ExprError();
// We don't check for e.g. function pointers here, since address
@@ -8890,7 +8891,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
assert(CurInit.get()->isPRValue() && "not a temporary");
// Check exception specifications
- if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(), DestType))
+ if (S.ExceptionSpec().CheckExceptionSpecCompatibility(CurInit.get(),
+ DestType))
return ExprError();
QualType MTETy = Step->Type;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9dd8fcd3c6ef4..db22530177fa7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -10419,7 +10419,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
// we have selected the primary template so we can check whether it matches.
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
- !ExceptionSpec().ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
+ !ExceptionSpec().ResolveExceptionSpec(FD->getLocation(),
+ SpecializationFPT))
return true;
FunctionTemplateSpecializationInfo *SpecInfo
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3803bb272d1a7..9af79d25e4266 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3501,9 +3501,9 @@ class SavePendingParsedClassStateRAII {
~SavePendingParsedClassStateRAII() {
assert(S.ExceptionSpec().DelayedOverridingExceptionSpecChecks.empty() &&
- "there shouldn't be any pending delayed exception spec checks");
+ "there shouldn't be any pending delayed exception spec checks");
assert(S.ExceptionSpec().DelayedEquivalentExceptionSpecChecks.empty() &&
- "there shouldn't be any pending delayed exception spec checsks");
+ "there shouldn't be any pending delayed exception spec checsks");
swapSavedState();
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6eed03a48a8c6..53df6964d4b37 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4818,7 +4818,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
return true;
if (isa<CXXDestructorDecl>(New) && SemaRef.getLangOpts().CPlusPlus11)
- SemaRef.ExceptionSpec().AdjustDestructorExceptionSpec(cast<CXXDestructorDecl>(New));
+ SemaRef.ExceptionSpec().AdjustDestructorExceptionSpec(
+ cast<CXXDestructorDecl>(New));
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten())
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 9d1abaed09651..55a5f90acf59e 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -4707,7 +4707,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus &&
+ S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -4743,7 +4744,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Reference: {
// Verify that we're not building a reference to pointer to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus &&
+ S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -4757,7 +4759,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Array: {
// Verify that we're not building an array of pointers to function with
// exception specification.
- if (LangOpts.CPlusPlus && S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
+ if (LangOpts.CPlusPlus &&
+ S.ExceptionSpec().CheckDistantExceptionSpec(T)) {
S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec);
D.setInvalidType(true);
// Build the type anyway.
@@ -5257,13 +5260,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
NoexceptExpr = FTI.NoexceptExpr;
}
- S.ExceptionSpec().checkExceptionSpecification(D.isFunctionDeclarationContext(),
- FTI.getExceptionSpecType(),
- DynamicExceptions,
- DynamicExceptionRanges,
- NoexceptExpr,
- Exceptions,
- EPI.ExceptionSpec);
+ S.ExceptionSpec().checkExceptionSpecification(
+ D.isFunctionDeclarationContext(), FTI.getExceptionSpecType(),
+ DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, Exceptions,
+ EPI.ExceptionSpec);
// FIXME: Set address space from attrs for C++ mode here.
// OpenCLCPlusPlus: A class member function has an address space.
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 85ee495ea9fc0..e86c77c9b7330 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -6368,14 +6368,16 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
QualType U = getDerived().TransformType(PackExpansion->getPattern());
- if (U.isNull() || SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
+ if (U.isNull() ||
+ SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
return true;
Exceptions.push_back(U);
}
} else {
QualType U = getDerived().TransformType(T);
- if (U.isNull() || SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
+ if (U.isNull() ||
+ SemaRef.ExceptionSpec().CheckSpecifiedExceptionType(U, Loc))
return true;
if (T != U)
Changed = true;
More information about the cfe-commits
mailing list