[libcxx-commits] [clang] [libcxx] pr branch (PR #94669)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jun 6 12:35:00 PDT 2024


https://github.com/EricWF created https://github.com/llvm/llvm-project/pull/94669

- Add contracts keywords
- Add parsing for pre contracts up to Expr
- add contracts builtin prototypes
- add contracts to FunctionDecl
- propagate contracts up to emit function
- add constexpr contract failure
- add constexpr precontract evaluation
- runtime contract violation flag now
- add post contracts
- switch back to CCEDiag
- use abort instead of terminate


>From ffbe0b21314c9036be0e05ffb0da8e04490fddb8 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Thu, 30 May 2024 22:03:31 +0200
Subject: [PATCH 01/11] Add contracts keywords

---
 clang/include/clang/Basic/LangOptions.def | 1 +
 clang/include/clang/Basic/TokenKinds.def  | 8 ++++++++
 clang/lib/Basic/IdentifierTable.cpp       | 5 ++++-
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 4061451b2150a..121e9e9459ca7 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -156,6 +156,7 @@ LANGOPT(NoBuiltin         , 1, 0, "disable builtin functions")
 LANGOPT(NoMathBuiltin     , 1, 0, "disable math builtin functions")
 LANGOPT(GNUAsm            , 1, 1, "GNU-style inline assembly")
 LANGOPT(Coroutines        , 1, 0, "C++20 coroutines")
+LANGOPT(Contracts         , 1, 1, "C++2c contracts")
 LANGOPT(CoroAlignedAllocation, 1, 0, "prefer Aligned Allocation according to P2014 Option 2")
 LANGOPT(DllExportInlines  , 1, 1, "dllexported classes dllexport inline methods")
 LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments")
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index b5a0e9df9f7ae..beef4a993014e 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -40,6 +40,9 @@
 #ifndef MODULES_KEYWORD
 #define MODULES_KEYWORD(X) KEYWORD(X,KEYMODULES)
 #endif
+#ifndef CONTRACTS_KEYWORD
+#define CONTRACTS_KEYWORD(X) KEYWORD(X,KEYCONTRACTS)
+#endif
 #ifndef TYPE_TRAIT
 #define TYPE_TRAIT(N,I,K) KEYWORD(I,K)
 #endif
@@ -280,6 +283,7 @@ PUNCTUATOR(caretcaret,            "^^")
 //                which are heavily based on AltiVec
 //   KEYBORLAND - This is a keyword if Borland extensions are enabled
 //   KEYCOROUTINES - This is a keyword if support for C++ coroutines is enabled
+//   KEYCONTRACTS - This is a keyword if support for C++ contracts is enabled
 //   BOOLSUPPORT - This is a keyword if 'bool' is a built-in type
 //   HALFSUPPORT - This is a keyword if 'half' is a built-in type
 //   WCHARSUPPORT - This is a keyword if 'wchar_t' is a built-in type
@@ -415,6 +419,10 @@ CXX20_KEYWORD(constinit             , 0)
 CXX20_KEYWORD(concept               , 0)
 CXX20_KEYWORD(requires              , 0)
 
+// C++ contracts keywords
+CONTRACTS_KEYWORD(pre)
+CONTRACTS_KEYWORD(post)
+
 // Not a CXX20_KEYWORD because it is disabled by -fno-char8_t.
 KEYWORD(char8_t                     , CHAR8SUPPORT)
 
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index feea84544d62f..3070bba7c3f93 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -109,7 +109,8 @@ namespace {
     KEYCUDA       = 0x1000000,
     KEYHLSL       = 0x2000000,
     KEYFIXEDPOINT = 0x4000000,
-    KEYMAX        = KEYFIXEDPOINT, // The maximum key
+    KEYCONTRACTS  = 0x8000000,
+    KEYMAX        = KEYCONTRACTS, // The maximum key
     KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20,
     KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 &
              ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude.
@@ -189,6 +190,8 @@ static KeywordStatus getKeywordStatusHelper(const LangOptions &LangOpts,
     return LangOpts.ZVector ? KS_Enabled : KS_Unknown;
   case KEYCOROUTINES:
     return LangOpts.Coroutines ? KS_Enabled : KS_Unknown;
+  case KEYCONTRACTS:
+    return LangOpts.Contracts ? KS_Enabled : KS_Unknown;
   case KEYMODULES:
     return KS_Unknown;
   case KEYOPENCLCXX:

>From 7fbad4b9b70b6dc8f087c32f6085d1b8229b0b37 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Thu, 30 May 2024 22:03:50 +0200
Subject: [PATCH 02/11] Add parsing for pre contracts up to Expr

---
 clang/include/clang/Parse/Parser.h  |   5 ++
 clang/include/clang/Sema/DeclSpec.h |  28 ++++++-
 clang/lib/Parse/ParseDecl.cpp       |  16 ++++
 clang/lib/Parse/ParseDeclCXX.cpp    | 120 ++++++++++++++++++++++++++++
 clang/lib/Parse/ParseExprCXX.cpp    |  10 ++-
 5 files changed, 177 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d054b8cf0d240..d01a7bc3fb0b5 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2103,6 +2103,11 @@ class Parser : public CodeCompletionHandler {
   ExprResult ParseRequiresExpression();
   void ParseTrailingRequiresClause(Declarator &D);
 
+  //===--------------------------------------------------------------------===//
+  // C++ Contracts
+  void ParsePreContract(Declarator &DeclaratorInfo);
+  void ParsePostContract(Declarator &DeclaratorInfo);
+
   //===--------------------------------------------------------------------===//
   // C99 6.7.8: Initialization.
 
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 23bc780e04979..d8c26f69ceab1 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1970,6 +1970,12 @@ class Declarator {
   /// requires-clause, or null if no such clause was specified.
   Expr *TrailingRequiresClause;
 
+  /// \brief All pre contracts specified by the function declaration
+  SmallVector<Expr*> PreContracts;
+
+  /// \brief All post contracts specified by the function declaration
+  SmallVector<Expr*> PostContracts;
+
   /// If this declarator declares a template, its template parameter lists.
   ArrayRef<TemplateParameterList *> TemplateParameterLists;
 
@@ -2628,7 +2634,7 @@ class Declarator {
 
     SetRangeEnd(TRC->getEndLoc());
   }
-
+  
   /// \brief Sets a trailing requires clause for this declarator.
   Expr *getTrailingRequiresClause() {
     return TrailingRequiresClause;
@@ -2640,6 +2646,26 @@ class Declarator {
     return TrailingRequiresClause != nullptr;
   }
 
+  /// \brief Add a pre contract for this declarator
+  void addPreContract(Expr *TRC) {
+    PreContracts.push_back(TRC);
+  }
+
+  /// \brief Get all pre contracts for this declarator
+  const SmallVector<Expr*>& getPreContracts() {
+    return PreContracts;
+  }
+
+  /// \brief Add a post contract for this declarator
+  void addPostContract(Expr *TRC) {
+    PostContracts.push_back(TRC);
+  }
+
+  /// \brief Get all post contracts for this declarator
+  const SmallVector<Expr*>& getPostContracts() {
+    return PostContracts;
+  }
+
   /// Sets the template parameter lists that preceded the declarator.
   void setTemplateParameterLists(ArrayRef<TemplateParameterList *> TPLs) {
     TemplateParameterLists = TPLs;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index c528917437332..dabb6ff846a73 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2288,6 +2288,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
   if (Tok.is(tok::kw_requires))
     ParseTrailingRequiresClause(D);
 
+  while (Tok.is(tok::kw_pre) || Tok.is(tok::kw_post)) {
+    if (Tok.is(tok::kw_pre)) {
+      ParsePreContract(D);
+    } else {
+      ParsePostContract(D);
+    }
+  }
+
   // Save late-parsed attributes for now; they need to be parsed in the
   // appropriate function scope after the function Decl has been constructed.
   // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
@@ -2537,6 +2545,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
       //    init-declarator:
       //	      declarator initializer[opt]
       //        declarator requires-clause
+      while (Tok.is(tok::kw_pre) || Tok.is(tok::kw_post)) {
+        if (Tok.is(tok::kw_pre)) {
+          ParsePreContract(D);
+        } else {
+          ParsePostContract(D);
+        }
+      }
+      
       if (Tok.is(tok::kw_requires))
         ParseTrailingRequiresClause(D);
       Decl *ThisDecl = ParseDeclarationAfterDeclarator(D, TemplateInfo);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 9a4a777f575b2..f9061eb5e2bb9 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2005,6 +2005,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
         ConsumeBracket();
         if (!SkipUntil(tok::r_square, StopAtSemi))
           break;
+      } else if ((Tok.is(tok::kw_pre) || Tok.is(tok::kw_post)) && NextToken().is(tok::l_paren)) {
+        ConsumeToken();
+        ConsumeParen();
+        if (!SkipUntil(tok::r_paren, StopAtSemi))
+          break;
       } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) {
         ConsumeToken();
         ConsumeParen();
@@ -2663,6 +2668,14 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
                                                               VS);
   }
 
+  while (Tok.is(tok::kw_pre) || Tok.is(tok::kw_post)) {
+    if (Tok.is(tok::kw_pre)) {
+      ParsePreContract(DeclaratorInfo);
+    } else {
+      ParsePostContract(DeclaratorInfo);
+    }
+  }
+
   // If a simple-asm-expr is present, parse it.
   if (Tok.is(tok::kw_asm)) {
     SourceLocation Loc;
@@ -4248,6 +4261,113 @@ ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
   return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic;
 }
 
+void Parser::ParsePostContract(Declarator &DeclaratorInfo) {
+  ConsumeToken();
+
+  ParseScope ParamScope(this, Scope::DeclScope | 
+                                  Scope::FunctionDeclarationScope |
+                                  Scope::FunctionPrototypeScope);
+
+  DeclaratorChunk::FunctionTypeInfo FTI = DeclaratorInfo.getFunctionTypeInfo();
+  for (unsigned i = 0; i != FTI.NumParams; ++i) {
+    ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
+    Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param);
+  }
+
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+    return;
+  }
+  ConsumeParen();
+
+  // Post contracts start with <identifier> colon <expression>
+  // As we have to support the "auto f() post (r : r > 42) {...}" case, we cannot parse here
+  // the return type is not guaranteed to be known until after the function body parses
+
+/*
+    if (Tok.isNot(tok::identifier)) {
+      Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+      return;
+    }
+
+    ParsingDeclSpec DS(*this);
+
+    ParsedTemplateInfo TemplateInfo;
+    DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(DeclaratorContext::Block);
+    ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext);
+    
+    ParsedAttributes LocalAttrs(AttrFactory);
+    ParsingDeclarator D(*this, DS, LocalAttrs, DeclaratorContext::Block);
+
+    D.setObjectType(getAsFunction().getReturnType());
+    IdentifierInfo *Id = Tok.getIdentifierInfo();
+    SourceLocation IdLoc = ConsumeToken();
+    D.setIdentifier(Id, IdLoc);
+
+    Decl* ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
+    Actions.ActOnUninitializedDecl(ThisDecl);
+    Actions.FinalizeDeclaration(ThisDecl);
+    D.complete(ThisDecl);
+    if (Tok.isNot(tok::colon)) {
+      Diag(Tok.getLocation(), diag::err_expected) << tok::colon;
+      return;
+    }
+
+    ExprResult Expr = ParseExpression();
+    if (Expr.isInvalid()) {
+      Diag(Tok.getLocation(), diag::err_invalid_pcs);
+      return;
+    }
+    DeclaratorInfo.addPostContract(Expr.get());
+*/
+  ExprResult Expr = ParseExpression();
+  if (Expr.isInvalid()) {
+    Diag(Tok.getLocation(), diag::err_invalid_pcs);
+    return;
+  }
+  DeclaratorInfo.addPostContract(Expr.get());
+
+  if (Tok.isNot(tok::r_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+    return;
+  }
+  ConsumeParen();
+}
+
+void Parser::ParsePreContract(Declarator &DeclaratorInfo) {
+  ConsumeToken();
+
+  ParseScope ParamScope(this, Scope::DeclScope | 
+                                  Scope::FunctionDeclarationScope |
+                                  Scope::FunctionPrototypeScope);
+
+  DeclaratorChunk::FunctionTypeInfo FTI = DeclaratorInfo.getFunctionTypeInfo();
+  for (unsigned i = 0; i != FTI.NumParams; ++i) {
+    ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
+    Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param);
+  }
+
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+    return;
+  }
+  ConsumeParen();
+
+  // Pre contracts are just an expression
+  ExprResult Expr = ParseExpression();
+  if (Expr.isInvalid()) {
+    Diag(Tok.getLocation(), diag::err_invalid_pcs);
+    return;
+  }
+  DeclaratorInfo.addPreContract(Expr.get());
+
+  if (Tok.isNot(tok::r_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
+    return;
+  }
+  ConsumeParen();
+}
+
 /// ParseTrailingReturnType - Parse a trailing return type on a new-style
 /// function declaration.
 TypeResult Parser::ParseTrailingReturnType(SourceRange &Range,
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 1558e3dcb8974..43d3868839de5 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1487,7 +1487,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
                   tok::kw_constexpr, tok::kw_consteval, tok::kw_static,
                   tok::kw___private, tok::kw___global, tok::kw___local,
                   tok::kw___constant, tok::kw___generic, tok::kw_groupshared,
-                  tok::kw_requires, tok::kw_noexcept) ||
+                  tok::kw_requires, tok::kw_pre, tok::kw_post, tok::kw_noexcept) ||
       Tok.isRegularKeywordAttribute() ||
       (Tok.is(tok::l_square) && NextToken().is(tok::l_square));
 
@@ -1585,6 +1585,14 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
     if (HasParentheses && Tok.is(tok::kw_requires))
       ParseTrailingRequiresClause(D);
+
+    while (Tok.is(tok::kw_pre) || Tok.is(tok::kw_post)) {
+      if (Tok.is(tok::kw_pre)) {
+        ParsePreContract(D);
+      } else {
+        ParsePostContract(D);
+      }
+    }
   }
 
   // Emit a warning if we see a CUDA host/device/global attribute

