Tyker created this revision.
Tyker added a reviewer: rsmith.
Herald added a reviewer: martong.
Herald added a reviewer: shafik.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

this revision adds the consteval specifier as specified by 
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r3.html

Changes:

- add the consteval keyword.
- add parsing of consteval specifier for normal declarations and lambdas 
expressions.
- add the a bit to FunctionDeclBits for consteval.
- adapt creation of FunctionDecl and some classes inheriting from it to take an 
extra bool for consteval.
- change most calls to FunctionDecl::isConstexpr into call to 
FunctionDecl::isConstexprOrConsteval.
- add semantic checking to prevent call to consteval function that cannot be 
constant evaluated.
- add semantic checking to prevent taking address from consteval function.
- add semantic checking to prevent consteval specified allocation function.
- add tests for semantic.

The code-gen has not yet been adapted, but it will need to be change to not 
emit consteval function and ensure calls to consteval function are folded 
correctly.


Repository:
  rC Clang

https://reviews.llvm.org/D61790

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/AST/DeclCXX.h
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/TokenKinds.def
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/Decl.cpp
  clang/lib/AST/DeclCXX.cpp
  clang/lib/AST/DeclPrinter.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Analysis/ReachableCode.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Parse/ParseTentative.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/test/SemaCXX/cxx2a-compat.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp

Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -0,0 +1,224 @@
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
+
+int i_global; // expected-note+ {{declared here}}
+extern int i_extern; // expected-note+ {{declared here}}
+const int i_const = 0;
+constexpr int i_constexpr = 0;
+
+consteval int f_eval(int i) {
+// expected-note@-1+ {{consteval function declared here}}
+  return i;
+}
+
+constexpr auto l_eval = [](int i) consteval {
+// expected-note@-1+ {{consteval operator declared here}}
+  return i;
+};
+
+constexpr int f_expr(int i) {
+  return i;
+}
+
+struct A {
+  consteval int f_eval(int i) const {
+// expected-note@-1+ {{consteval function declared here}}
+    return i;
+  }
+};
+
+constexpr A a;
+
+namespace invalid_call_args {
+
+int d0 = f_eval(0);
+int l0 = l_eval(0);
+int m0 = a.f_eval(0);
+int d2 = f_eval(i_extern);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int l2 = l_eval(i_extern);
+// expected-error@-1 {{call to consteval operator cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int m2 = a.f_eval(i_extern);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int d4 = f_eval(i_const);
+int l4 = l_eval(i_const);
+int m4 = a.f_eval(i_const);
+int d6 = f_eval(i_constexpr);
+int l6 = l_eval(i_constexpr);
+int m6 = a.f_eval(i_constexpr);
+int d8 = f_eval(i_global);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int l8 = l_eval(i_global);
+// expected-error@-1 {{call to consteval operator cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int m8 = a.f_eval(i_global);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{argument 0 cannot be constant evaluated}}
+// expected-note@-3 {{not allowed in a constant expression}}
+
+constexpr int f1(int i) { // expected-note+ {{declared here}}
+  int d0 = f_eval(0);
+  int l0 = l_eval(0);
+  int m0 = a.f_eval(0);
+  int d2 = f_eval(i);
+  // expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  // expected-error@-4 {{variables defined in a constexpr function must be initialized}}
+  // TODO: prevent the error from the previous line from being emitted.
+  int l2 = l_eval(i);
+  // expected-error@-1 {{call to consteval operator cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  int m2 = a.f_eval(i);
+  // expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  int d4 = f_eval(i_const);
+  int l4 = l_eval(i_const);
+  int m4 = a.f_eval(i_const);
+  int d6 = f_eval(i_constexpr);
+  int l6 = l_eval(i_constexpr);
+  int m6 = a.f_eval(i_constexpr);
+  int d8 = f_eval(i_global);
+  // expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  int l8 = l_eval(i_global);
+  // expected-error@-1 {{call to consteval operator cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  int m8 = a.f_eval(i_global);
+  // expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+  // expected-note@-2 {{argument 0 cannot be constant evaluated}}
+  // expected-note@-3 {{not allowed in a constant expression}}
+  return 0;
+}
+
+consteval int f2(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int d0 = f_eval(i);
+  int l0 = l_eval(i);
+  int m0 = a.f_eval(i);
+  int d2 = f_eval(i_extern);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+consteval int f3(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int m2 = a.f_eval(i_extern);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+consteval int l3(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int l2 = l_eval(i_extern);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+consteval int f4(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int d4 = f_eval(i_const);
+  int l4 = l_eval(i_const);
+  int m4 = a.f_eval(i_const);
+  int d6 = f_eval(i_constexpr);
+  int l6 = l_eval(i_constexpr);
+  int m6 = a.f_eval(i_constexpr);
+  int d8 = f_eval(i_global);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+consteval int f5(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int l8 = l_eval(i_global);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+consteval int m5(int i) {
+  // expected-error@-1 {{constexpr function never produces a constant expression}}
+  int m8 = a.f_eval(i_global);
+  // expected-note@-1 {{not allowed in a constant expression}}
+  return 0;
+}
+
+consteval int f_multi(int a, int b, int c) {
+// expected-note@-1 {{declared here}}
+  return a + b + c;
+}
+
+int v = f_multi(i_const, i_extern, i_global);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{argument 1 cannot be constant evaluate}}
+// expected-note@-3+ {{not allowed in a constant expression}}
+// expected-note@-4 {{argument 2 cannot be constant evaluate}}
+
+constexpr A a;
+
+A a_dependent;
+// expected-note@-1+ {{declared here}}
+auto l_dependent = [](int i) consteval {
+// expected-note@-1+ {{declared here}}
+  return i;
+};
+
+int i_l = l_dependent(0);
+// expected-error@-1 {{call to consteval operator cannot be constant evaluated}}
+// expected-note@-2 {{call to member of non-constexpr value}}
+// expected-note@-3 {{not allowed in a constant expression}}
+int i_m = a_dependent.f_eval(0);
+// expected-error@-1 {{call to consteval function cannot be constant evaluated}}
+// expected-note@-2 {{call to member of non-constexpr value}}
+// expected-note@-3 {{not allowed in a constant expression}}
+}
+
+namespace taking_address {
+
+using func_type = int(int);
+using mem_ptr_type = int(A::*)(int);
+
+func_type* p1 = (f_eval);
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p2= &(((f_eval)));
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p3 = (func_type*)f_eval;
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p4 = static_cast<func_type*>(f_eval);
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p5 = reinterpret_cast<func_type*>(f_eval);
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p6 = reinterpret_cast<func_type*>(&reinterpret_cast<char>(f_eval));
+// expected-error@-1 {{taking address of a consteval function}}
+func_type* p7 = __builtin_addressof(f_eval);
+// expected-error@-1 {{taking address of a consteval function}}
+
+mem_ptr_type m1 = &A::f_eval;
+// expected-error@-1 {{taking address of a consteval function}}
+auto* l1 = &decltype(l_eval)::operator();
+// expected-error@-1 {{taking address of a consteval operator}}
+
+}
+
+namespace invalid_function {
+using size_t = unsigned long;
+struct A {
+  consteval void *operator new(size_t count);
+  // expected-error@-1 {{operator new cannot be marked consteval}}
+  consteval void *operator new[](size_t count);
+  // expected-error@-1 {{operator new[] cannot be marked consteval}}
+  consteval void operator delete(void* ptr);
+  // expected-error@-1 {{operator delete cannot be marked consteval}}
+  consteval void operator delete[](void* ptr);
+  // expected-error@-1 {{operator delete[] cannot be marked consteval}}
+  consteval ~A();
+  // expected-error@-1 {{destructor cannot be marked consteval}}
+};
+
+}
Index: clang/test/SemaCXX/cxx2a-compat.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-compat.cpp
+++ clang/test/SemaCXX/cxx2a-compat.cpp
@@ -56,4 +56,12 @@
 #if !defined(__cpp_conditional_explicit) || __cpp_conditional_explicit != 201806L
 #error "the feature test macro __cpp_conditional_explicit isn't correct"
 #endif
+#endif
+
+auto l = []() consteval {};
+int consteval();
+#if __cplusplus <= 201703L
+// expected-warning@-3 {{'consteval' is a keyword in C++2a}}
+#else
+// expected-error@-4 {{expected unqualified-id}}
 #endif
\ No newline at end of file
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -546,6 +546,7 @@
   Record.push_back(D->isExplicitlyDefaulted());
   Record.push_back(D->hasImplicitReturnZero());
   Record.push_back(D->isConstexpr());
+  Record.push_back(D->isConsteval());
   Record.push_back(D->usesSEHTry());
   Record.push_back(D->hasSkippedBody());
   Record.push_back(D->isMultiVersion());
@@ -2174,6 +2175,7 @@
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr
+  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Consteval
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // UsesSEHTry
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -869,6 +869,7 @@
   FD->setExplicitlyDefaulted(Record.readInt());
   FD->setHasImplicitReturnZero(Record.readInt());
   FD->setConstexpr(Record.readInt());
+  FD->setConsteval(Record.readInt());
   FD->setUsesSEHTry(Record.readInt());
   FD->setHasSkippedBody(Record.readInt());
   FD->setIsMultiVersion(Record.readInt());
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -11224,7 +11224,7 @@
       Class, E->getIntroducerRange(), NewCallOpTSI,
       E->getCallOperator()->getEndLoc(),
       NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
-      E->getCallOperator()->isConstexpr());
+      E->getCallOperator()->isConstexpr(), E->getCallOperator()->isConsteval());
 
   LSI->CallOperator = NewCallOperator;
 
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1768,7 +1768,7 @@
     Function = FunctionDecl::Create(
         SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo,
         D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(),
-        D->hasWrittenPrototype(), D->isConstexpr());
+        D->hasWrittenPrototype(), D->isConstexpr(), D->isConsteval());
     Function->setRangeEnd(D->getSourceRange().getEnd());
   }
 
@@ -2076,7 +2076,7 @@
     Method = CXXConstructorDecl::Create(
         SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
         InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
-        Constructor->isConstexpr());
+        Constructor->isConstexpr(), Constructor->isConsteval());
     Method->setRangeEnd(Constructor->getEndLoc());
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
@@ -2088,12 +2088,14 @@
     Method = CXXConversionDecl::Create(
         SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
         Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
-        Conversion->isConstexpr(), Conversion->getEndLoc());
+        Conversion->isConstexpr(), Conversion->isConsteval(),
+        Conversion->getEndLoc());
   } else {
     StorageClass SC = D->isStatic() ? SC_Static : SC_None;
     Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo,
                                    T, TInfo, SC, D->isInlineSpecified(),
-                                   D->isConstexpr(), D->getEndLoc());
+                                   D->isConstexpr(), D->isConsteval(),
+                                   D->getEndLoc());
   }
 
   if (D->isInlined())
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -8255,7 +8255,7 @@
       // it will be a static member function until we know which template it
       // specializes), so adjust it now assuming it specializes this template.
       QualType FT = FD->getType();
-      if (FD->isConstexpr()) {
+      if (FD->isConstexprOrConsteval()) {
         CXXMethodDecl *OldMD =
           dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
         if (OldMD && OldMD->isConst()) {
@@ -8362,6 +8362,7 @@
     // FIXME: What if there are multiple such prior declarations (for instance,
     // from different modules)?
     Specialization->setConstexpr(FD->isConstexpr());
+    Specialization->setConsteval(FD->isConsteval());
   }
 
   // FIXME: Check if the prior specialization has a point of instantiation.
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -69,7 +69,9 @@
 
   S.MarkDeclRefReferenced(DRE, Base);
   return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()),
-                             CK_FunctionToPointerDecay);
+                             CK_FunctionToPointerDecay, VK_RValue, nullptr,
+                             Sema::CCK_ImplicitConversion,
+                             /*isCastForCall*/ true);
 }
 
 static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
@@ -13110,6 +13112,9 @@
     MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
   }
 
+  if (CheckInvalidConstevalCall(Method, LParenLoc, Args, MemExprE))
+    return ExprError();
+
   QualType ResultType = Method->getReturnType();
   ExprValueKind VK = Expr::getValueKindForType(ResultType);
   ResultType = ResultType.getNonLValueExprType(Context);
@@ -13367,6 +13372,9 @@
 
   CheckMemberOperatorAccess(LParenLoc, Object.get(), nullptr, Best->FoundDecl);
 
+  if (CheckInvalidConstevalCall(Best->Function, LParenLoc, Args, Object.get()))
+    return ExprError();
+
   // We found an overloaded operator(). Build a CXXOperatorCallExpr
   // that calls this method, using Object for the implicit object
   // parameter and passing along the remaining arguments.
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -372,7 +372,8 @@
                                            TypeSourceInfo *MethodTypeInfo,
                                            SourceLocation EndLoc,
                                            ArrayRef<ParmVarDecl *> Params,
-                                           const bool IsConstexprSpecified) {
+                                           const bool IsConstexprSpecified,
+                                           const bool IsConstevalSpecified) {
   QualType MethodType = MethodTypeInfo->getType();
   TemplateParameterList *TemplateParams =
             getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -401,16 +402,12 @@
     = IntroducerRange.getBegin().getRawEncoding();
   MethodNameLoc.CXXOperatorName.EndOpNameLoc
     = IntroducerRange.getEnd().getRawEncoding();
-  CXXMethodDecl *Method
-    = CXXMethodDecl::Create(Context, Class, EndLoc,
-                            DeclarationNameInfo(MethodName,
-                                                IntroducerRange.getBegin(),
-                                                MethodNameLoc),
-                            MethodType, MethodTypeInfo,
-                            SC_None,
-                            /*isInline=*/true,
-                            IsConstexprSpecified,
-                            EndLoc);
+  CXXMethodDecl *Method = CXXMethodDecl::Create(
+      Context, Class, EndLoc,
+      DeclarationNameInfo(MethodName, IntroducerRange.getBegin(),
+                          MethodNameLoc),
+      MethodType, MethodTypeInfo, SC_None,
+      /*isInline=*/true, IsConstexprSpecified, IsConstevalSpecified, EndLoc);
   Method->setAccess(AS_public);
 
   // Temporarily set the lexical declaration context to the current
@@ -929,7 +926,8 @@
 
   CXXMethodDecl *Method =
       startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
-                            ParamInfo.getDeclSpec().isConstexprSpecified());
+                            ParamInfo.getDeclSpec().isConstexprSpecified(),
+                            ParamInfo.getDeclSpec().isConstevalSpecified());
   if (ExplicitParams)
     CheckCXXDefaultArguments(Method);
 
@@ -1327,7 +1325,7 @@
       DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
       /*isInline=*/true, ExplicitSpecifier(),
       /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
-      CallOperator->getBody()->getEndLoc());
+      /*isConsteval=*/false, CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
   Conversion->setImplicit(true);
 
@@ -1366,7 +1364,8 @@
       S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc),
       InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static,
       /*IsInline=*/true,
-      /*IsConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+      /*IsConstexpr=*/false,
+      /*IsConsteval=*/false, CallOperator->getBody()->getEndLoc());
   for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
     InvokerParams[I]->setOwningFunction(Invoke);
   Invoke->setParams(InvokerParams);
@@ -1413,7 +1412,8 @@
       S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
       S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
       /*isInline=*/true, ExplicitSpecifier(),
-      /*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
+      /*isConstexpr=*/false, /*isConsteval=*/false,
+      CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
   Conversion->setImplicit(true);
   Class->addDecl(Conversion);
@@ -1681,7 +1681,7 @@
   // and we are not in a dependent context, analyze the call operator to infer
   // its constexpr-ness, suppressing diagnostics while doing so.
   if (getLangOpts().CPlusPlus17 && !CallOperator->isInvalidDecl() &&
-      !CallOperator->isConstexpr() &&
+      !CallOperator->isConstexprOrConsteval() &&
       !isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
       !Class->getDeclContext()->isDependentContext()) {
     TentativeAnalysisScope DiagnosticScopeGuard(*this);
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -4012,6 +4012,9 @@
     llvm_unreachable("Improper first standard conversion");
   }
 
+  if (!From)
+    return ExprError();
+
   // Perform the second implicit conversion
   switch (SCS.Second) {
   case ICK_Identity:
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -454,8 +454,8 @@
         if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc()))
           return ExprError();
 
-    E = ImpCastExprToType(E, Context.getPointerType(Ty),
-                          CK_FunctionToPointerDecay).get();
+    return ImpCastExprToType(E, Context.getPointerType(Ty),
+                             CK_FunctionToPointerDecay);
   } else if (Ty->isArrayType()) {
     // In C90 mode, arrays only promote to pointers if the array expression is
     // an lvalue.  The relevant legalese is C90 6.2.2.1p3: "an lvalue that has
@@ -469,8 +469,8 @@
     // T" can be converted to an rvalue of type "pointer to T".
     //
     if (getLangOpts().C99 || getLangOpts().CPlusPlus || E->isLValue())
-      E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
-                            CK_ArrayToPointerDecay).get();
+      return ImpCastExprToType(E, Context.getArrayDecayedType(Ty),
+                               CK_ArrayToPointerDecay);
   }
   return E;
 }
@@ -666,7 +666,10 @@
   // to function type.
   if (Ty->isFunctionType()) {
     Res = ImpCastExprToType(E, Context.getPointerType(Ty),
-                            CK_FunctionToPointerDecay).get();
+                            CK_FunctionToPointerDecay, VK_RValue, nullptr,
+                            CCK_ImplicitConversion,
+                            /*isCastForCall*/ true)
+              .get();
     if (Res.isInvalid())
       return ExprError();
   }
@@ -5714,6 +5717,60 @@
   return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc);
 }
 
+bool Sema::CheckInvalidConstevalCall(FunctionDecl *FDecl, SourceLocation Loc,
+                                     ArrayRef<Expr *> Args, Expr *This) {
+  bool Failed = false;
+  if (FDecl && FDecl->isConsteval() &&
+      (!getCurFunctionDecl() || !getCurFunctionDecl()->isConsteval())) {
+
+    SmallVector<PartialDiagnosticAt, 8> Diags;
+    auto Check = [&](Expr *Arg, unsigned int DiagID, int Index = 0) {
+      Expr::EvalResult Result;
+      Result.Diag = &Diags;
+      if (!Arg->EvaluateAsRValue(Result, getASTContext(), true)) {
+        if (!Failed) {
+          Failed = true;
+          const char *DeclName =
+              (isa<CXXConstructorDecl>(FDecl) ? "consteval constructor"
+                                              : "consteval function");
+          if (FDecl->isOverloadedOperator())
+            DeclName = "consteval operator";
+          Diag(Loc, diag::err_consteval_cannot_be_constant_eval) << DeclName;
+          Diag(FDecl->getLocation(), diag::note_callee_decl) << DeclName;
+        }
+        Diag(Arg->getBeginLoc(), DiagID) << Index;
+        for (const auto &Diag : Diags) {
+          this->Diag(Diag.first, Diag.second);
+        }
+        Diags.clear();
+      }
+    };
+    if (This) {
+      This = This->IgnoreParens();
+      if (auto *MemExpr = dyn_cast<MemberExpr>(This)) {
+        This = nullptr;
+        // the first children of a MemberExpr is the object.
+        if (MemExpr->children().begin() != MemExpr->children().end())
+          // is it possible to have no childrens ?
+          if (*MemExpr->children().begin())
+            // is it possible to have a null childrens ?
+            This = cast<Expr>(*MemExpr->children().begin());
+      }
+
+      if (This) {
+        This = This->IgnoreParenCasts();
+        Check(This, diag::note_not_constexpr_this);
+      }
+    }
+    for (auto It = Args.begin(); It != Args.end(); It++) {
+      Expr *Arg = *It;
+      Check(Arg, diag::note_argument_n_cannot_be_constant_eval,
+            It - Args.begin());
+    }
+  }
+  return Failed;
+}
+
 /// BuildResolvedCallExpr - Build a call to a resolved expression,
 /// i.e. an expression not of \p OverloadTy.  The expression should
 /// unary-convert to an expression of function-pointer or
@@ -5745,6 +5802,9 @@
         Diag(Fn->getExprLoc(), diag::warn_arm_interrupt_calling_convention);
     }
 
+  if (CheckInvalidConstevalCall(FDecl, LParenLoc, Args))
+    return ExprError();
+
   // Promote the function operand.
   // We special-case function promotion here because we only allow promoting
   // builtin functions to function pointers in the callee of a call.
@@ -13357,10 +13417,33 @@
   return CreateBuiltinUnaryOp(OpLoc, Opc, Input);
 }
 
+bool Sema::CheckInvalidConstevalTakeAddress(Expr *Input) {
+  if (Input) {
+    if (auto *DeclRef = dyn_cast<DeclRefExpr>(Input->IgnoreParens())) {
+      if (auto *Function = dyn_cast<FunctionDecl>(DeclRef->getDecl())) {
+        if (Function->isConsteval()) {
+          const char *DeclName = Function->isOverloadedOperator()
+                                     ? "consteval operator"
+                                     : "consteval function";
+          Diag(DeclRef->getExprLoc(), diag::err_take_adress_of_consteval_decl)
+              << DeclName;
+          Diag(Function->getLocation(), diag::note_entity_declared_at)
+              << DeclName;
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 // Unary Operators.  'Tok' is the token for the operator.
 ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
                               tok::TokenKind Op, Expr *Input) {
-  return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input);
+  UnaryOperatorKind Opc = ConvertTokenKindToUnaryOpcode(Op);
+  if (Opc == UO_AddrOf && CheckInvalidConstevalTakeAddress(Input))
+    return ExprError();
+  return BuildUnaryOp(S, OpLoc, Opc, Input);
 }
 
 /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
@@ -14782,7 +14865,7 @@
 
 static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
   CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
-  return Func->isConstexpr() &&
+  return Func->isConstexprOrConsteval() &&
          (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
 }
 
@@ -14918,13 +15001,13 @@
     }
 
     if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
-        Func->isConstexpr()) {
+        Func->isConstexprOrConsteval()) {
       if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
           cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
           CodeSynthesisContexts.size())
         PendingLocalImplicitInstantiations.push_back(
             std::make_pair(Func, PointOfInstantiation));
-      else if (Func->isConstexpr())
+      else if (Func->isConstexprOrConsteval())
         // Do not defer instantiations of constexpr functions, to avoid the
         // expression evaluator needing to call back into Sema if it sees a
         // call to such a function.
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -634,12 +634,17 @@
   }
 
   const FunctionDecl *Def;
-  // C++11 [dcl.constexpr]p1: If any declaration of a function or function
-  // template has a constexpr specifier then all its declarations shall
-  // contain the constexpr specifier.
+  // C++2a [dcl.constexpr]p1: If any declaration of a function or function
+  // template has a constexpr or consteval specifier, then all its declarations
+  // shall contain the same specifier.
   if (New->isConstexpr() != Old->isConstexpr()) {
     Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
-      << New << New->isConstexpr();
+        << New << New->isConstexpr() << "constexpr";
+    Diag(Old->getLocation(), diag::note_previous_declaration);
+    Invalid = true;
+  } else if (New->isConsteval() != Old->isConsteval()) {
+    Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch)
+        << New << New->isConsteval() << "consteval";
     Diag(Old->getLocation(), diag::note_previous_declaration);
     Invalid = true;
   } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() &&
@@ -1960,7 +1965,7 @@
          !getLangOpts().CPlusPlus2a
              ? diag::ext_constexpr_function_try_block_cxx2a
              : diag::warn_cxx17_compat_constexpr_function_try_block)
-        << isa<CXXConstructorDecl>(Dcl);
+        << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
   }
 
   // - its function-body shall be [...] a compound-statement that contains only
@@ -6332,7 +6337,7 @@
     auto BaseCtor =
         Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first;
     if (BaseCtor)
-      return BaseCtor->isConstexpr();
+      return BaseCtor->isConstexprOrConsteval();
   }
 
   if (CSM == Sema::CXXDefaultConstructor)
@@ -6344,7 +6349,7 @@
     // A constructor we wouldn't select can't be "involved in initializing"
     // anything.
     return true;
-  return SMOR.getMethod()->isConstexpr();
+  return SMOR.getMethod()->isConstexprOrConsteval();
 }
 
 /// Determine whether the specified special member function would be constexpr
@@ -6631,20 +6636,21 @@
     HadError = true;
   }
 
-  // C++11 [dcl.fct.def.default]p2:
-  //   An explicitly-defaulted function may be declared constexpr only if it
-  //   would have been implicitly declared as constexpr,
-  // Do not apply this rule to members of class templates, since core issue 1358
-  // makes such functions always instantiate to constexpr functions. For
-  // functions which cannot be constexpr (for non-constructors in C++11 and for
-  // destructors in C++1y), this is checked elsewhere.
-  //
+  // C++2a [dcl.fct.def.default]p3:
+  // An explicitly-defaulted function that is not defined as deleted may be
+  // declared constexpr or consteval only if it would have been implicitly
+  // declared as constexpr.
+  // Do not apply this rule to members of class
+  // templates, since core issue 1358 makes such functions always instantiate to
+  // constexpr functions. For functions which cannot be constexpr (for
+  // non-constructors in C++11 and for destructors in C++1y), this is checked
+  // elsewhere.
   // FIXME: This should not apply if the member is deleted.
   bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
                                                      HasConstParam);
   if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
                                  : isa<CXXConstructorDecl>(MD)) &&
-      MD->isConstexpr() && !Constexpr &&
+      MD->isConstexprOrConsteval() && !Constexpr &&
       MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
     Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr) << CSM;
     // FIXME: Explain why the special member can't be constexpr.
@@ -10993,7 +10999,8 @@
   CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
       Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
       /*TInfo=*/nullptr, ExplicitSpecifier(),
-      /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
+      /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr,
+      /*isConsteval=*/false);
   DefaultCon->setAccess(AS_public);
   DefaultCon->setDefaulted();
 
@@ -11114,7 +11121,7 @@
       Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
       BaseCtor->getExplicitSpecifier(), /*Inline=*/true,
       /*ImplicitlyDeclared=*/true, Constexpr,
-      InheritedConstructor(Shadow, BaseCtor));
+      /*isConsteval=*/false, InheritedConstructor(Shadow, BaseCtor));
   if (Shadow->isInvalidDecl())
     DerivedCtor->setInvalidDecl();
 
@@ -11862,10 +11869,10 @@
   DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
   SourceLocation ClassLoc = ClassDecl->getLocation();
   DeclarationNameInfo NameInfo(Name, ClassLoc);
-  CXXMethodDecl *CopyAssignment =
-      CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
-                            /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
-                            /*isInline=*/true, Constexpr, SourceLocation());
+  CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+      /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+      /*isInline=*/true, Constexpr, /*isConsteval=*/false, SourceLocation());
   CopyAssignment->setAccess(AS_public);
   CopyAssignment->setDefaulted();
   CopyAssignment->setImplicit();
@@ -12182,10 +12189,10 @@
   DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
   SourceLocation ClassLoc = ClassDecl->getLocation();
   DeclarationNameInfo NameInfo(Name, ClassLoc);
-  CXXMethodDecl *MoveAssignment =
-      CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
-                            /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
-                            /*isInline=*/true, Constexpr, SourceLocation());
+  CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create(
+      Context, ClassDecl, ClassLoc, NameInfo, QualType(),
+      /*TInfo=*/nullptr, /*StorageClass=*/SC_None,
+      /*isInline=*/true, Constexpr, /*isConsteval=*/false, SourceLocation());
   MoveAssignment->setAccess(AS_public);
   MoveAssignment->setDefaulted();
   MoveAssignment->setImplicit();
@@ -12566,7 +12573,8 @@
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
       ExplicitSpecifier(),
       /*isInline=*/true,
-      /*isImplicitlyDeclared=*/true, Constexpr);
+      /*isImplicitlyDeclared=*/true, Constexpr,
+      /*isConsteval=*/false);
   CopyConstructor->setAccess(AS_public);
   CopyConstructor->setDefaulted();
 
@@ -12697,7 +12705,7 @@
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
       ExplicitSpecifier(),
       /*isInline=*/true,
-      /*isImplicitlyDeclared=*/true, Constexpr);
+      /*isImplicitlyDeclared=*/true, Constexpr, /*isConsteval=*/false);
   MoveConstructor->setAccess(AS_public);
   MoveConstructor->setDefaulted();
 
@@ -13005,6 +13013,9 @@
   if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
     return ExprError();
 
+  if (CheckInvalidConstevalCall(Constructor, ConstructLoc, ExprArgs))
+    return ExprError();
+
   return CXXConstructExpr::Create(
       Context, DeclInitType, ConstructLoc, Constructor, Elidable,
       ExprArgs, HadMultipleCandidates, IsListInitialization,
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -7991,6 +7991,7 @@
 
   ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
   bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+  bool isConsteval = D.getDeclSpec().isConstevalSpecified();
 
   // Check that the return type is not an abstract class type.
   // For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -8010,7 +8011,7 @@
     return CXXConstructorDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
         TInfo, ExplicitSpecifier, isInline,
-        /*isImplicitlyDeclared=*/false, isConstexpr);
+        /*isImplicitlyDeclared=*/false, isConstexpr, isConsteval);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
     // This is a C++ destructor declaration.
@@ -8037,10 +8038,10 @@
 
       // Create a FunctionDecl to satisfy the function definition parsing
       // code path.
-      return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
-                                  D.getIdentifierLoc(), Name, R, TInfo, SC,
-                                  isInline,
-                                  /*hasPrototype=*/true, isConstexpr);
+      return FunctionDecl::Create(
+          SemaRef.Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), Name, R,
+          TInfo, SC, isInline,
+          /*hasPrototype=*/true, isConstexpr, isConsteval);
     }
 
   } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
@@ -8052,9 +8053,10 @@
 
     SemaRef.CheckConversionDeclarator(D, R, SC);
     IsVirtualOkay = true;
-    return CXXConversionDecl::Create(
-        SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
-        TInfo, isInline, ExplicitSpecifier, isConstexpr, SourceLocation());
+    return CXXConversionDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
+                                     D.getBeginLoc(), NameInfo, R, TInfo,
+                                     isInline, ExplicitSpecifier, isConstexpr,
+                                     isConsteval, SourceLocation());
 
   } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
     SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
@@ -8078,7 +8080,7 @@
     // This is a C++ method declaration.
     CXXMethodDecl *Ret = CXXMethodDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
-        TInfo, SC, isInline, isConstexpr, SourceLocation());
+        TInfo, SC, isInline, isConstexpr, isConsteval, SourceLocation());
     IsVirtualOkay = !Ret->isStatic();
     return Ret;
   } else {
@@ -8092,7 +8094,7 @@
     //   - we're in C++ (where every function has a prototype),
     return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo,
                                 R, TInfo, SC, isInline, true /*HasPrototype*/,
-                                isConstexpr);
+                                isConstexpr, isConsteval);
   }
 }
 
@@ -8423,6 +8425,7 @@
     bool isVirtual = D.getDeclSpec().isVirtualSpecified();
     bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
     bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
+    bool isConsteval = D.getDeclSpec().isConstevalSpecified();
     isFriend = D.getDeclSpec().isFriendSpecified();
     if (isFriend && !isInline && D.isFunctionDefinition()) {
       // C++ [class.friend]p5
@@ -8621,16 +8624,40 @@
       }
     }
 
-    if (isConstexpr) {
-      // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
-      // are implicitly inline.
+    if (isConstexpr || isConsteval) {
+      // C++2a [dcl.constexpr]p1: A function or static data member declared with
+      // the constexpr or consteval specifier is implicitly an inline function
+      // or variable ([dcl.inline])
       NewFD->setImplicitlyInline();
 
       // C++11 [dcl.constexpr]p3: functions declared constexpr are required to
       // be either constructors or to return a literal type. Therefore,
       // destructors cannot be declared constexpr.
-      if (isa<CXXDestructorDecl>(NewFD))
-        Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
+      // C++2a [dcl.constexpr]p2: A destructor, an allocation function, or a
+      // deallocation function shall not be declared with the consteval
+      // specifier.
+      if (isa<CXXDestructorDecl>(NewFD)) {
+        if (isConstexpr)
+          Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
+              << "constexpr";
+        if (isConsteval)
+          Diag(D.getDeclSpec().getConstevalSpecLoc(), diag::err_constexpr_dtor)
+              << "consteval";
+      }
+      if (isConsteval) {
+        if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD)) {
+          if (MD->getOverloadedOperator() == OO_New ||
+              MD->getOverloadedOperator() == OO_Array_New ||
+              MD->getOverloadedOperator() == OO_Delete ||
+              MD->getOverloadedOperator() == OO_Array_Delete) {
+            Diag(D.getDeclSpec().getConstevalSpecLoc(),
+                 diag::err_invalid_consteval_decl_kind)
+                << MD->getOverloadedOperator() - OO_New;
+            NewFD->setConsteval(false);
+            NewFD->setConstexpr(true);
+          }
+        }
+      }
     }
 
     // If __module_private__ was specified, mark the function accordingly.
@@ -9527,6 +9554,7 @@
     DeletedFuncs = 5,
     DefaultedFuncs = 6,
     ConstexprFuncs = 7,
+    ConstevalFuncs = 8,
   };
   enum Different {
     CallingConv = 0,
@@ -9534,7 +9562,8 @@
     ConstexprSpec = 2,
     InlineSpec = 3,
     StorageClass = 4,
-    Linkage = 5
+    Linkage = 5,
+    ConstevalSpec = 6
   };
 
   bool IsCPUSpecificCPUDispatchMVType =
@@ -9599,10 +9628,15 @@
     return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
            << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs;
 
-  if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch ||
-                               MVType == MultiVersionKind::CPUSpecific))
-    return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
-           << IsCPUSpecificCPUDispatchMVType << ConstexprFuncs;
+  if (MVType == MultiVersionKind::CPUDispatch ||
+      MVType == MultiVersionKind::CPUSpecific) {
+    if (NewFD->isConstexpr())
+      return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
+             << IsCPUSpecificCPUDispatchMVType << ConstexprFuncs;
+    if (NewFD->isConsteval())
+      return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
+             << IsCPUSpecificCPUDispatchMVType << ConstevalFuncs;
+  }
 
   QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
   const auto *NewType = cast<FunctionType>(NewQType);
@@ -9637,6 +9671,10 @@
       return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
              << ConstexprSpec;
 
+    if (OldFD->isConsteval() != NewFD->isConsteval())
+      return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
+             << ConstevalSpec;
+
     if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified())
       return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
              << InlineSpec;
@@ -10383,9 +10421,14 @@
   }
   if (FD->isConstexpr()) {
     Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
-      << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
+        << 0 << FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
     FD->setConstexpr(false);
   }
+  if (FD->isConsteval()) {
+    Diag(DS.getConstevalSpecLoc(), diag::err_constexpr_main)
+        << 1 << FixItHint::CreateRemoval(DS.getConstevalSpecLoc());
+    FD->setConsteval(false);
+  }
 
   if (getLangOpts().OpenCL) {
     Diag(FD->getLocation(), diag::err_opencl_no_main)
@@ -13157,7 +13200,7 @@
   // We cannot skip the body of a function with an undeduced return type,
   // because any callers of that function need to know the type.
   if (const FunctionDecl *FD = D->getAsFunction()) {
-    if (FD->isConstexpr())
+    if (FD->isConstexprOrConsteval())
       return false;
     // We can't simply call Type::isUndeducedType here, because inside template
     // auto can be deduced to a dependent type, which is not considered
@@ -13486,7 +13529,8 @@
       ActivePolicy = &WP;
     }
 
-    if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+    if (!IsInstantiation && FD && FD->isConstexprOrConsteval() &&
+        !FD->isInvalidDecl() &&
         (!CheckConstexprFunctionDecl(FD) ||
          !CheckConstexprFunctionBody(FD, Body)))
       FD->setInvalidDecl();
Index: clang/lib/Sema/SemaCoroutine.cpp
===================================================================
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -210,6 +210,7 @@
     DiagConstexpr,
     DiagAutoRet,
     DiagVarargs,
+    DiagConsteval
   };
   bool Diagnosed = false;
   auto DiagInvalid = [&](InvalidFuncDiag ID) {
@@ -245,6 +246,8 @@
   // [...] an await-expression [...] a yield-expression."
   if (FD->isConstexpr())
     DiagInvalid(DiagConstexpr);
+  if (FD->isConsteval())
+    DiagInvalid(DiagConsteval);
   // [dcl.spec.auto]p15: "A function declared with a return type that uses a
   // placeholder type shall not be a coroutine."
   if (FD->getReturnType()->isUndeducedType())
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -483,10 +483,11 @@
 /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
 /// If there is already an implicit cast, merge into the existing one.
 /// The result is of the given category.
-ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
-                                   CastKind Kind, ExprValueKind VK,
+ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, CastKind Kind,
+                                   ExprValueKind VK,
                                    const CXXCastPath *BasePath,
-                                   CheckedConversionKind CCK) {
+                                   CheckedConversionKind CCK,
+                                   bool isCastForCall) {
 #ifndef NDEBUG
   if (VK == VK_RValue && !E->isRValue()) {
     switch (Kind) {
@@ -533,6 +534,10 @@
     }
   }
 
+  if (Kind == CK_FunctionToPointerDecay && !isCastForCall &&
+      CheckInvalidConstevalTakeAddress(E))
+    return ExprError();
+
   return ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK);
 }
 
Index: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -1039,6 +1039,18 @@
   return false;
 }
 
+bool DeclSpec::SetConstevalSpec(SourceLocation Loc, const char *&PrevSpec,
+                                unsigned &DiagID) {
+  if (Consteval_specified) {
+    DiagID = diag::ext_warn_duplicate_declspec;
+    PrevSpec = "consteval";
+    return true;
+  }
+  Consteval_specified = true;
+  ConstevalLoc = Loc;
+  return false;
+}
+
 void DeclSpec::SaveWrittenBuiltinSpecs() {
   writtenBS.Sign = getTypeSpecSign();
   writtenBS.Width = getTypeSpecWidth();
@@ -1311,6 +1323,14 @@
     ClearStorageClassSpecs();
   }
 
+  // C++2a [dcl.spec]p2: The constexpr and consteval decl-specifiers shall not
+  // both appear in a decl-specifier-seq.
+  if (isConstevalSpecified() && isConstexprSpecified()) {
+    S.Diag(ConstexprLoc, diag::err_incompatible_constexpr_consteval)
+        << FixItHint::CreateRemoval(ConstexprLoc);
+    Constexpr_specified = false;
+  }
+
   // C++11 [dcl.fct.spec]p5:
   //   The virtual specifier shall be used only in the initial
   //   declaration of a non-static class member function;
Index: clang/lib/Parse/ParseTentative.cpp
===================================================================
--- clang/lib/Parse/ParseTentative.cpp
+++ clang/lib/Parse/ParseTentative.cpp
@@ -1197,6 +1197,7 @@
 ///           'friend'
 ///           'typedef'
 /// [C++11]   'constexpr'
+/// [C++20]   'consteval'
 /// [GNU]     attributes declaration-specifiers[opt]
 ///
 ///         storage-class-specifier:
@@ -1379,9 +1380,11 @@
     //   'friend'
     //   'typedef'
     //   'constexpr'
+    //   'consteval'
   case tok::kw_friend:
   case tok::kw_typedef:
   case tok::kw_constexpr:
+  case tok::kw_consteval:
     // storage-class-specifier
   case tok::kw_register:
   case tok::kw_static:
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1038,10 +1038,11 @@
   return true;
 }
 
-static void
-tryConsumeMutableOrConstexprToken(Parser &P, SourceLocation &MutableLoc,
-                                  SourceLocation &ConstexprLoc,
-                                  SourceLocation &DeclEndLoc) {
+static void tryConsumeLambdaSpecifierToken(Parser &P,
+                                           SourceLocation &MutableLoc,
+                                           SourceLocation &ConstexprLoc,
+                                           SourceLocation &ConstevalLoc,
+                                           SourceLocation &DeclEndLoc) {
   assert(MutableLoc.isInvalid());
   assert(ConstexprLoc.isInvalid());
   // Consume constexpr-opt mutable-opt in any sequence, and set the DeclEndLoc
@@ -1069,6 +1070,20 @@
       ConstexprLoc = P.ConsumeToken();
       DeclEndLoc = ConstexprLoc;
       break /*switch*/;
+    case tok::identifier:
+      if (P.getCurToken().getIdentifierInfo()->getName() != "consteval")
+        return;
+      // Diagnostic has already been emitted by the Lexer.
+      LLVM_FALLTHROUGH;
+    case tok::kw_consteval:
+      if (ConstevalLoc.isValid()) {
+        P.Diag(P.getCurToken().getLocation(),
+               diag::err_lambda_decl_specifier_repeated)
+            << 2 << FixItHint::CreateRemoval(P.getCurToken().getLocation());
+      }
+      ConstevalLoc = P.ConsumeToken();
+      DeclEndLoc = ConstevalLoc;
+      break /*switch*/;
     default:
       return;
     }
@@ -1090,6 +1105,18 @@
   }
 }
 
+static void addConstevalToLambdaDeclSpecifier(Parser &P,
+                                              SourceLocation ConstevalLoc,
+                                              DeclSpec &DS) {
+  if (ConstevalLoc.isValid()) {
+    const char *PrevSpec = nullptr;
+    unsigned DiagID = 0;
+    DS.SetConstevalSpec(ConstevalLoc, PrevSpec, DiagID);
+    assert(PrevSpec == nullptr && DiagID == 0 &&
+           "Consteval cannot have been set previously!");
+  }
+}
+
 /// ParseLambdaExpressionAfterIntroducer - Parse the rest of a lambda
 /// expression.
 ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
@@ -1200,14 +1227,17 @@
     // compatible with MSVC.
     MaybeParseMicrosoftDeclSpecs(Attr, &DeclEndLoc);
 
-    // Parse mutable-opt and/or constexpr-opt, and update the DeclEndLoc.
+    // Parse mutable-opt and/or constexpr-opt or consteval-opt, and update the
+    // DeclEndLoc.
     SourceLocation MutableLoc;
     SourceLocation ConstexprLoc;
-    tryConsumeMutableOrConstexprToken(*this, MutableLoc, ConstexprLoc,
-                                      DeclEndLoc);
+    SourceLocation ConstevalLoc;
+    tryConsumeLambdaSpecifierToken(*this, MutableLoc, ConstexprLoc,
+                                   ConstevalLoc, DeclEndLoc);
 
     addConstexprToLambdaDeclSpecifier(*this, ConstexprLoc, DS);
-
+    addConstevalToLambdaDeclSpecifier(*this, ConstevalLoc, DS);
+    DS.Finish(Actions, Actions.getPrintingPolicy());
     // Parse exception-specification[opt].
     ExceptionSpecificationType ESpecType = EST_None;
     SourceRange ESpecRange;
@@ -1259,7 +1289,7 @@
                       TrailingReturnType),
                   std::move(Attr), DeclEndLoc);
   } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute,
-                         tok::kw_constexpr) ||
+                         tok::kw_constexpr, tok::kw_consteval) ||
              (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
     // It's common to forget that one needs '()' before 'mutable', an attribute
     // specifier, or the result type. Deal with this.
@@ -1270,6 +1300,9 @@
     case tok::kw___attribute:
     case tok::l_square: TokKind = 2; break;
     case tok::kw_constexpr: TokKind = 3; break;
+    case tok::kw_consteval:
+      TokKind = 4;
+      break;
     default: llvm_unreachable("Unknown token kind");
     }
 
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -2477,18 +2477,29 @@
   // Issue diagnostic and remove function specifier if present.
   if (Specs & DeclSpec::PQ_FunctionSpecifier) {
     if (DS.isInlineSpecified())
-      Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
+      Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_specifier)
+          << "function";
     if (DS.isVirtualSpecified())
-      Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
+      Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_specifier)
+          << "function";
     if (DS.hasExplicitSpecifier())
-      Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
+      Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_specifier)
+          << "function";
     DS.ClearFunctionSpecs();
   }
 
-  // Issue diagnostic and remove constexpr specifier if present.
-  if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
-    Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
-    DS.ClearConstexprSpec();
+  // Issue diagnostic and remove constexpr or consteval specifier if present.
+  if (DSC != DeclSpecContext::DSC_condition) {
+    if (DS.isConstexprSpecified()) {
+      Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_specifier)
+          << "constexpr";
+      DS.ClearConstexprSpec();
+    }
+    if (DS.isConstevalSpecified()) {
+      Diag(DS.getConstevalSpecLoc(), diag::err_typename_invalid_specifier)
+          << "consteval";
+      DS.ClearConstevalSpec();
+    }
   }
 }
 
@@ -2982,6 +2993,7 @@
 /// [OpenCL] '__kernel'
 ///       'friend': [C++ dcl.friend]
 ///       'constexpr': [C++0x dcl.constexpr]
+///       'consteval': [C++2a dcl.constexpr]
 void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
                                         const ParsedTemplateInfo &TemplateInfo,
                                         AccessSpecifier AS,
@@ -3624,6 +3636,10 @@
       isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
       break;
 
+    case tok::kw_consteval:
+      isInvalid = DS.SetConstevalSpec(Loc, PrevSpec, DiagID);
+      break;
+
     // type-specifier
     case tok::kw_short:
       isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec,
@@ -5027,6 +5043,9 @@
   case tok::annot_decltype:
   case tok::kw_constexpr:
 
+    // C++20 consteval.
+  case tok::kw_consteval:
+
     // C11 _Atomic
   case tok::kw__Atomic:
     return true;
Index: clang/lib/Analysis/ReachableCode.cpp
===================================================================
--- clang/lib/Analysis/ReachableCode.cpp
+++ clang/lib/Analysis/ReachableCode.cpp
@@ -213,7 +213,7 @@
     case Stmt::CallExprClass: {
       const FunctionDecl *Callee =
         dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
-      return Callee ? Callee->isConstexpr() : false;
+      return Callee ? Callee->isConstexprOrConsteval() : false;
     }
     case Stmt::DeclRefExprClass:
       return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -255,9 +255,12 @@
 
   if (D->isInvalidDecl())
     OS << " invalid";
-  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     if (FD->isConstexpr())
       OS << " constexpr";
+    if (FD->isConsteval())
+      OS << " consteval";
+  }
 
   if (!isa<FunctionDecl>(*D)) {
     const auto *MD = dyn_cast<ObjCMethodDecl>(D);
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4347,7 +4347,7 @@
   // Value-initialization does not call a trivial default constructor, so such a
   // call is a core constant expression whether or not the constructor is
   // constexpr.
-  if (!CD->isConstexpr() && !IsValueInitialization) {
+  if (!CD->isConstexprOrConsteval() && !IsValueInitialization) {
     if (Info.getLangOpts().CPlusPlus11) {
       // FIXME: If DiagDecl is an implicitly-declared special member function,
       // we should be much more explicit about why it's not constexpr.
@@ -4370,7 +4370,7 @@
   // Potential constant expressions can contain calls to declared, but not yet
   // defined, constexpr functions.
   if (Info.checkingPotentialConstantExpression() && !Definition &&
-      Declaration->isConstexpr())
+      Declaration->isConstexprOrConsteval())
     return false;
 
   // Bail out if the function declaration itself is invalid.  We will
@@ -4382,7 +4382,7 @@
   }
 
   // Can we evaluate this function call?
-  if (Definition && Definition->isConstexpr() &&
+  if (Definition && Definition->isConstexprOrConsteval() &&
       !Definition->isInvalidDecl() && Body)
     return true;
 
@@ -4394,7 +4394,7 @@
     auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
     if (CD && CD->isInheritingConstructor()) {
       auto *Inherited = CD->getInheritedConstructor().getConstructor();
-      if (!Inherited->isConstexpr())
+      if (!Inherited->isConstexprOrConsteval())
         DiagDecl = CD = Inherited;
     }
 
@@ -4406,7 +4406,7 @@
         << CD->getInheritedConstructor().getConstructor()->getParent();
     else
       Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
-        << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+          << DiagDecl->isConstexprOrConsteval() << (bool)CD << DiagDecl;
     Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
   } else {
     Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
Index: clang/lib/AST/DeclPrinter.cpp
===================================================================
--- clang/lib/AST/DeclPrinter.cpp
+++ clang/lib/AST/DeclPrinter.cpp
@@ -610,7 +610,10 @@
     if (D->isInlineSpecified())  Out << "inline ";
     if (D->isVirtualAsWritten()) Out << "virtual ";
     if (D->isModulePrivate())    Out << "__module_private__ ";
-    if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
+    if (D->isConstexpr() && !D->isExplicitlyDefaulted())
+      Out << "constexpr ";
+    if (D->isConsteval() && !D->isExplicitlyDefaulted())
+      Out << "consteval ";
     ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
     if (ExplicitSpec.isSpecified())
       printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -730,7 +730,7 @@
 
       if (Constructor->isUserProvided())
         data().UserProvidedDefaultConstructor = true;
-      if (Constructor->isConstexpr())
+      if (Constructor->isConstexprOrConsteval())
         data().HasConstexprDefaultConstructor = true;
       if (Constructor->isDefaulted())
         data().HasDefaultedDefaultConstructor = true;
@@ -767,7 +767,8 @@
     //   [...] has at least one constexpr constructor or constructor template
     //   (possibly inherited from a base class) that is not a copy or move
     //   constructor [...]
-    if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
+    if ((Constructor->isConstexprOrConsteval()) &&
+        !Constructor->isCopyOrMoveConstructor())
       data().HasConstexprNonCopyMoveConstructor = true;
   }
 
@@ -1301,7 +1302,7 @@
   if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
     if (Constructor->isDefaultConstructor()) {
       SMKind |= SMF_DefaultConstructor;
-      if (Constructor->isConstexpr())
+      if (Constructor->isConstexprOrConsteval())
         data().HasConstexprDefaultConstructor = true;
     }
     if (Constructor->isCopyConstructor())
@@ -1986,22 +1987,22 @@
   return nullptr;
 }
 
-CXXMethodDecl *
-CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
-                      SourceLocation StartLoc,
-                      const DeclarationNameInfo &NameInfo,
-                      QualType T, TypeSourceInfo *TInfo,
-                      StorageClass SC, bool isInline,
-                      bool isConstexpr, SourceLocation EndLocation) {
-  return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo,
-                                   T, TInfo, SC, isInline, isConstexpr,
-                                   EndLocation);
+CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+                                     SourceLocation StartLoc,
+                                     const DeclarationNameInfo &NameInfo,
+                                     QualType T, TypeSourceInfo *TInfo,
+                                     StorageClass SC, bool isInline,
+                                     bool isConstexpr, bool isConsteval,
+                                     SourceLocation EndLocation) {
+  return new (C, RD)
+      CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC,
+                    isInline, isConstexpr, isConsteval, EndLocation);
 }
 
 CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
-  return new (C, ID) CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(),
-                                   DeclarationNameInfo(), QualType(), nullptr,
-                                   SC_None, false, false, SourceLocation());
+  return new (C, ID) CXXMethodDecl(
+      CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(),
+      QualType(), nullptr, SC_None, false, false, false, SourceLocation());
 }
 
 CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
@@ -2358,9 +2359,10 @@
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
-    bool isConstexpr, InheritedConstructor Inherited)
+    bool isConstexpr, bool isConsteval, InheritedConstructor Inherited)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
-                    SC_None, isInline, isConstexpr, SourceLocation()) {
+                    SC_None, isInline, isConstexpr, isConsteval,
+                    SourceLocation()) {
   setNumCtorInitializers(0);
   setInheritingConstructor(static_cast<bool>(Inherited));
   setImplicit(isImplicitlyDeclared);
@@ -2383,7 +2385,7 @@
           isInheritingConstructor, hasTraillingExplicit);
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      ExplicitSpecifier(), false, false, false, InheritedConstructor());
+      ExplicitSpecifier(), false, false, false, false, InheritedConstructor());
   Result->setInheritingConstructor(isInheritingConstructor);
   Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
       hasTraillingExplicit;
@@ -2395,16 +2397,16 @@
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
     ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
-    bool isConstexpr, InheritedConstructor Inherited) {
+    bool isConstexpr, bool isConsteval, InheritedConstructor Inherited) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConstructorName &&
          "Name must refer to a constructor");
   unsigned Extra =
       additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
           Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
-  return new (C, RD, Extra)
-      CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
-                         isImplicitlyDeclared, isConstexpr, Inherited);
+  return new (C, RD, Extra) CXXConstructorDecl(
+      C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline, isImplicitlyDeclared,
+      isConstexpr, isConsteval, Inherited);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2557,19 +2559,20 @@
 CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) CXXConversionDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      false, ExplicitSpecifier(), false, SourceLocation());
+      false, ExplicitSpecifier(), false, false, SourceLocation());
 }
 
 CXXConversionDecl *CXXConversionDecl::Create(
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-    bool isInline, ExplicitSpecifier ES, bool isConstexpr,
+    bool isInline, ExplicitSpecifier ES, bool isConstexpr, bool isConsteval,
     SourceLocation EndLocation) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConversionFunctionName &&
          "Name must refer to a conversion function");
-  return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
-                                       isInline, ES, isConstexpr, EndLocation);
+  return new (C, RD)
+      CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES,
+                        isConstexpr, isConsteval, EndLocation);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2704,7 +2704,8 @@
                            SourceLocation StartLoc,
                            const DeclarationNameInfo &NameInfo, QualType T,
                            TypeSourceInfo *TInfo, StorageClass S,
-                           bool isInlineSpecified, bool isConstexprSpecified)
+                           bool isInlineSpecified, bool isConstexprSpecified,
+                           bool isConstevalSpecified)
     : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
                      StartLoc),
       DeclContext(DK), redeclarable_base(C), ODRHash(0),
@@ -2725,6 +2726,7 @@
   FunctionDeclBits.HasImplicitReturnZero = false;
   FunctionDeclBits.IsLateTemplateParsed = false;
   FunctionDeclBits.IsConstexpr = isConstexprSpecified;
+  FunctionDeclBits.IsConsteval = isConstevalSpecified;
   FunctionDeclBits.InstantiationIsPending = false;
   FunctionDeclBits.UsesSEHTry = false;
   FunctionDeclBits.HasSkippedBody = false;
@@ -4517,17 +4519,15 @@
   return new (C, ID) ImplicitParamDecl(C, QualType(), ImplicitParamKind::Other);
 }
 
-FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
-                                   SourceLocation StartLoc,
-                                   const DeclarationNameInfo &NameInfo,
-                                   QualType T, TypeSourceInfo *TInfo,
-                                   StorageClass SC,
-                                   bool isInlineSpecified,
-                                   bool hasWrittenPrototype,
-                                   bool isConstexprSpecified) {
-  FunctionDecl *New =
-      new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo,
-                               SC, isInlineSpecified, isConstexprSpecified);
+FunctionDecl *
+FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+                     const DeclarationNameInfo &NameInfo, QualType T,
+                     TypeSourceInfo *TInfo, StorageClass SC,
+                     bool isInlineSpecified, bool hasWrittenPrototype,
+                     bool isConstexprSpecified, bool isConstevalSpecified) {
+  FunctionDecl *New = new (C, DC) FunctionDecl(
+      Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, isInlineSpecified,
+      isConstexprSpecified, isConstevalSpecified);
   New->setHasWrittenPrototype(hasWrittenPrototype);
   return New;
 }
@@ -4535,7 +4535,7 @@
 FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(),
                                   DeclarationNameInfo(), QualType(), nullptr,
-                                  SC_None, false, false);
+                                  SC_None, false, false, false);
 }
 
 BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3089,7 +3089,8 @@
             ExplicitSpecifier(
                 ExplicitExpr,
                 FromConstructor->getExplicitSpecifier().getKind()),
-            D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
+            D->isInlineSpecified(), D->isImplicit(), D->isConstexpr(),
+            D->isConsteval()))
       return ToFunction;
   } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
 
@@ -3127,19 +3128,20 @@
             ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
             ExplicitSpecifier(ExplicitExpr,
                               FromConversion->getExplicitSpecifier().getKind()),
-            D->isConstexpr(), SourceLocation()))
+            D->isConstexpr(), D->isConsteval(), SourceLocation()))
       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->isInlineSpecified(), D->isConstexpr(), SourceLocation()))
+            Method->isInlineSpecified(), D->isConstexpr(), D->isConsteval(),
+            SourceLocation()))
       return ToFunction;
   } else {
-    if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC,
-                                ToInnerLocStart, NameInfo, T, TInfo,
-                                D->getStorageClass(), D->isInlineSpecified(),
-                                D->hasWrittenPrototype(), D->isConstexpr()))
+    if (GetImportedOrCreateDecl(
+            ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart,
+            NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(),
+            D->hasWrittenPrototype(), D->isConstexpr(), D->isConsteval()))
       return ToFunction;
   }
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -978,9 +978,12 @@
     /// fields, such as a SIZE operator in MS-style inline assembly.
     UnevaluatedAbstract,
 
-    /// The current context is "potentially evaluated" in C++11 terms,
-    /// but the expression is evaluated at compile-time (like the values of
-    /// cases in a switch statement).
+    /// The current context is either of:
+    /// - "potentially evaluated" in C++11 terms,
+    ///   but the expression is evaluated at compile-time (like the values of
+    ///   cases in a switch statement).
+    /// - "immediate function context" in C++2a terms, a call to a function
+    ///   marked as consteval
     ConstantEvaluated,
 
     /// The current expression is potentially evaluated at run time,
@@ -4046,6 +4049,16 @@
 
   void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
 
+  /// CheckInvalidConstevalCall - detect and diagnose invalid calls to
+  /// consteval function.
+  /// return true if the call is invalid.
+  bool CheckInvalidConstevalCall(FunctionDecl *FDecl, SourceLocation Loc,
+                                 ArrayRef<Expr *> Args, Expr *This = nullptr);
+
+  /// CheckInvalidConstevalTakeAddress - detect and diagnose if Input is a
+  /// DeclRef to a consteval function. return true if the operation is forbiden.
+  bool CheckInvalidConstevalTakeAddress(Expr *Input);
+
   bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const;
 
   /// If it's a file scoped decl that must warn if not used, keep track
@@ -5678,12 +5691,11 @@
                                          LambdaCaptureDefault CaptureDefault);
 
   /// Start the definition of a lambda expression.
-  CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
-                                       SourceRange IntroducerRange,
-                                       TypeSourceInfo *MethodType,
-                                       SourceLocation EndLoc,
-                                       ArrayRef<ParmVarDecl *> Params,
-                                       bool IsConstexprSpecified);
+  CXXMethodDecl *
+  startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange,
+                        TypeSourceInfo *MethodType, SourceLocation EndLoc,
+                        ArrayRef<ParmVarDecl *> Params,
+                        bool IsConstexprSpecified, bool IsConstevalSpecified);
 
   /// Endow the lambda scope info with the relevant properties.
   void buildLambdaScope(sema::LambdaScopeInfo *LSI,
@@ -9610,11 +9622,12 @@
   /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
   /// cast.  If there is already an implicit cast, merge into the existing one.
   /// If isLvalue, the result of the cast is an lvalue.
-  ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
-                               ExprValueKind VK = VK_RValue,
-                               const CXXCastPath *BasePath = nullptr,
-                               CheckedConversionKind CCK
-                                  = CCK_ImplicitConversion);
+  ExprResult
+  ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
+                    ExprValueKind VK = VK_RValue,
+                    const CXXCastPath *BasePath = nullptr,
+                    CheckedConversionKind CCK = CCK_ImplicitConversion,
+                    bool isCastForCall = false);
 
   /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
   /// to the conversion from scalar type ScalarTy to the Boolean type.
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -365,6 +365,9 @@
   // constexpr-specifier
   unsigned Constexpr_specified : 1;
 
+  // consteval-specifier
+  unsigned Consteval_specified : 1;
+
   union {
     UnionParsedType TypeRep;
     Decl *DeclRep;
@@ -398,7 +401,7 @@
   SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
   SourceLocation FS_explicitCloseParenLoc;
   SourceLocation FS_forceinlineLoc;
-  SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
+  SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConstevalLoc;
   SourceLocation TQ_pipeLoc;
 
   WrittenBuiltinSpecs writtenBS;
@@ -434,8 +437,8 @@
         FS_inline_specified(false), FS_forceinline_specified(false),
         FS_virtual_specified(false), FS_noreturn_specified(false),
         Friend_specified(false), Constexpr_specified(false),
-        FS_explicit_specifier(), Attrs(attrFactory), writtenBS(),
-        ObjCQualifiers(nullptr) {}
+        Consteval_specified(false), FS_explicit_specifier(), Attrs(attrFactory),
+        writtenBS(), ObjCQualifiers(nullptr) {}
 
   // storage-class-specifier
   SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
@@ -721,6 +724,9 @@
   bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
                         unsigned &DiagID);
 
+  bool SetConstevalSpec(SourceLocation Loc, const char *&PrevSpec,
+                        unsigned &DiagID);
+
   bool isFriendSpecified() const { return Friend_specified; }
   SourceLocation getFriendSpecLoc() const { return FriendLoc; }
 
@@ -735,6 +741,14 @@
     ConstexprLoc = SourceLocation();
   }
 
+  bool isConstevalSpecified() const { return Consteval_specified; }
+  SourceLocation getConstevalSpecLoc() const { return ConstevalLoc; }
+
+  void ClearConstevalSpec() {
+    Consteval_specified = false;
+    ConstevalLoc = SourceLocation();
+  }
+
   AttributePool &getAttributePool() const {
     return Attrs.getPool();
   }
Index: clang/include/clang/Basic/TokenKinds.def
===================================================================
--- clang/include/clang/Basic/TokenKinds.def
+++ clang/include/clang/Basic/TokenKinds.def
@@ -387,6 +387,9 @@
 // C++ char8_t proposal
 CXX2A_KEYWORD(char8_t               , CHAR8SUPPORT)
 
+// C++ consteval proposal
+CXX2A_KEYWORD(consteval             , 0)
+
 // C11 Extension
 KEYWORD(_Float16                    , KEYALL)
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -695,7 +695,7 @@
   "'main' is not allowed to be declared _Noreturn">, InGroup<Main>;
 def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
 def err_constexpr_main : Error<
-  "'main' is not allowed to be declared constexpr">;
+  "'main' is not allowed to be declared %select{constexpr|consteval}0">;
 def err_deleted_main : Error<"'main' is not allowed to be deleted">;
 def err_mainlike_template_decl : Error<"%0 cannot be a template">;
 def err_main_returns_nonint : Error<"'main' must return 'int'">;
@@ -2283,7 +2283,7 @@
   "initialization statement is not supported when iterating over Objective-C "
   "collection">;
 
-// C++11 constexpr
+// C++11 constexpr and C++2a consteval
 def warn_cxx98_compat_constexpr : Warning<
   "'constexpr' specifier is incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
@@ -2292,6 +2292,14 @@
   "'constexpr' non-static member function will not be implicitly 'const' "
   "in C++14; add 'const' to avoid a change in behavior">,
   InGroup<DiagGroup<"constexpr-not-const">>;
+def err_incompatible_constexpr_consteval : Error<
+  "constexpr specifier is incompatible with consteval specifier">;
+def err_consteval_cannot_be_constant_eval : Error<
+  "call to %0 cannot be constant evaluated">;
+def note_argument_n_cannot_be_constant_eval : Note<
+  "argument %0 cannot be constant evaluated">;
+def note_not_constexpr_this : Note<
+  "call to member of non-constexpr value">;
 def err_invalid_constexpr : Error<
   "%select{function parameter|typedef|non-static data member}0 "
   "cannot be constexpr">;
@@ -2299,7 +2307,11 @@
   "constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
 def err_constexpr_tag : Error<
   "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
-def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
+def err_constexpr_dtor : Error<"destructor cannot be marked %0">;
+def err_invalid_consteval_decl_kind : Error<
+  "operator %select{new|delete|new[]|delete[]}0 cannot be marked consteval">;
+def err_take_adress_of_consteval_decl : Error<
+  "taking address of a %0">;
 def err_constexpr_no_declarators : Error<
   "constexpr can only be used in variable and function declarations">;
 def err_invalid_constexpr_var_decl : Error<
@@ -2311,8 +2323,8 @@
 def err_constexpr_var_requires_const_init : Error<
   "constexpr variable %0 must be initialized by a constant expression">;
 def err_constexpr_redecl_mismatch : Error<
-  "%select{non-constexpr declaration of %0 follows constexpr declaration"
-  "|constexpr declaration of %0 follows non-constexpr declaration}1">;
+  "%select{non-%2 declaration of %0 follows %2 declaration"
+  "|%2 declaration of %0 follows non-%2 declaration}1">;
 def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
 def err_constexpr_virtual_base : Error<
   "constexpr %select{member function|constructor}0 not allowed in "
@@ -9380,7 +9392,7 @@
   "'%1' cannot be used in %select{a constructor|a destructor"
   "|a copy assignment operator|a move assignment operator|the 'main' function"
   "|a constexpr function|a function with a deduced return type"
-  "|a varargs function}0">;
+  "|a varargs function|a consteval function}0">;
 def err_implied_coroutine_type_not_found : Error<
   "%0 type was not found; include <experimental/coroutine> before defining "
   "a coroutine">;
@@ -9618,7 +9630,7 @@
   "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not "
   "yet support %select{function templates|virtual functions|"
   "deduced return types|constructors|destructors|deleted functions|"
-  "defaulted functions|constexpr functions}1">;
+  "defaulted functions|constexpr functions|consteval functions}1">;
 def err_multiversion_not_allowed_on_main : Error<
   "'main' cannot be a multiversioned function">;
 def err_multiversion_not_supported : Error<
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -355,10 +355,8 @@
   "type name requires a specifier or qualifier">;
 def err_typename_invalid_storageclass : Error<
   "type name does not allow storage class to be specified">;
-def err_typename_invalid_functionspec : Error<
-  "type name does not allow function specifier to be specified">;
-def err_typename_invalid_constexpr : Error<
-  "type name does not allow constexpr specifier to be specified">;
+def err_typename_invalid_specifier : Error<
+  "type name does not allow %0 specifier to be specified">;
 def err_typename_identifiers_only : Error<
   "typename is allowed for identifiers only">;
 
@@ -873,9 +871,9 @@
   InGroup<CXX98Compat>, DefaultIgnore;
 def err_lambda_missing_parens : Error<
   "lambda requires '()' before %select{'mutable'|return type|"
-  "attribute specifier|'constexpr'}0">;
+  "attribute specifier|'constexpr'|'consteval'}0">;
 def err_lambda_decl_specifier_repeated : Error<
-  "%select{'mutable'|'constexpr'}0 cannot appear multiple times in a lambda declarator">;
+  "%select{'mutable'|'constexpr'|'consteval'}0 cannot appear multiple times in a lambda declarator">;
 // C++17 lambda expressions
 def err_expected_star_this_capture : Error<
   "expected 'this' following '*' in lambda capture list">;
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -2056,7 +2056,7 @@
                         const DeclarationNameInfo &NameInfo, QualType T,
                         TypeSourceInfo *TInfo, SourceLocation EndLocation)
       : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
-                     SC_None, false, false),
+                     SC_None, false, false, false),
         ExplicitSpec(ES) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
@@ -2111,11 +2111,11 @@
 protected:
   CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD,
                 SourceLocation StartLoc, const DeclarationNameInfo &NameInfo,
-                QualType T, TypeSourceInfo *TInfo,
-                StorageClass SC, bool isInline,
-                bool isConstexpr, SourceLocation EndLocation)
-    : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo,
-                   SC, isInline, isConstexpr) {
+                QualType T, TypeSourceInfo *TInfo, StorageClass SC,
+                bool isInline, bool isConstexpr, bool isConsteval,
+                SourceLocation EndLocation)
+      : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, isInline,
+                     isConstexpr, isConsteval) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
   }
@@ -2123,12 +2123,10 @@
 public:
   static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD,
                                SourceLocation StartLoc,
-                               const DeclarationNameInfo &NameInfo,
-                               QualType T, TypeSourceInfo *TInfo,
-                               StorageClass SC,
-                               bool isInline,
-                               bool isConstexpr,
-                               SourceLocation EndLocation);
+                               const DeclarationNameInfo &NameInfo, QualType T,
+                               TypeSourceInfo *TInfo, StorageClass SC,
+                               bool isInline, bool isConstexpr,
+                               bool isConsteval, SourceLocation EndLocation);
 
   static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
@@ -2564,7 +2562,7 @@
                      const DeclarationNameInfo &NameInfo, QualType T,
                      TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline,
                      bool isImplicitlyDeclared, bool isConstexpr,
-                     InheritedConstructor Inherited);
+                     bool isConsteval, InheritedConstructor Inherited);
 
   void anchor() override;
 
@@ -2616,7 +2614,7 @@
   Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
-         bool isConstexpr,
+         bool isConstexpr, bool isConsteval,
          InheritedConstructor Inherited = InheritedConstructor());
 
   ExplicitSpecifier getExplicitSpecifier() {
@@ -2822,12 +2820,12 @@
   Expr *OperatorDeleteThisArg = nullptr;
 
   CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
-                    const DeclarationNameInfo &NameInfo,
-                    QualType T, TypeSourceInfo *TInfo,
-                    bool isInline, bool isImplicitlyDeclared)
-    : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
-                    SC_None, isInline, /*isConstexpr=*/false, SourceLocation())
-  {
+                    const DeclarationNameInfo &NameInfo, QualType T,
+                    TypeSourceInfo *TInfo, bool isInline,
+                    bool isImplicitlyDeclared)
+      : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
+                      SC_None, isInline, /*isConstexpr=*/false,
+                      /*isConsteval=*/false, SourceLocation()) {
     setImplicit(isImplicitlyDeclared);
   }
 
@@ -2878,9 +2876,10 @@
   CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                     const DeclarationNameInfo &NameInfo, QualType T,
                     TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES,
-                    bool isConstexpr, SourceLocation EndLocation)
+                    bool isConstexpr, bool isConsteval,
+                    SourceLocation EndLocation)
       : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
-                      SC_None, isInline, isConstexpr, EndLocation),
+                      SC_None, isInline, isConstexpr, isConsteval, EndLocation),
         ExplicitSpec(ES) {}
   void anchor() override;
 
@@ -2896,7 +2895,7 @@
   Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
          bool isInline, ExplicitSpecifier ES, bool isConstexpr,
-         SourceLocation EndLocation);
+         bool isConsteval, SourceLocation EndLocation);
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
   ExplicitSpecifier getExplicitSpecifier() {
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1492,6 +1492,7 @@
     uint64_t HasImplicitReturnZero : 1;
     uint64_t IsLateTemplateParsed : 1;
     uint64_t IsConstexpr : 1;
+    uint64_t IsConsteval : 1;
     uint64_t InstantiationIsPending : 1;
 
     /// Indicates if the function uses __try.
@@ -1519,7 +1520,7 @@
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 24 };
+  enum { NumFunctionDeclBits = 25 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1536,7 +1537,7 @@
     /// exactly 64 bits and thus the width of NumCtorInitializers
     /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
     /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
-    uint64_t NumCtorInitializers : 24;
+    uint64_t NumCtorInitializers : 23;
     uint64_t IsInheritingConstructor : 1;
 
     /// Whether this constructor has a trail-allocated explicit specifier.
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -1856,7 +1856,7 @@
   FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
                const DeclarationNameInfo &NameInfo, QualType T,
                TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified,
-               bool isConstexprSpecified);
+               bool isConstexprSpecified, bool isConstevalSpecified);
 
   using redeclarable_base = Redeclarable<FunctionDecl>;
 
@@ -1886,29 +1886,23 @@
   using redeclarable_base::getMostRecentDecl;
   using redeclarable_base::isFirstDecl;
 
-  static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
-                              SourceLocation StartLoc, SourceLocation NLoc,
-                              DeclarationName N, QualType T,
-                              TypeSourceInfo *TInfo,
-                              StorageClass SC,
-                              bool isInlineSpecified = false,
-                              bool hasWrittenPrototype = true,
-                              bool isConstexprSpecified = false) {
+  static FunctionDecl *
+  Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+         SourceLocation NLoc, DeclarationName N, QualType T,
+         TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified = false,
+         bool hasWrittenPrototype = true, bool isConstexprSpecified = false,
+         bool isConstevalSpecified = false) {
     DeclarationNameInfo NameInfo(N, NLoc);
-    return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
-                                SC,
+    return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC,
                                 isInlineSpecified, hasWrittenPrototype,
-                                isConstexprSpecified);
+                                isConstexprSpecified, isConstevalSpecified);
   }
 
-  static FunctionDecl *Create(ASTContext &C, DeclContext *DC,
-                              SourceLocation StartLoc,
-                              const DeclarationNameInfo &NameInfo,
-                              QualType T, TypeSourceInfo *TInfo,
-                              StorageClass SC,
-                              bool isInlineSpecified,
-                              bool hasWrittenPrototype,
-                              bool isConstexprSpecified = false);
+  static FunctionDecl *
+  Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+         const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+         StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype,
+         bool isConstexprSpecified = false, bool isConstevalSpecified = false);
 
   static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
@@ -2108,6 +2102,12 @@
   bool isConstexpr() const { return FunctionDeclBits.IsConstexpr; }
   void setConstexpr(bool IC) { FunctionDeclBits.IsConstexpr = IC; }
 
+  /// Whether this is a (C++2a) consteval function or consteval constructor.
+  bool isConsteval() const { return FunctionDeclBits.IsConsteval; }
+  void setConsteval(bool IC) { FunctionDeclBits.IsConsteval = IC; }
+
+  bool isConstexprOrConsteval() const { return isConstexpr() || isConsteval(); }
+
   /// Whether the instantiation of this function is pending.
   /// This bit is set when the decision to instantiate this function is made
   /// and unset if and when the function body is created. That leaves out
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to