From 396a5ba51e9e47f818a749ec3f2368e4fea6a67f Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Wed, 17 Jul 2024 14:08:51 +0100 Subject: [PATCH] [Clang] Add attribute for consteval builtin functions (#91894) Builtins with the new `Consteval` attribute will also be marked `Constexpr` and will only be available in C++20 mode where `consteval` makes sense. --- clang/include/clang/Basic/Builtins.def | 1 + clang/include/clang/Basic/Builtins.h | 5 +++++ clang/include/clang/Basic/BuiltinsBase.td | 2 ++ clang/lib/Basic/Builtins.cpp | 3 +++ clang/lib/Sema/SemaDecl.cpp | 15 +++++++++++---- clang/lib/Sema/SemaExpr.cpp | 8 ++++++-- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index d2d500c990b99b..48437c9397570d 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -101,3 +101,4 @@ // M_0, ..., M_k as payload // z -> this is a function in (possibly-versioned) namespace std // E -> this function can be constant evaluated by Clang frontend +// G -> this is a C++20 consteval function diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index f955d21169556a..e85ec5b2dca14e 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -280,6 +280,11 @@ class Context { return strchr(getRecord(ID).Attributes, 'E') != nullptr; } + /// Returns true if this is an immediate (consteval) function + bool isImmediate(unsigned ID) const { + return strchr(getRecord(ID).Attributes, 'G') != nullptr; + } + private: const Info &getRecord(unsigned ID) const; diff --git a/clang/include/clang/Basic/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td index 724747ec76d732..58dee22fc0a450 100644 --- a/clang/include/clang/Basic/BuiltinsBase.td +++ b/clang/include/clang/Basic/BuiltinsBase.td @@ -70,6 +70,8 @@ class VScanfFormat : IndexedAttribute<"S", I>; // Builtin can be constant evaluated def Constexpr : Attribute<"E">; +// Builtin is immediate and must be constant evaluated. Implies Constexpr, and will only be supported in C++20 mode. +def Consteval : Attribute<"EG">; // Builtin kinds // ============= diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index b116abbe034f7a..7116e27cd95463 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -119,6 +119,9 @@ static bool builtinIsSupported(const Builtin::Info &BuiltinInfo, /* CPlusPlus Unsupported */ if (!LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG) return false; + /* consteval Unsupported */ + if (!LangOpts.CPlusPlus20 && strchr(BuiltinInfo.Attributes, 'G') != nullptr) + return false; return true; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 80b5a8cd4bae61..1f2fde12c9d243 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2294,10 +2294,17 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type, Parent = CLinkageDecl; } - FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type, - /*TInfo=*/nullptr, SC_Extern, - getCurFPFeatures().isFPConstrained(), - false, Type->isFunctionProtoType()); + ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified; + if (Context.BuiltinInfo.isImmediate(ID)) { + assert(getLangOpts().CPlusPlus20 && + "consteval builtins should only be available in C++20 mode"); + ConstexprKind = ConstexprSpecKind::Consteval; + } + + FunctionDecl *New = FunctionDecl::Create( + Context, Parent, Loc, Loc, II, Type, /*TInfo=*/nullptr, SC_Extern, + getCurFPFeatures().isFPConstrained(), /*isInlineSpecified=*/false, + Type->isFunctionProtoType(), ConstexprKind); New->setImplicit(); New->addAttr(BuiltinAttr::CreateImplicit(Context, ID)); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d47db14d5dd3b9..8d24e34520e778 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6770,8 +6770,12 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, } // Bail out early if calling a builtin with custom type checking. - if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) - return CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); + if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) { + ExprResult E = CheckBuiltinFunctionCall(FDecl, BuiltinID, TheCall); + if (!E.isInvalid() && Context.BuiltinInfo.isImmediate(BuiltinID)) + E = CheckForImmediateInvocation(E, FDecl); + return E; + } if (getLangOpts().CUDA) { if (Config) {