>From 13ddd08d9040a08ca0cea44aca14eecd876730e9 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Fri, 31 May 2024 11:49:43 +0200
Subject: [PATCH 03/11] add contracts builtin prototypes

---
 clang/include/clang/Basic/Builtins.td | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 11982af3fa609..79a26256bee68 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2575,6 +2575,20 @@ def SetJmpEx : MSLibBuiltin<"setjmpex.h"> {
   let Prototype = "int(jmp_buf)";
 }
 
+// C++ contracts
+def ContractViolation : Builtin {
+  let Spellings = ["contract_violation"];
+  let Prototype = "void(char const*, int, char const*)";
+  let Attributes = [NoThrow];
+  let Namespace = "std";
+}
+
+def ContractAssert : Builtin {
+  let Spellings = ["contract_assert"];
+  let Attributes = [NoThrow];
+  let Prototype = "void(bool)";
+}
+
 // C99 library functions
 // C99 stdarg.h
 def VaStart : LibBuiltin<"stdarg.h"> {

>From 165068c64bece75030961915a4da40be3d88aec7 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Fri, 31 May 2024 13:12:14 +0200
Subject: [PATCH 04/11] add contracts to FunctionDecl

---
 clang/include/clang/AST/Decl.h                | 20 +++++++++-----
 clang/include/clang/AST/DeclCXX.h             | 22 ++++++++--------
 clang/include/clang/Sema/Sema.h               |  2 ++
 clang/lib/AST/ASTImporter.cpp                 | 11 ++++----
 clang/lib/AST/Decl.cpp                        |  7 ++---
 clang/lib/AST/DeclCXX.cpp                     | 26 +++++++++----------
 clang/lib/Sema/SemaDecl.cpp                   | 13 +++++-----
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  3 ++-
 8 files changed, 59 insertions(+), 45 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7fd80b90d1033..bb885f3ef1a3c 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -769,11 +769,12 @@ struct QualifierInfo {
 /// Contains type source information through TypeSourceInfo.
 class DeclaratorDecl : public ValueDecl {
   // A struct representing a TInfo, a trailing requires-clause and a syntactic
-  // qualifier, to be used for the (uncommon) case of out-of-line declarations
-  // and constrained function decls.
+  // qualifier, to be used for the (uncommon) case of out-of-line declarations,
+  // constrained function decls or functions with contracts.
   struct ExtInfo : public QualifierInfo {
     TypeSourceInfo *TInfo;
     Expr *TrailingRequiresClause = nullptr;
+    SmallVector<Expr*> PreContracts = {};
   };
 
   llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo;
@@ -853,8 +854,15 @@ class DeclaratorDecl : public ValueDecl {
                         : nullptr;
   }
 
+  SmallVector<Expr*> getPreContracts() const {
+    if (hasExtInfo()) return getExtInfo()->PreContracts;
+    return {};
+  }
+
   void setTrailingRequiresClause(Expr *TrailingRequiresClause);
 
+  void setPreContracts(SmallVector<Expr*> PreContracts);
+
   unsigned getNumTemplateParameterLists() const {
     return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0;
   }
@@ -2126,7 +2134,7 @@ class FunctionDecl : public DeclaratorDecl,
                const DeclarationNameInfo &NameInfo, QualType T,
                TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin,
                bool isInlineSpecified, ConstexprSpecKind ConstexprKind,
-               Expr *TrailingRequiresClause = nullptr);
+               Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
 
   using redeclarable_base = Redeclarable<FunctionDecl>;
 
@@ -2162,12 +2170,12 @@ class FunctionDecl : public DeclaratorDecl,
          TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false,
          bool isInlineSpecified = false, bool hasWrittenPrototype = true,
          ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified,
-         Expr *TrailingRequiresClause = nullptr) {
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}) {
     DeclarationNameInfo NameInfo(N, NLoc);
     return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
                                 UsesFPIntrin, isInlineSpecified,
                                 hasWrittenPrototype, ConstexprKind,
-                                TrailingRequiresClause);
+                                TrailingRequiresClause, PreContracts);
   }
 
   static FunctionDecl *
@@ -2175,7 +2183,7 @@ class FunctionDecl : public DeclaratorDecl,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified,
          bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind,
-         Expr *TrailingRequiresClause);
+         Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts);
 
   static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index fb52ac804849d..4b7689266c36e 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -2066,9 +2066,9 @@ class CXXMethodDecl : public FunctionDecl {
                 QualType T, TypeSourceInfo *TInfo, StorageClass SC,
                 bool UsesFPIntrin, bool isInline,
                 ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-                Expr *TrailingRequiresClause = nullptr)
+                Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
       : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-                     isInline, ConstexprKind, TrailingRequiresClause) {
+                     isInline, ConstexprKind, TrailingRequiresClause, PreContracts) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
   }
@@ -2079,7 +2079,7 @@ class CXXMethodDecl : public FunctionDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          StorageClass SC, bool UsesFPIntrin, bool isInline,
          ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-         Expr *TrailingRequiresClause = nullptr);
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
 
   static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
@@ -2547,7 +2547,7 @@ class CXXConstructorDecl final
                      bool UsesFPIntrin, bool isInline,
                      bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
                      InheritedConstructor Inherited,
-                     Expr *TrailingRequiresClause);
+                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts);
 
   void anchor() override;
 
@@ -2590,7 +2590,7 @@ class CXXConstructorDecl final
          ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
          bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
          InheritedConstructor Inherited = InheritedConstructor(),
-         Expr *TrailingRequiresClause = nullptr);
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
 
   void setExplicitSpecifier(ExplicitSpecifier ES) {
     assert((!ES.getExpr() ||
@@ -2809,10 +2809,10 @@ class CXXDestructorDecl : public CXXMethodDecl {
                     const DeclarationNameInfo &NameInfo, QualType T,
                     TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
                     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-                    Expr *TrailingRequiresClause = nullptr)
+                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
       : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
                       SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                      SourceLocation(), TrailingRequiresClause) {
+                      SourceLocation(), TrailingRequiresClause, PreContracts) {
     setImplicit(isImplicitlyDeclared);
   }
 
@@ -2824,7 +2824,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
          ConstexprSpecKind ConstexprKind,
-         Expr *TrailingRequiresClause = nullptr);
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
   static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
   void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@@ -2865,10 +2865,10 @@ class CXXConversionDecl : public CXXMethodDecl {
                     TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
                     ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
                     SourceLocation EndLocation,
-                    Expr *TrailingRequiresClause = nullptr)
+                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
       : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
                       SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                      EndLocation, TrailingRequiresClause),
+                      EndLocation, TrailingRequiresClause, PreContracts),
         ExplicitSpec(ES) {}
   void anchor() override;
 
@@ -2883,7 +2883,7 @@ class CXXConversionDecl : public CXXMethodDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
          ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-         Expr *TrailingRequiresClause = nullptr);
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
   ExplicitSpecifier getExplicitSpecifier() {
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7dea2b6826cfd..ba43236aa46b9 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4765,6 +4765,8 @@ class Sema final : public SemaBase {
   void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D);
   ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr);
   ExprResult ActOnRequiresClause(ExprResult ConstraintExpr);
+  void ActOnPreContract(Scope *S, Declarator &D);
+  void ActOnPostContract(Scope *S, Declarator &D);
 
   NamedDecl *
   ActOnDecompositionDeclarator(Scope *S, Declarator &D,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index cab5ee6047956..ab132d6449813 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3857,6 +3857,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
   auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
   auto TrailingRequiresClause =
       importChecked(Err, D->getTrailingRequiresClause());
+  auto PreContracts = D->getPreContracts();
   if (Err)
     return std::move(Err);
 
@@ -3888,7 +3889,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, ESpec, D->UsesFPIntrin(),
             D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
-            ToInheritedConstructor, TrailingRequiresClause))
+            ToInheritedConstructor, TrailingRequiresClause, PreContracts))
       return ToFunction;
   } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
 
@@ -3903,7 +3904,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(),
             D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
-            TrailingRequiresClause))
+            TrailingRequiresClause, PreContracts))
       return ToFunction;
 
     CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
@@ -3919,14 +3920,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(),
             D->isInlineSpecified(), ESpec, D->getConstexprKind(),
-            SourceLocation(), TrailingRequiresClause))
+            SourceLocation(), TrailingRequiresClause, PreContracts))
       return ToFunction;
   } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
     if (GetImportedOrCreateDecl<CXXMethodDecl>(
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(),
             Method->UsesFPIntrin(), Method->isInlineSpecified(),
-            D->getConstexprKind(), SourceLocation(), TrailingRequiresClause))
+            D->getConstexprKind(), SourceLocation(), TrailingRequiresClause, PreContracts))
       return ToFunction;
   } else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) {
     ExplicitSpecifier ESpec =
@@ -3946,7 +3947,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
             NameInfo, T, TInfo, D->getStorageClass(), D->UsesFPIntrin(),
             D->isInlineSpecified(), D->hasWrittenPrototype(),
-            D->getConstexprKind(), TrailingRequiresClause))
+            D->getConstexprKind(), TrailingRequiresClause, PreContracts))
       return ToFunction;
   }
 
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 0a35ed536a6a7..b174201b61803 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3042,7 +3042,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
                            TypeSourceInfo *TInfo, StorageClass S,
                            bool UsesFPIntrin, bool isInlineSpecified,
                            ConstexprSpecKind ConstexprKind,
-                           Expr *TrailingRequiresClause)
+                           Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts)
     : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
                      StartLoc),
       DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
@@ -3078,6 +3078,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
   FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
   if (TrailingRequiresClause)
     setTrailingRequiresClause(TrailingRequiresClause);
+//  setPreContracts(PreContracts);
 }
 
 void FunctionDecl::getNameForDiagnostic(
@@ -5401,10 +5402,10 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                      TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
                      bool isInlineSpecified, bool hasWrittenPrototype,
                      ConstexprSpecKind ConstexprKind,
-                     Expr *TrailingRequiresClause) {
+                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
   FunctionDecl *New = new (C, DC) FunctionDecl(
       Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-      isInlineSpecified, ConstexprKind, TrailingRequiresClause);
+      isInlineSpecified, ConstexprKind, TrailingRequiresClause, PreContracts);
   New->setHasWrittenPrototype(hasWrittenPrototype);
   return New;
 }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 75c441293d62e..c7cf36bed83c6 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2276,10 +2276,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                       TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
                       bool isInline, ConstexprSpecKind ConstexprKind,
                       SourceLocation EndLocation,
-                      Expr *TrailingRequiresClause) {
+                      Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
   return new (C, RD) CXXMethodDecl(
       CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-      isInline, ConstexprKind, EndLocation, TrailingRequiresClause);
+      isInline, ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts);
 }
 
 CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C,
@@ -2287,7 +2287,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C,
   return new (C, ID) CXXMethodDecl(
       CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
       QualType(), nullptr, SC_None, false, false,
-      ConstexprSpecKind::Unspecified, SourceLocation(), nullptr);
+      ConstexprSpecKind::Unspecified, SourceLocation(), nullptr, {});
 }
 
 CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2685,10 +2685,10 @@ CXXConstructorDecl::CXXConstructorDecl(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-    InheritedConstructor Inherited, Expr *TrailingRequiresClause)
+    InheritedConstructor Inherited, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
                     SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                    SourceLocation(), TrailingRequiresClause) {
+                    SourceLocation(), TrailingRequiresClause, PreContracts) {
   setNumCtorInitializers(0);
   setInheritingConstructor(static_cast<bool>(Inherited));
   setImplicit(isImplicitlyDeclared);
@@ -2712,7 +2712,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
       ExplicitSpecifier(), false, false, false, ConstexprSpecKind::Unspecified,
-      InheritedConstructor(), nullptr);
+      InheritedConstructor(), nullptr, {});
   Result->setInheritingConstructor(isInheritingConstructor);
   Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
       hasTrailingExplicit;
@@ -2725,7 +2725,7 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-    InheritedConstructor Inherited, Expr *TrailingRequiresClause) {
+    InheritedConstructor Inherited, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConstructorName &&
          "Name must refer to a constructor");
@@ -2734,7 +2734,7 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
           Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
   return new (C, RD, Extra) CXXConstructorDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, ES, UsesFPIntrin, isInline,
-      isImplicitlyDeclared, ConstexprKind, Inherited, TrailingRequiresClause);
+      isImplicitlyDeclared, ConstexprKind, Inherited, TrailingRequiresClause, PreContracts);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2851,20 +2851,20 @@ CXXDestructorDecl *CXXDestructorDecl::CreateDeserialized(ASTContext &C,
                                                          GlobalDeclID ID) {
   return new (C, ID) CXXDestructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      false, false, false, ConstexprSpecKind::Unspecified, nullptr);
+      false, false, false, ConstexprSpecKind::Unspecified, nullptr, {});
 }
 
 CXXDestructorDecl *CXXDestructorDecl::Create(
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
-    ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause) {
+    ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXDestructorName &&
          "Name must refer to a destructor");
   return new (C, RD) CXXDestructorDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline,
-      isImplicitlyDeclared, ConstexprKind, TrailingRequiresClause);
+      isImplicitlyDeclared, ConstexprKind, TrailingRequiresClause, PreContracts);
 }
 
 void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
@@ -2892,13 +2892,13 @@ CXXConversionDecl *CXXConversionDecl::Create(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
     ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-    Expr *TrailingRequiresClause) {
+    Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConversionFunctionName &&
          "Name must refer to a conversion function");
   return new (C, RD) CXXConversionDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline, ES,
-      ConstexprKind, EndLocation, TrailingRequiresClause);
+      ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 34e46e12859bb..1853ac81ca829 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9325,7 +9325,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
         SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype,
         ConstexprSpecKind::Unspecified,
-        /*TrailingRequiresClause=*/nullptr);
+        /*TrailingRequiresClause=*/nullptr, {});
     if (D.isInvalidType())
       NewFD->setInvalidDecl();
 
@@ -9334,6 +9334,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
 
   ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
   Expr *TrailingRequiresClause = D.getTrailingRequiresClause();
+  SmallVector<Expr*> PreContracts = D.getPreContracts();
 
   SemaRef.CheckExplicitObjectMemberFunction(DC, D, Name, R);
 
@@ -9347,7 +9348,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, ExplicitSpecifier, SemaRef.getCurFPFeatures().isFPConstrained(),
         isInline, /*isImplicitlyDeclared=*/false, ConstexprKind,
-        InheritedConstructor(), TrailingRequiresClause);
+        InheritedConstructor(), TrailingRequiresClause, PreContracts);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
     // This is a C++ destructor declaration.
@@ -9382,7 +9383,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
       return FunctionDecl::Create(
           SemaRef.Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), Name, R,
           TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-          /*hasPrototype=*/true, ConstexprKind, TrailingRequiresClause);
+          /*hasPrototype=*/true, ConstexprKind, TrailingRequiresClause, PreContracts);
     }
 
   } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -9401,7 +9402,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
         ExplicitSpecifier, ConstexprKind, SourceLocation(),
-        TrailingRequiresClause);
+        TrailingRequiresClause, PreContracts);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
     if (TrailingRequiresClause)
@@ -9430,7 +9431,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
     CXXMethodDecl *Ret = CXXMethodDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-        ConstexprKind, SourceLocation(), TrailingRequiresClause);
+        ConstexprKind, SourceLocation(), TrailingRequiresClause, PreContracts);
     IsVirtualOkay = !Ret->isStatic();
     return Ret;
   } else {
@@ -9445,7 +9446,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
     return FunctionDecl::Create(
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
         SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-        true /*HasPrototype*/, ConstexprKind, TrailingRequiresClause);
+        true /*HasPrototype*/, ConstexprKind, TrailingRequiresClause, PreContracts);
   }
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4c8eaf2d4ebf6..435223cc50b92 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2163,6 +2163,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
   }
 
   Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
+  SmallVector<Expr*> PreContracts = D->getPreContracts();
 
   // If we're instantiating a local function declaration, put the result
   // in the enclosing namespace; otherwise we need to find the instantiated
@@ -2200,7 +2201,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
         D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
         D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
-        TrailingRequiresClause);
+        TrailingRequiresClause, PreContracts);
     Function->setFriendConstraintRefersToEnclosingTemplate(
         D->FriendConstraintRefersToEnclosingTemplate());
     Function->setRangeEnd(D->getSourceRange().getEnd());

>From 87a3f7e1f1c88bef5c59ace6588003f01464345b Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Sun, 2 Jun 2024 13:41:07 +0200
Subject: [PATCH 05/11] propagate contracts up to emit function

---
 clang/lib/AST/Decl.cpp                | 16 +++++++-
 clang/lib/CodeGen/CGBuiltin.cpp       |  5 +++
 clang/lib/CodeGen/CodeGenFunction.cpp | 53 +++++++++++++++++++++++++++
 clang/lib/CodeGen/CodeGenFunction.h   |  3 ++
 4 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index b174201b61803..5f4c4938f5f41 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2028,6 +2028,20 @@ void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) {
   getExtInfo()->TrailingRequiresClause = TrailingRequiresClause;
 }
 
+void DeclaratorDecl::setPreContracts(SmallVector<Expr*> PreContracts) {
+  // Make sure the extended decl info is allocated.
+  if (!hasExtInfo()) {
+    // Save (non-extended) type source info pointer.
+    auto *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+    // Allocate external info struct.
+    DeclInfo = new (getASTContext()) ExtInfo;
+    // Restore savedTInfo into (extended) decl info.
+    getExtInfo()->TInfo = savedTInfo;
+  }
+  // Set requires clause info.
+  getExtInfo()->PreContracts = PreContracts;
+}
+
 void DeclaratorDecl::setTemplateParameterListsInfo(
     ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
   assert(!TPLists.empty());
@@ -3078,7 +3092,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
   FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
   if (TrailingRequiresClause)
     setTrailingRequiresClause(TrailingRequiresClause);
-//  setPreContracts(PreContracts);
+  setPreContracts(PreContracts);
 }
 
 void FunctionDecl::getNameForDiagnostic(
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 37d0c478e0330..4e4395ba5d96e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3350,6 +3350,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     Builder.CreateCall(FnAssume, ArgValue);
     return RValue::get(nullptr);
   }
+  case Builtin::BIcontract_assert: {
+    EmitCXXContractCheck(E->getArg(0));
+    EmitCXXContractImply(E->getArg(0));
+    return RValue::get(nullptr);
+  }
   case Builtin::BI__builtin_assume_separate_storage: {
     const Expr *Arg0 = E->getArg(0);
     const Expr *Arg1 = E->getArg(1);
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index f0345f3b191b8..a2592fbb7307f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -336,6 +336,48 @@ llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
   return llvm::DebugLoc();
 }
 
+void CodeGenFunction::EmitCXXContractCheck(const Expr* Expr) {
+  llvm::Value *ArgValue = EmitScalarExpr(Expr);
+/*
+  llvm::BasicBlock *Begin = Builder.GetInsertBlock();
+  llvm::BasicBlock *End = createBasicBlock("contract_assert_end", this->CurFn);
+  llvm::BasicBlock *Violation = createBasicBlock("contract_assert_violation", this->CurFn);
+
+  Builder.SetInsertPoint(Begin);
+  Builder.CreateCondBr(ArgValue, End, Violation);
+
+  Builder.SetInsertPoint(Violation);
+  */
+/*
+  SourceRange range = Expr->getSourceRange();
+  PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(range->getBegin());
+  clang::StringLiteral* Filename = PLoc->getFilename();
+  llvm::Value* LineNo = PLoc->getLine();
+  clang::StringLiteral* ExpressionText = range.print(os, Ctx.getSourceManager());
+*/
+  const char *VLibCallName = "__contract_violation"; // const char*
+  CallArgList Args;
+  /*
+  Args.add(EmitLoadOfLValue(EmitStringLiteralLValue(Filename), Expr->getExprLoc()), getContext().VoidPtrTy);
+  Args.add(RValue::get(LineNo), getContext().getSizeType());
+  Args.add(EmitLoadOfLValue(EmitStringLiteralLValue(ExpressionText), Expr->getExprLoc()), getContext().VoidPtrTy);
+  */
+  /*
+  const CGFunctionInfo &VFuncInfo = CGM.getTypes().arrangeBuiltinFunctionCall(getContext().VoidPtrTy, {});
+  llvm::FunctionType *VFTy = CGM.getTypes().GetFunctionType(VFuncInfo);
+  llvm::FunctionCallee VFunc = CGM.CreateRuntimeFunction(VFTy, VLibCallName);
+  EmitCall(VFuncInfo, CGCallee::forDirect(VFunc), ReturnValueSlot(), Args);
+*/
+
+//  Builder.SetInsertPoint(End);
+}
+
+void CodeGenFunction::EmitCXXContractImply(const Expr* expr) {
+  llvm::Value *ArgValue = EmitScalarExpr(expr);
+  llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume);
+  Builder.CreateCall(FnAssume, ArgValue);
+}
+
 static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
   if (!BB) return;
   if (!BB->use_empty()) {
@@ -420,6 +462,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   // Emit debug descriptor for function end.
   if (CGDebugInfo *DI = getDebugInfo())
     DI->EmitFunctionEnd(Builder, CurFn);
+/*
+  for (Expr* expr : FN->getPostContracts()) {
+    EmitCXXContractCheck(expr);
+    EmitCXXContractImply(expr);
+  }
+  */
 
   // Reset the debug location to that of the simple 'return' expression, if any
   // rather than that of the end of the function's scope '}'.
@@ -1200,6 +1248,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
 
   EmitFunctionProlog(*CurFnInfo, CurFn, Args);
 
+  for (Expr* expr : FD->getPreContracts()) {
+    EmitCXXContractCheck(expr);
+    EmitCXXContractImply(expr);
+  }
+
   if (const CXXMethodDecl *MD = dyn_cast_if_present<CXXMethodDecl>(D);
       MD && !MD->isStatic()) {
     bool IsInLambda =
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 45585361a4fc9..fb478929cbb2f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4337,6 +4337,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E);
   void   EmitDeclRefExprDbgValue(const DeclRefExpr *E, const APValue &Init);
 
+  void   EmitCXXContractCheck(const Expr* expr);
+  void   EmitCXXContractImply(const Expr* expr);
+
   //===--------------------------------------------------------------------===//
   //                         Scalar Expression Emission
   //===--------------------------------------------------------------------===//

>From 1c11146110254428d77a494df6680cda0c617e83 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Mon, 3 Jun 2024 08:37:16 +0200
Subject: [PATCH 06/11] add constexpr contract failure

---
 clang/include/clang/Basic/Builtins.td           |  5 +++--
 clang/include/clang/Basic/DiagnosticASTKinds.td |  2 ++
 clang/lib/AST/ExprConstant.cpp                  | 11 +++++++++++
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 79a26256bee68..e9ec87a15467f 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2579,13 +2579,14 @@ def SetJmpEx : MSLibBuiltin<"setjmpex.h"> {
 def ContractViolation : Builtin {
   let Spellings = ["contract_violation"];
   let Prototype = "void(char const*, int, char const*)";
-  let Attributes = [NoThrow];
+  let Attributes = [NoThrow, Constexpr];
   let Namespace = "std";
 }
 
 def ContractAssert : Builtin {
   let Spellings = ["contract_assert"];
-  let Attributes = [NoThrow];
+  let Attributes = [NoThrow, Constexpr];
+
   let Prototype = "void(bool)";
 }
 
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index a024f9b2a9f8c..82325f2b396e3 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -403,6 +403,8 @@ def note_constexpr_assumption_failed : Note<
   "assumption evaluated to false">;
 def err_experimental_clang_interp_failed : Error<
   "the experimental clang interpreter failed to evaluate an expression">;
+def note_constexpr_contract_failure : Error<
+  "contract failed during execution of constexpr function">;
 
 def warn_integer_constant_overflow : Warning<
   "overflow in expression; result is %0 with type %1">,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e1..7d5633092447e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15508,6 +15508,17 @@ class VoidExprEvaluator
     case Builtin::BI__builtin_operator_delete:
       return HandleOperatorDeleteCall(Info, E);
 
+    case Builtin::BIcontract_assert:
+    {
+      APSInt Desired;
+      if (!EvaluateInteger(E->getArg(0), Desired, Info)){
+        return false;
+      }
+      if (!Desired) {
+        Info.CCEDiag(E, diag::note_constexpr_contract_failure);
+      }
+      return true;
+    }
     default:
       return false;
     }

>From fcd97445f8023e81abb81a277a3b790dc7b69ecd Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Mon, 3 Jun 2024 09:37:08 +0200
Subject: [PATCH 07/11] add constexpr precontract evaluation

---
 clang/lib/AST/ExprConstant.cpp | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7d5633092447e..b8ec7eab44efd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6294,6 +6294,19 @@ static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param,
       CopyObjectRepresentation);
 }
 
+static bool EvaluatePreContracts(const FunctionDecl* Callee, EvalInfo& Info) {
+  for (Expr* E : Callee->getPreContracts()) {
+    APSInt Desired;
+    if (!EvaluateInteger(E, Desired, Info)){
+      return false;
+    }
+    if (!Desired) {
+      Info.CCEDiag(E, diag::note_constexpr_contract_failure);
+    }
+  }
+  return true;
+}
+
 /// Evaluate a function call.
 static bool HandleFunctionCall(SourceLocation CallLoc,
                                const FunctionDecl *Callee, const LValue *This,
@@ -6339,6 +6352,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
                                         Frame.LambdaThisCaptureField);
   }
 
+  EvaluatePreContracts(Callee, Info);
   StmtResult Ret = {Result, ResultSlot};
   EvalStmtResult ESR = EvaluateStmt(Ret, Info, Body);
   if (ESR == ESR_Succeeded) {
@@ -15515,7 +15529,7 @@ class VoidExprEvaluator
         return false;
       }
       if (!Desired) {
-        Info.CCEDiag(E, diag::note_constexpr_contract_failure);
+        Info.CCEDiag(E->getArg(0), diag::note_constexpr_contract_failure);
       }
       return true;
     }

>From 59bbcbe9b7d409290515020024b40c59ee4c8ca3 Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Mon, 3 Jun 2024 12:16:50 +0200
Subject: [PATCH 08/11] runtime contract violation flag now

---
 clang/include/clang/Basic/Builtins.td |  5 +++--
 clang/lib/CodeGen/CodeGenFunction.cpp | 21 ++++++++++++---------
 libcxx/src/system_error.cpp           |  4 ++++
 3 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index e9ec87a15467f..88bb52af92521 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2578,8 +2578,9 @@ def SetJmpEx : MSLibBuiltin<"setjmpex.h"> {
 // C++ contracts
 def ContractViolation : Builtin {
   let Spellings = ["contract_violation"];
-  let Prototype = "void(char const*, int, char const*)";
-  let Attributes = [NoThrow, Constexpr];
+//  let Prototype = "void(char const*, int, char const*)";
+  let Prototype = "void()";
+  let Attributes = [NoThrow, NoReturn, Constexpr];
   let Namespace = "std";
 }
 
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index a2592fbb7307f..22665ec4b34f7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -338,7 +338,6 @@ llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
 
 void CodeGenFunction::EmitCXXContractCheck(const Expr* Expr) {
   llvm::Value *ArgValue = EmitScalarExpr(Expr);
-/*
   llvm::BasicBlock *Begin = Builder.GetInsertBlock();
   llvm::BasicBlock *End = createBasicBlock("contract_assert_end", this->CurFn);
   llvm::BasicBlock *Violation = createBasicBlock("contract_assert_violation", this->CurFn);
@@ -347,7 +346,7 @@ void CodeGenFunction::EmitCXXContractCheck(const Expr* Expr) {
   Builder.CreateCondBr(ArgValue, End, Violation);
 
   Builder.SetInsertPoint(Violation);
-  */
+
 /*
   SourceRange range = Expr->getSourceRange();
   PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(range->getBegin());
@@ -355,21 +354,25 @@ void CodeGenFunction::EmitCXXContractCheck(const Expr* Expr) {
   llvm::Value* LineNo = PLoc->getLine();
   clang::StringLiteral* ExpressionText = range.print(os, Ctx.getSourceManager());
 */
-  const char *VLibCallName = "__contract_violation"; // const char*
+  const char *VLibCallName = "_ZSt18contract_violationv"; // const char*
   CallArgList Args;
-  /*
+/*
   Args.add(EmitLoadOfLValue(EmitStringLiteralLValue(Filename), Expr->getExprLoc()), getContext().VoidPtrTy);
   Args.add(RValue::get(LineNo), getContext().getSizeType());
   Args.add(EmitLoadOfLValue(EmitStringLiteralLValue(ExpressionText), Expr->getExprLoc()), getContext().VoidPtrTy);
-  */
-  /*
-  const CGFunctionInfo &VFuncInfo = CGM.getTypes().arrangeBuiltinFunctionCall(getContext().VoidPtrTy, {});
+*/
+  const CGFunctionInfo &VFuncInfo = CGM.getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, {});
   llvm::FunctionType *VFTy = CGM.getTypes().GetFunctionType(VFuncInfo);
   llvm::FunctionCallee VFunc = CGM.CreateRuntimeFunction(VFTy, VLibCallName);
   EmitCall(VFuncInfo, CGCallee::forDirect(VFunc), ReturnValueSlot(), Args);
-*/
 
-//  Builder.SetInsertPoint(End);
+  llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
+  TrapCall->setDoesNotReturn();
+  TrapCall->setDoesNotThrow();
+  Builder.CreateUnreachable();
+  Builder.ClearInsertionPoint();
+
+  Builder.SetInsertPoint(End);
 }
 
 void CodeGenFunction::EmitCXXContractImply(const Expr* expr) {
diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp
index f518b480a2782..de64edf199278 100644
--- a/libcxx/src/system_error.cpp
+++ b/libcxx/src/system_error.cpp
@@ -220,4 +220,8 @@ void __throw_system_error(int ev, const char* what_arg) {
 #endif
 }
 
+void contract_violation() {
+  std::terminate();
+}
+
 _LIBCPP_END_NAMESPACE_STD

>From c206da08714efcc6ed22e2ad53c9a39366e3aa2f Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Mon, 3 Jun 2024 19:59:26 +0200
Subject: [PATCH 09/11] add post contracts

---
 clang/include/clang/AST/Decl.h                | 19 +++++++++---
 clang/include/clang/AST/DeclCXX.h             | 28 +++++++++++-------
 clang/include/clang/Basic/Builtins.td         |  3 +-
 clang/include/clang/Sema/Sema.h               |  2 --
 clang/lib/AST/ASTImporter.cpp                 | 11 +++----
 clang/lib/AST/Decl.cpp                        | 23 +++++++++++++--
 clang/lib/AST/DeclCXX.cpp                     | 29 +++++++++++--------
 clang/lib/AST/ExprConstant.cpp                | 18 ++++++++++--
 clang/lib/CodeGen/CodeGenFunction.cpp         | 21 +++++++-------
 clang/lib/Sema/SemaDecl.cpp                   | 13 +++++----
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  3 +-
 11 files changed, 111 insertions(+), 59 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index bb885f3ef1a3c..db8786c19452f 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -775,6 +775,7 @@ class DeclaratorDecl : public ValueDecl {
     TypeSourceInfo *TInfo;
     Expr *TrailingRequiresClause = nullptr;
     SmallVector<Expr*> PreContracts = {};
+    SmallVector<Expr*> PostContracts = {};
   };
 
   llvm::PointerUnion<TypeSourceInfo *, ExtInfo *> DeclInfo;
@@ -859,10 +860,17 @@ class DeclaratorDecl : public ValueDecl {
     return {};
   }
 
+  SmallVector<Expr*> getPostContracts() const {
+    if (hasExtInfo()) return getExtInfo()->PostContracts;
+    return {};
+  }
+
   void setTrailingRequiresClause(Expr *TrailingRequiresClause);
 
   void setPreContracts(SmallVector<Expr*> PreContracts);
 
+  void setPostContracts(SmallVector<Expr*> PostContracts);
+
   unsigned getNumTemplateParameterLists() const {
     return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0;
   }
@@ -2134,7 +2142,8 @@ class FunctionDecl : public DeclaratorDecl,
                const DeclarationNameInfo &NameInfo, QualType T,
                TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin,
                bool isInlineSpecified, ConstexprSpecKind ConstexprKind,
-               Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
+               Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {},
+               SmallVector<Expr*> PostContracts = {});
 
   using redeclarable_base = Redeclarable<FunctionDecl>;
 
@@ -2170,12 +2179,13 @@ class FunctionDecl : public DeclaratorDecl,
          TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false,
          bool isInlineSpecified = false, bool hasWrittenPrototype = true,
          ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified,
-         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}) {
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {},
+         SmallVector<Expr*> PostContracts = {}) {
     DeclarationNameInfo NameInfo(N, NLoc);
     return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
                                 UsesFPIntrin, isInlineSpecified,
                                 hasWrittenPrototype, ConstexprKind,
-                                TrailingRequiresClause, PreContracts);
+                                TrailingRequiresClause, PreContracts, PostContracts);
   }
 
   static FunctionDecl *
@@ -2183,7 +2193,8 @@ class FunctionDecl : public DeclaratorDecl,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified,
          bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind,
-         Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts);
+         Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts, 
+         SmallVector<Expr*> PostContracts);
 
   static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 4b7689266c36e..80082b4c49b93 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -2066,9 +2066,10 @@ class CXXMethodDecl : public FunctionDecl {
                 QualType T, TypeSourceInfo *TInfo, StorageClass SC,
                 bool UsesFPIntrin, bool isInline,
                 ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-                Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
+                Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}, 
+                SmallVector<Expr*> PostContracts = {})
       : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-                     isInline, ConstexprKind, TrailingRequiresClause, PreContracts) {
+                     isInline, ConstexprKind, TrailingRequiresClause, PreContracts, PostContracts) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
   }
@@ -2079,7 +2080,7 @@ class CXXMethodDecl : public FunctionDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          StorageClass SC, bool UsesFPIntrin, bool isInline,
          ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}, SmallVector<Expr*> PostContracts = {});
 
   static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
@@ -2547,7 +2548,7 @@ class CXXConstructorDecl final
                      bool UsesFPIntrin, bool isInline,
                      bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
                      InheritedConstructor Inherited,
-                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts);
+                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts, SmallVector<Expr*> PostContracts);
 
   void anchor() override;
 
@@ -2590,7 +2591,8 @@ class CXXConstructorDecl final
          ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
          bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
          InheritedConstructor Inherited = InheritedConstructor(),
-         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}, 
+         SmallVector<Expr*> PostContracts = {});
 
   void setExplicitSpecifier(ExplicitSpecifier ES) {
     assert((!ES.getExpr() ||
@@ -2809,10 +2811,11 @@ class CXXDestructorDecl : public CXXMethodDecl {
                     const DeclarationNameInfo &NameInfo, QualType T,
                     TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
                     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
+                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {},
+                    SmallVector<Expr*> PostContracts = {})
       : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
                       SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                      SourceLocation(), TrailingRequiresClause, PreContracts) {
+                      SourceLocation(), TrailingRequiresClause, PreContracts, PostContracts) {
     setImplicit(isImplicitlyDeclared);
   }
 
@@ -2824,7 +2827,8 @@ class CXXDestructorDecl : public CXXMethodDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
          ConstexprSpecKind ConstexprKind,
-         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {},
+         SmallVector<Expr*> PostContracts = {});
   static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
   void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@@ -2865,10 +2869,11 @@ class CXXConversionDecl : public CXXMethodDecl {
                     TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline,
                     ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind,
                     SourceLocation EndLocation,
-                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {})
+                    Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {},
+                    SmallVector<Expr*> PostContracts = {})
       : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
                       SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                      EndLocation, TrailingRequiresClause, PreContracts),
+                      EndLocation, TrailingRequiresClause, PreContracts, PostContracts),
         ExplicitSpec(ES) {}
   void anchor() override;
 
@@ -2883,7 +2888,8 @@ class CXXConversionDecl : public CXXMethodDecl {
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
          ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {});
