https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/91894
>From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sun, 12 May 2024 19:48:24 +0100 Subject: [PATCH 1/4] [Clang] Add attribute for consteval builtins; Declare constexpr builtins as constexpr in C++ Also support redeclaring now-constexpr builtins without constexpr --- clang/include/clang/Basic/Builtins.h | 5 +++++ clang/include/clang/Basic/BuiltinsBase.td | 2 ++ clang/lib/Sema/SemaDecl.cpp | 15 +++++++++++---- clang/lib/Sema/SemaDeclCXX.cpp | 18 +++++++++++++----- clang/lib/Sema/SemaExpr.cpp | 8 ++++++-- clang/test/Sema/builtin-redecl.cpp | 15 ++++++++++----- 6 files changed, 47 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index f955d21169556..e85ec5b2dca14 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 724747ec76d73..1196b9e15c10d 100644 --- a/clang/include/clang/Basic/BuiltinsBase.td +++ b/clang/include/clang/Basic/BuiltinsBase.td @@ -70,6 +70,8 @@ class VScanfFormat<int I> : IndexedAttribute<"S", I>; // Builtin can be constant evaluated def Constexpr : Attribute<"E">; +// Builtin is immediate and must be constant evaluated. Implies Constexpr. +def Consteval : Attribute<"EG">; // Builtin kinds // ============= diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fb913034bd836..6b0a04585928a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2409,10 +2409,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 (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) { + ConstexprKind = ConstexprSpecKind::Constexpr; + if (Context.BuiltinInfo.isImmediate(ID)) + 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/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 53238d355ea09..1b558d70f9b48 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -676,11 +676,19 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // template has a constexpr specifier then all its declarations shall // contain the constexpr specifier. if (New->getConstexprKind() != Old->getConstexprKind()) { - Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) - << New << static_cast<int>(New->getConstexprKind()) - << static_cast<int>(Old->getConstexprKind()); - Diag(Old->getLocation(), diag::note_previous_declaration); - Invalid = true; + if (Old->getBuiltinID() && + Old->getConstexprKind() == ConstexprSpecKind::Constexpr && + New->getConstexprKind() == ConstexprSpecKind::Unspecified) { + // Except allow redeclaring a builtin as non-constexpr to match C + // redeclarations which will not be constexpr + New->setConstexprKind(ConstexprSpecKind::Constexpr); + } else { + Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) + << New << static_cast<int>(New->getConstexprKind()) + << static_cast<int>(Old->getConstexprKind()); + Diag(Old->getLocation(), diag::note_previous_declaration); + Invalid = true; + } } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && Old->isDefined(Def) && // If a friend function is inlined but does not have 'inline' diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index bb4b116fd73ca..39aa32526d2b1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -7095,8 +7095,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) { diff --git a/clang/test/Sema/builtin-redecl.cpp b/clang/test/Sema/builtin-redecl.cpp index 323c63e202883..31409a4d46a65 100644 --- a/clang/test/Sema/builtin-redecl.cpp +++ b/clang/test/Sema/builtin-redecl.cpp @@ -14,13 +14,18 @@ void __builtin_va_copy(double d); // expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}} // expected-note@+1 {{'__builtin_va_end' is a builtin with type}} void __builtin_va_end(__builtin_va_list); -// RUN: %clang_cc1 %s -fsyntax-only -verify -// RUN: %clang_cc1 %s -fsyntax-only -verify -x c void __va_start(__builtin_va_list*, ...); + void *__builtin_assume_aligned(const void *, size_t, ...); #ifdef __cplusplus -void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; -#else -void *__builtin_assume_aligned(const void *, size_t, ...); +constexpr void *__builtin_assume_aligned(const void *, size_t, ...); + void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; +constexpr void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; + void *__builtin_assume_aligned(const void *, size_t, ...) throw(); +constexpr void *__builtin_assume_aligned(const void *, size_t, ...) throw(); + +// expected-error@+1 {{constexpr declaration of '__builtin_calloc' follows non-constexpr declaration}} +constexpr void *__builtin_calloc(size_t, size_t); +// expected-note@-1 {{previous declaration is here}} #endif >From 88c68cdffe8bf94d8ecca651d6162e8b601cdc38 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Tue, 14 May 2024 18:29:48 +0100 Subject: [PATCH 2/4] No longer declare constexpr builtins as constexpr --- clang/lib/Sema/SemaDecl.cpp | 6 ++---- clang/lib/Sema/SemaDeclCXX.cpp | 18 +++++------------- clang/test/Sema/builtin-redecl.cpp | 15 +++++---------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6b0a04585928a..7ca02b5bbf624 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2410,10 +2410,8 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type, } ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified; - if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isConstantEvaluated(ID)) { - ConstexprKind = ConstexprSpecKind::Constexpr; - if (Context.BuiltinInfo.isImmediate(ID)) - ConstexprKind = ConstexprSpecKind::Consteval; + if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isImmediate(ID)) { + ConstexprKind = ConstexprSpecKind::Consteval; } FunctionDecl *New = FunctionDecl::Create( diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1b558d70f9b48..53238d355ea09 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -676,19 +676,11 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // template has a constexpr specifier then all its declarations shall // contain the constexpr specifier. if (New->getConstexprKind() != Old->getConstexprKind()) { - if (Old->getBuiltinID() && - Old->getConstexprKind() == ConstexprSpecKind::Constexpr && - New->getConstexprKind() == ConstexprSpecKind::Unspecified) { - // Except allow redeclaring a builtin as non-constexpr to match C - // redeclarations which will not be constexpr - New->setConstexprKind(ConstexprSpecKind::Constexpr); - } else { - Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) - << New << static_cast<int>(New->getConstexprKind()) - << static_cast<int>(Old->getConstexprKind()); - Diag(Old->getLocation(), diag::note_previous_declaration); - Invalid = true; - } + Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) + << New << static_cast<int>(New->getConstexprKind()) + << static_cast<int>(Old->getConstexprKind()); + Diag(Old->getLocation(), diag::note_previous_declaration); + Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && Old->isDefined(Def) && // If a friend function is inlined but does not have 'inline' diff --git a/clang/test/Sema/builtin-redecl.cpp b/clang/test/Sema/builtin-redecl.cpp index 31409a4d46a65..323c63e202883 100644 --- a/clang/test/Sema/builtin-redecl.cpp +++ b/clang/test/Sema/builtin-redecl.cpp @@ -14,18 +14,13 @@ void __builtin_va_copy(double d); // expected-error@+2 {{cannot redeclare builtin function '__builtin_va_end'}} // expected-note@+1 {{'__builtin_va_end' is a builtin with type}} void __builtin_va_end(__builtin_va_list); +// RUN: %clang_cc1 %s -fsyntax-only -verify +// RUN: %clang_cc1 %s -fsyntax-only -verify -x c void __va_start(__builtin_va_list*, ...); - void *__builtin_assume_aligned(const void *, size_t, ...); #ifdef __cplusplus -constexpr void *__builtin_assume_aligned(const void *, size_t, ...); - void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; -constexpr void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; - void *__builtin_assume_aligned(const void *, size_t, ...) throw(); -constexpr void *__builtin_assume_aligned(const void *, size_t, ...) throw(); - -// expected-error@+1 {{constexpr declaration of '__builtin_calloc' follows non-constexpr declaration}} -constexpr void *__builtin_calloc(size_t, size_t); -// expected-note@-1 {{previous declaration is here}} +void *__builtin_assume_aligned(const void *, size_t, ...) noexcept; +#else +void *__builtin_assume_aligned(const void *, size_t, ...); #endif >From ec88839cb34bf2a5f57edd376e30d8c08740f855 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Tue, 14 May 2024 18:57:09 +0100 Subject: [PATCH 3/4] Prevent consteval builtins from being available when consteval doesn't make sense (!CPlusPlus20) --- clang/include/clang/Basic/Builtins.def | 1 + clang/include/clang/Basic/BuiltinsBase.td | 2 +- clang/lib/Basic/Builtins.cpp | 3 +++ clang/lib/Sema/SemaDecl.cpp | 3 ++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index f356f881d5ef9..f3d7642573380 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -100,3 +100,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/BuiltinsBase.td b/clang/include/clang/Basic/BuiltinsBase.td index 1196b9e15c10d..58dee22fc0a45 100644 --- a/clang/include/clang/Basic/BuiltinsBase.td +++ b/clang/include/clang/Basic/BuiltinsBase.td @@ -70,7 +70,7 @@ class VScanfFormat<int I> : IndexedAttribute<"S", I>; // Builtin can be constant evaluated def Constexpr : Attribute<"E">; -// Builtin is immediate and must be constant evaluated. Implies Constexpr. +// 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 b116abbe034f7..7116e27cd9546 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 7ca02b5bbf624..d651ee2f502b1 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2410,7 +2410,8 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type, } ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified; - if (getLangOpts().CPlusPlus && Context.BuiltinInfo.isImmediate(ID)) { + if (Context.BuiltinInfo.isImmediate(ID)) { + assert(getLangOpts().CPlusPlus20 && "consteval builtins should only be available in C++20 mode"); ConstexprKind = ConstexprSpecKind::Consteval; } >From b498e90f6bd72e2b9044aef9a4c049845a68bc0d Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Tue, 14 May 2024 19:06:46 +0100 Subject: [PATCH 4/4] clang-format --- clang/lib/Sema/SemaDecl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 8554cb59729ff..c24ebc3ef4ebb 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2373,7 +2373,8 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type, ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified; if (Context.BuiltinInfo.isImmediate(ID)) { - assert(getLangOpts().CPlusPlus20 && "consteval builtins should only be available in C++20 mode"); + assert(getLangOpts().CPlusPlus20 && + "consteval builtins should only be available in C++20 mode"); ConstexprKind = ConstexprSpecKind::Consteval; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits