[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
https://github.com/MitalAshok ready_for_review https://github.com/llvm/llvm-project/pull/91895 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/91895 >From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Sun, 12 May 2024 19:48:24 +0100 Subject: [PATCH 1/9] [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 (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 : 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(New->getConstexprKind()) -<< static_cast(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(New->getConstexprKind()) + << static_cast(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
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
https://github.com/MitalAshok edited https://github.com/llvm/llvm-project/pull/91895 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/91895 >From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Sun, 12 May 2024 19:48:24 +0100 Subject: [PATCH 1/8] [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 (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 : 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(New->getConstexprKind()) -<< static_cast(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(New->getConstexprKind()) + << static_cast(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
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
MitalAshok wrote: This is on top of #91894 [P2641R4](https://wg21.link/P2641R4) Currently, this doesn't strictly check "whose complete object's lifetime began within `E`". A bunch of the static_asserts I have for objects under construction should be ill-formed instead of false, but some of them should be true. https://github.com/llvm/llvm-project/pull/91895 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 17daa204feadf9c28fc13b7daa69c3cbe865b238 253f58f0e34bc6dedbbfe17f68cfe9baa3a9146f -- clang/test/SemaCXX/builtin-is-within-lifetime.cpp clang/include/clang/Basic/Builtins.h clang/lib/AST/ExprConstant.cpp clang/lib/AST/Interp/State.h clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/test/Sema/builtin-redecl.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f3b31d87dd..ffe2f172a9 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1507,7 +1507,8 @@ CallStackFrame::~CallStackFrame() { } static bool isRead(AccessKinds AK) { - return AK == AK_Read || AK == AK_ReadObjectRepresentation || AK == AK_IsWithinLifetime; + return AK == AK_Read || AK == AK_ReadObjectRepresentation || + AK == AK_IsWithinLifetime; } static bool isModification(AccessKinds AK) { @@ -1535,7 +1536,8 @@ static bool isAnyAccess(AccessKinds AK) { /// Is this an access per the C++ definition? static bool isFormalAccess(AccessKinds AK) { - return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy && AK != AK_IsWithinLifetime; + return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy && + AK != AK_IsWithinLifetime; } /// Is this kind of axcess valid on an indeterminate object value? @@ -3655,7 +3657,8 @@ struct CompleteObject { // In C++14 onwards, it is permitted to read a mutable member whose // lifetime began within the evaluation. // FIXME: Should we also allow this in C++11? -if (!Info.getLangOpts().CPlusPlus14 && AK != AccessKinds::AK_IsWithinLifetime) +if (!Info.getLangOpts().CPlusPlus14 && +AK != AccessKinds::AK_IsWithinLifetime) return false; return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true); } @@ -4093,7 +4096,7 @@ static CompleteObject findCompleteObject(EvalInfo , const Expr *E, // started in the current evaluation. BaseVal = Info.EvaluatingDeclValue; if (AK == AccessKinds::AK_IsWithinLifetime) - return CompleteObject(); // Not within lifetime + return CompleteObject(); // Not within lifetime } else if (const ValueDecl *D = LVal.Base.dyn_cast()) { // Allow reading from a GUID declaration. if (auto *GD = dyn_cast(D)) { @@ -11508,7 +11511,8 @@ public: bool ZeroInitialization(const Expr *E) { return Success(0, E); } - friend std::optional EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &, const CallExpr *); + friend std::optional EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &, + const CallExpr *); //======// //Visitor Methods @@ -17030,56 +17034,70 @@ bool Expr::tryEvaluateStrLen(uint64_t , ASTContext ) const { } namespace { - struct IsWithinLifetimeHandler { -EvalInfo -static constexpr AccessKinds AccessKind = AccessKinds::AK_IsWithinLifetime; -using result_type = std::optional; -std::optional failed() { return std::nullopt; } -template -std::optional found(T , QualType SubobjType) { - return true; -} - }; +struct IsWithinLifetimeHandler { + EvalInfo + static constexpr AccessKinds AccessKind = AccessKinds::AK_IsWithinLifetime; + using result_type = std::optional; + std::optional failed() { return std::nullopt; } + template + std::optional found(T , QualType SubobjType) { +return true; + } +}; - std::optional EvaluateBuiltinIsWithinLifetime(IntExprEvaluator , const CallExpr *E) { -EvalInfo& Info = IEE.Info; -//assert(Info.InConstantContext && "Call to consteval builtin not in constant context?"); -assert(E->getBuiltinCallee() == Builtin::BI__builtin_is_within_lifetime); -const Expr *Arg = E->getArg(0); -if (Arg->isValueDependent()) - return std::nullopt; -LValue Val; -if (!EvaluatePointer(Arg, Val, Info)) - return std::nullopt; +std::optional EvaluateBuiltinIsWithinLifetime(IntExprEvaluator , +const CallExpr *E) { + EvalInfo = IEE.Info; + // assert(Info.InConstantContext && "Call to consteval builtin not in constant + // context?"); + assert(E->getBuiltinCallee() == Builtin::BI__builtin_is_within_lifetime); + const Expr *Arg = E->getArg(0); + if (Arg->isValueDependent()) +return std::nullopt; + LValue Val; + if (!EvaluatePointer(Arg, Val, Info)) +return std::nullopt; -auto Error = [&](int Diag) { - const auto *Callee = Info.CurrentCall->getCallee(); - bool CalledFromStd = Callee &&
[clang] [Clang] Add __builtin_is_within_lifetime to implement P2641R4's std::is_within_lifetime (PR #91895)
https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/91895 None >From 56aed689dc5825fc5bacc6dfdff58ee0eaf71f82 Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Sun, 12 May 2024 19:48:24 +0100 Subject: [PATCH 1/2] [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 (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 : 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(New->getConstexprKind()) -<< static_cast(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(New->getConstexprKind()) + << static_cast(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