+         Expr *TrailingRequiresClause = nullptr, SmallVector<Expr*> PreContracts = {}, 
+         SmallVector<Expr*> PostContracts = {});
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
 
   ExplicitSpecifier getExplicitSpecifier() {
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 88bb52af92521..6150d3d7a1fb0 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2578,8 +2578,7 @@ def SetJmpEx : MSLibBuiltin<"setjmpex.h"> {
 // C++ contracts
 def ContractViolation : Builtin {
   let Spellings = ["contract_violation"];
-//  let Prototype = "void(char const*, int, char const*)";
-  let Prototype = "void()";
+  let Prototype = "void(char const*, int, char const*)";
   let Attributes = [NoThrow, NoReturn, Constexpr];
   let Namespace = "std";
 }
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index ba43236aa46b9..7dea2b6826cfd 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4765,8 +4765,6 @@ class Sema final : public SemaBase {
   void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D);
   ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr);
   ExprResult ActOnRequiresClause(ExprResult ConstraintExpr);
-  void ActOnPreContract(Scope *S, Declarator &D);
-  void ActOnPostContract(Scope *S, Declarator &D);
 
   NamedDecl *
   ActOnDecompositionDeclarator(Scope *S, Declarator &D,
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index ab132d6449813..58ec48c1c80f8 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -3858,6 +3858,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
   auto TrailingRequiresClause =
       importChecked(Err, D->getTrailingRequiresClause());
   auto PreContracts = D->getPreContracts();
+  auto PostContracts = D->getPostContracts();
   if (Err)
     return std::move(Err);
 
@@ -3889,7 +3890,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, ESpec, D->UsesFPIntrin(),
             D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
-            ToInheritedConstructor, TrailingRequiresClause, PreContracts))
+            ToInheritedConstructor, TrailingRequiresClause, PreContracts, PostContracts))
       return ToFunction;
   } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
 
@@ -3904,7 +3905,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(),
             D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(),
-            TrailingRequiresClause, PreContracts))
+            TrailingRequiresClause, PreContracts, PostContracts))
       return ToFunction;
 
     CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
@@ -3920,14 +3921,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(),
             D->isInlineSpecified(), ESpec, D->getConstexprKind(),
-            SourceLocation(), TrailingRequiresClause, PreContracts))
+            SourceLocation(), TrailingRequiresClause, PreContracts, PostContracts))
       return ToFunction;
   } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
     if (GetImportedOrCreateDecl<CXXMethodDecl>(
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(),
             Method->UsesFPIntrin(), Method->isInlineSpecified(),
-            D->getConstexprKind(), SourceLocation(), TrailingRequiresClause, PreContracts))
+            D->getConstexprKind(), SourceLocation(), TrailingRequiresClause, PreContracts, PostContracts))
       return ToFunction;
   } else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(D)) {
     ExplicitSpecifier ESpec =
@@ -3947,7 +3948,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
             ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
             NameInfo, T, TInfo, D->getStorageClass(), D->UsesFPIntrin(),
             D->isInlineSpecified(), D->hasWrittenPrototype(),
-            D->getConstexprKind(), TrailingRequiresClause, PreContracts))
+            D->getConstexprKind(), TrailingRequiresClause, PreContracts, PostContracts))
       return ToFunction;
   }
 
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 5f4c4938f5f41..6d2486a3a7927 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2042,6 +2042,20 @@ void DeclaratorDecl::setPreContracts(SmallVector<Expr*> PreContracts) {
   getExtInfo()->PreContracts = PreContracts;
 }
 
+void DeclaratorDecl::setPostContracts(SmallVector<Expr*> PostContracts) {
+  // Make sure the extended decl info is allocated.
+  if (!hasExtInfo()) {
+    // Save (non-extended) type source info pointer.
+    auto *savedTInfo = DeclInfo.get<TypeSourceInfo*>();
+    // Allocate external info struct.
+    DeclInfo = new (getASTContext()) ExtInfo;
+    // Restore savedTInfo into (extended) decl info.
+    getExtInfo()->TInfo = savedTInfo;
+  }
+  // Set requires clause info.
+  getExtInfo()->PostContracts = PostContracts;
+}
+
 void DeclaratorDecl::setTemplateParameterListsInfo(
     ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
   assert(!TPLists.empty());
@@ -3056,7 +3070,8 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
                            TypeSourceInfo *TInfo, StorageClass S,
                            bool UsesFPIntrin, bool isInlineSpecified,
                            ConstexprSpecKind ConstexprKind,
-                           Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts)
+                           Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts,
+                           SmallVector<Expr*> PostContracts)
     : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
                      StartLoc),
       DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0),
@@ -3093,6 +3108,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
   if (TrailingRequiresClause)
     setTrailingRequiresClause(TrailingRequiresClause);
   setPreContracts(PreContracts);
+  setPostContracts(PostContracts);
 }
 
 void FunctionDecl::getNameForDiagnostic(
@@ -5416,10 +5432,11 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                      TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
                      bool isInlineSpecified, bool hasWrittenPrototype,
                      ConstexprSpecKind ConstexprKind,
-                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
+                     Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts, 
+                     SmallVector<Expr*> PostContracts) {
   FunctionDecl *New = new (C, DC) FunctionDecl(
       Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-      isInlineSpecified, ConstexprKind, TrailingRequiresClause, PreContracts);
+      isInlineSpecified, ConstexprKind, TrailingRequiresClause, PreContracts, PostContracts);
   New->setHasWrittenPrototype(hasWrittenPrototype);
   return New;
 }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c7cf36bed83c6..b5a70feb0b7f8 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2276,10 +2276,11 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                       TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin,
                       bool isInline, ConstexprSpecKind ConstexprKind,
                       SourceLocation EndLocation,
-                      Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
+                      Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts,
+                      SmallVector<Expr*> PostContracts) {
   return new (C, RD) CXXMethodDecl(
       CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin,
-      isInline, ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts);
+      isInline, ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts, PostContracts);
 }
 
 CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C,
@@ -2287,7 +2288,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C,
   return new (C, ID) CXXMethodDecl(
       CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
       QualType(), nullptr, SC_None, false, false,
-      ConstexprSpecKind::Unspecified, SourceLocation(), nullptr, {});
+      ConstexprSpecKind::Unspecified, SourceLocation(), nullptr, {}, {});
 }
 
 CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2685,10 +2686,11 @@ CXXConstructorDecl::CXXConstructorDecl(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-    InheritedConstructor Inherited, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts)
+    InheritedConstructor Inherited, Expr *TrailingRequiresClause, 
+    SmallVector<Expr*> PreContracts, SmallVector<Expr*> PostContracts)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
                     SC_None, UsesFPIntrin, isInline, ConstexprKind,
-                    SourceLocation(), TrailingRequiresClause, PreContracts) {
+                    SourceLocation(), TrailingRequiresClause, PreContracts, PostContracts) {
   setNumCtorInitializers(0);
   setInheritingConstructor(static_cast<bool>(Inherited));
   setImplicit(isImplicitlyDeclared);
@@ -2712,7 +2714,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
       ExplicitSpecifier(), false, false, false, ConstexprSpecKind::Unspecified,
-      InheritedConstructor(), nullptr, {});
+      InheritedConstructor(), nullptr, {}, {});
   Result->setInheritingConstructor(isInheritingConstructor);
   Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
       hasTrailingExplicit;
@@ -2725,7 +2727,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline,
     bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind,
-    InheritedConstructor Inherited, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
+    InheritedConstructor Inherited, Expr *TrailingRequiresClause, 
+    SmallVector<Expr*> PreContracts, SmallVector<Expr*> PostContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConstructorName &&
          "Name must refer to a constructor");
@@ -2734,7 +2737,7 @@ CXXConstructorDecl *CXXConstructorDecl::Create(
           Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
   return new (C, RD, Extra) CXXConstructorDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, ES, UsesFPIntrin, isInline,
-      isImplicitlyDeclared, ConstexprKind, Inherited, TrailingRequiresClause, PreContracts);
+      isImplicitlyDeclared, ConstexprKind, Inherited, TrailingRequiresClause, PreContracts, PostContracts);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2858,13 +2861,14 @@ CXXDestructorDecl *CXXDestructorDecl::Create(
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
-    ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
+    ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause, 
+    SmallVector<Expr*> PreContracts, SmallVector<Expr*> PostContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXDestructorName &&
          "Name must refer to a destructor");
   return new (C, RD) CXXDestructorDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline,
-      isImplicitlyDeclared, ConstexprKind, TrailingRequiresClause, PreContracts);
+      isImplicitlyDeclared, ConstexprKind, TrailingRequiresClause, PreContracts, PostContracts);
 }
 
 void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
@@ -2892,13 +2896,14 @@ CXXConversionDecl *CXXConversionDecl::Create(
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
     ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
-    Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts) {
+    Expr *TrailingRequiresClause, SmallVector<Expr*> PreContracts,
+    SmallVector<Expr*> PostContracts) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConversionFunctionName &&
          "Name must refer to a conversion function");
   return new (C, RD) CXXConversionDecl(
       C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline, ES,
-      ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts);
+      ConstexprKind, EndLocation, TrailingRequiresClause, PreContracts, PostContracts);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index b8ec7eab44efd..8b56b0b0d8073 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6301,7 +6301,20 @@ static bool EvaluatePreContracts(const FunctionDecl* Callee, EvalInfo& Info) {
       return false;
     }
     if (!Desired) {
-      Info.CCEDiag(E, diag::note_constexpr_contract_failure);
+      Info.report(E->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getSourceRange();
+    }
+  }
+  return true;
+}
+
+static bool EvaluatePostContracts(const FunctionDecl* Callee, EvalInfo& Info) {
+  for (Expr* E : Callee->getPostContracts()) {
+    APSInt Desired;
+    if (!EvaluateInteger(E, Desired, Info)){
+      return false;
+    }
+    if (!Desired) {
+      Info.report(E->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getSourceRange();
     }
   }
   return true;
@@ -6355,6 +6368,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
   EvaluatePreContracts(Callee, Info);
   StmtResult Ret = {Result, ResultSlot};
   EvalStmtResult ESR = EvaluateStmt(Ret, Info, Body);
+  EvaluatePostContracts(Callee, Info);
   if (ESR == ESR_Succeeded) {
     if (Callee->getReturnType()->isVoidType())
       return true;
@@ -15529,7 +15543,7 @@ class VoidExprEvaluator
         return false;
       }
       if (!Desired) {
-        Info.CCEDiag(E->getArg(0), diag::note_constexpr_contract_failure);
+        Info.report(E->getArg(0)->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getArg(0)->getSourceRange();
       }
       return true;
     }
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 22665ec4b34f7..8864ecc211fcd 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -465,12 +465,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   // Emit debug descriptor for function end.
   if (CGDebugInfo *DI = getDebugInfo())
     DI->EmitFunctionEnd(Builder, CurFn);
-/*
-  for (Expr* expr : FN->getPostContracts()) {
-    EmitCXXContractCheck(expr);
-    EmitCXXContractImply(expr);
-  }
-  */
 
   // Reset the debug location to that of the simple 'return' expression, if any
   // rather than that of the end of the function's scope '}'.
@@ -1251,11 +1245,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
 
   EmitFunctionProlog(*CurFnInfo, CurFn, Args);
 
-  for (Expr* expr : FD->getPreContracts()) {
-    EmitCXXContractCheck(expr);
-    EmitCXXContractImply(expr);
-  }
-
   if (const CXXMethodDecl *MD = dyn_cast_if_present<CXXMethodDecl>(D);
       MD && !MD->isStatic()) {
     bool IsInLambda =
@@ -1535,6 +1524,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
   // Emit the standard function prologue.
   StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
 
+  for (Expr* expr : FD->getPreContracts()) {
+    EmitCXXContractCheck(expr);
+    EmitCXXContractImply(expr);
+  }
+
   // Save parameters for coroutine function.
   if (Body && isa_and_nonnull<CoroutineBodyStmt>(Body))
     llvm::append_range(FnArgs, FD->parameters());
@@ -1610,6 +1604,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
     }
   }
 
+  for (Expr* expr : FD->getPostContracts()) {
+    EmitCXXContractCheck(expr);
+    EmitCXXContractImply(expr);
+  }
+
   // Emit the standard function epilogue.
   FinishFunction(BodyRange.getEnd());
 
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1853ac81ca829..c83b86f9d8816 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9325,7 +9325,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
         SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype,
         ConstexprSpecKind::Unspecified,
-        /*TrailingRequiresClause=*/nullptr, {});
+        /*TrailingRequiresClause=*/nullptr, {}, {});
     if (D.isInvalidType())
       NewFD->setInvalidDecl();
 
@@ -9335,6 +9335,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
   ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
   Expr *TrailingRequiresClause = D.getTrailingRequiresClause();
   SmallVector<Expr*> PreContracts = D.getPreContracts();
+  SmallVector<Expr*> PostContracts = D.getPostContracts();
 
   SemaRef.CheckExplicitObjectMemberFunction(DC, D, Name, R);
 
@@ -9348,7 +9349,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, ExplicitSpecifier, SemaRef.getCurFPFeatures().isFPConstrained(),
         isInline, /*isImplicitlyDeclared=*/false, ConstexprKind,
-        InheritedConstructor(), TrailingRequiresClause, PreContracts);
+        InheritedConstructor(), TrailingRequiresClause, PreContracts, PostContracts);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
     // This is a C++ destructor declaration.
@@ -9383,7 +9384,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
       return FunctionDecl::Create(
           SemaRef.Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), Name, R,
           TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-          /*hasPrototype=*/true, ConstexprKind, TrailingRequiresClause, PreContracts);
+          /*hasPrototype=*/true, ConstexprKind, TrailingRequiresClause, PreContracts, PostContracts);
     }
 
   } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -9402,7 +9403,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
         ExplicitSpecifier, ConstexprKind, SourceLocation(),
-        TrailingRequiresClause, PreContracts);
+        TrailingRequiresClause, PreContracts, PostContracts);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
     if (TrailingRequiresClause)
@@ -9431,7 +9432,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
     CXXMethodDecl *Ret = CXXMethodDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-        ConstexprKind, SourceLocation(), TrailingRequiresClause, PreContracts);
+        ConstexprKind, SourceLocation(), TrailingRequiresClause, PreContracts, PostContracts);
     IsVirtualOkay = !Ret->isStatic();
     return Ret;
   } else {
@@ -9446,7 +9447,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
     return FunctionDecl::Create(
         SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC,
         SemaRef.getCurFPFeatures().isFPConstrained(), isInline,
-        true /*HasPrototype*/, ConstexprKind, TrailingRequiresClause, PreContracts);
+        true /*HasPrototype*/, ConstexprKind, TrailingRequiresClause, PreContracts, PostContracts);
   }
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 435223cc50b92..612e339a9aac7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2164,6 +2164,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
 
   Expr *TrailingRequiresClause = D->getTrailingRequiresClause();
   SmallVector<Expr*> PreContracts = D->getPreContracts();
+  SmallVector<Expr*> PostContracts = D->getPostContracts();
 
   // If we're instantiating a local function declaration, put the result
   // in the enclosing namespace; otherwise we need to find the instantiated
@@ -2201,7 +2202,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
         SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
         D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(),
         D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(),
-        TrailingRequiresClause, PreContracts);
+        TrailingRequiresClause, PreContracts, PostContracts);
     Function->setFriendConstraintRefersToEnclosingTemplate(
         D->FriendConstraintRefersToEnclosingTemplate());
     Function->setRangeEnd(D->getSourceRange().getEnd());

>From 027b095fb6ab958a29399871095aa2e1e844863a Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Mon, 3 Jun 2024 20:30:12 +0200
Subject: [PATCH 10/11] switch back to CCEDiag

---
 clang/lib/AST/ExprConstant.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8b56b0b0d8073..eb62f558bfc46 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6301,7 +6301,7 @@ static bool EvaluatePreContracts(const FunctionDecl* Callee, EvalInfo& Info) {
       return false;
     }
     if (!Desired) {
-      Info.report(E->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getSourceRange();
+      Info.CCEDiag(E, diag::note_constexpr_contract_failure);
     }
   }
   return true;
@@ -6314,7 +6314,7 @@ static bool EvaluatePostContracts(const FunctionDecl* Callee, EvalInfo& Info) {
       return false;
     }
     if (!Desired) {
-      Info.report(E->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getSourceRange();
+      Info.CCEDiag(E, diag::note_constexpr_contract_failure);
     }
   }
   return true;
@@ -15543,7 +15543,7 @@ class VoidExprEvaluator
         return false;
       }
       if (!Desired) {
-        Info.report(E->getArg(0)->getSourceRange().getBegin(), diag::note_constexpr_contract_failure) << E->getArg(0)->getSourceRange();
+        Info.CCEDiag(E->getArg(0), diag::note_constexpr_contract_failure);
       }
       return true;
     }

>From 075da514a4dd2d89bc30cef614547cbe961d0aea Mon Sep 17 00:00:00 2001
From: Dascandy <dascandy at gmail.com>
Date: Tue, 4 Jun 2024 10:24:07 +0200
Subject: [PATCH 11/11] use abort instead of terminate

---
 libcxx/src/system_error.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp
index de64edf199278..db145327cc2e7 100644
--- a/libcxx/src/system_error.cpp
+++ b/libcxx/src/system_error.cpp
@@ -221,7 +221,7 @@ void __throw_system_error(int ev, const char* what_arg) {
 }
 
 void contract_violation() {
-  std::terminate();
+  std::abort();
 }
 
 _LIBCPP_END_NAMESPACE_STD



More information about the libcxx-commits mailing list