- Notifications
You must be signed in to change notification settings - Fork 15.3k
[flang][OpenMP] Use OmpDirectiveSpecification in DECLARE_VARIANT #160371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
…sing The DECLARE_VARIANT directive takes two names separated by a colon as an argument: base-name:variant-name. Define OmpBaseVariantNames to represent this, since no existing argument alternative matches it. However, there is an issue. The syntax "name1:name2" can be the argument to DECLARE_VARIANT (if both names are OmpObjects), but it can also be a reduction-specifier if "name2" is a type. This conflict can only be resolved once we know what the names are, which is after name resolution has visited them. The problem is that name resolution has side-effects that may be (practically) impossible to undo (e.g. creating new symbols, emitting diagnostic messages). To avoid this problem this PR makes the parsing of OmpArgument directive- sensitive: when the directive is DECLARE_VARIANT, don't attempt to parse a reduction-specifier, consider OmpBaseVariantNames instead. Otherwise ignore OmpBaseVariantNames in favor of reduction-specifier.
Member
| @llvm/pr-subscribers-flang-semantics @llvm/pr-subscribers-flang-openmp Author: Krzysztof Parzyszek (kparzysz) ChangesFull diff: https://github.com/llvm/llvm-project/pull/160371.diff 9 Files Affected:
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h index 34eb6ac3436bc..64be9714f6cc2 100644 --- a/flang/include/flang/Parser/openmp-utils.h +++ b/flang/include/flang/Parser/openmp-utils.h @@ -38,7 +38,6 @@ struct ConstructId { static constexpr llvm::omp::Directive id{Id}; \ } -MAKE_CONSTR_ID(OmpDeclareVariantDirective, D::OMPD_declare_variant); MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate); MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes); MAKE_CONSTR_ID(OpenMPDeclareReductionConstruct, D::OMPD_declare_reduction); @@ -92,8 +91,7 @@ struct DirectiveNameScope { } else if constexpr (TupleTrait<T>) { if constexpr (std::is_base_of_v<OmpBlockConstruct, T>) { return std::get<OmpBeginDirective>(x.t).DirName(); - } else if constexpr (std::is_same_v<T, OmpDeclareVariantDirective> || - std::is_same_v<T, OpenMPDeclarativeAllocate> || + } else if constexpr (std::is_same_v<T, OpenMPDeclarativeAllocate> || std::is_same_v<T, OpenMPDeclarativeAssumes> || std::is_same_v<T, OpenMPDeclareReductionConstruct> || std::is_same_v<T, OpenMPDeclareSimdConstruct> || diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 4808a5b844a6f..de65088c01eae 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -4933,10 +4933,14 @@ struct OpenMPSectionsConstruct { t; }; +// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336] +// +// declare-variant-directive -> +// DECLARE_VARIANT([base-name:]variant-name) // since 4.5 struct OmpDeclareVariantDirective { - TUPLE_CLASS_BOILERPLATE(OmpDeclareVariantDirective); + WRAPPER_CLASS_BOILERPLATE( + OmpDeclareVariantDirective, OmpDirectiveSpecification); CharBlock source; - std::tuple<Verbatim, std::optional<Name>, Name, OmpClauseList> t; }; // 2.10.6 declare-target -> DECLARE TARGET (extended-list) | diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 3b32e1a4a67b1..6ec6eb4038933 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -1763,8 +1763,9 @@ TYPE_PARSER(construct<OmpInitializerClause>( // OpenMP 5.2: 7.5.4 Declare Variant directive TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>( - verbatim("DECLARE VARIANT"_tok) || verbatim("DECLARE_VARIANT"_tok), - "(" >> maybe(name / ":"), name / ")", Parser<OmpClauseList>{}))) + predicated(Parser<OmpDirectiveName>{}, + IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >= + Parser<OmpDirectiveSpecification>{}))) // 2.16 Declare Reduction Construct TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 1b3eef0eefba3..fc81cfb7a3818 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2539,12 +2539,8 @@ class UnparseVisitor { } void Unparse(const OmpDeclareVariantDirective &x) { BeginOpenMP(); - Word("!$OMP DECLARE VARIANT "); - Put("("); - Walk(std::get<std::optional<Name>>(x.t), ":"); - Walk(std::get<Name>(x.t)); - Put(")"); - Walk(std::get<OmpClauseList>(x.t)); + Word("!$OMP "); + Walk(x.v); Put("\n"); EndOpenMP(); } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index e9bd34d449461..f10858ac1356d 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -634,11 +634,6 @@ template <typename Checker> struct DirectiveSpellingVisitor { std::get<parser::Verbatim>(x.t).source, Directive::OMPD_declare_target); return false; } - bool Pre(const parser::OmpDeclareVariantDirective &x) { - checker_(std::get<parser::Verbatim>(x.t).source, - Directive::OMPD_declare_variant); - return false; - } bool Pre(const parser::OpenMPGroupprivate &x) { checker_(x.v.DirName().source, Directive::OMPD_groupprivate); return false; @@ -1370,9 +1365,50 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) { } void OmpStructureChecker::Enter(const parser::OmpDeclareVariantDirective &x) { - const auto &dir{std::get<parser::Verbatim>(x.t)}; - PushContextAndClauseSets( - dir.source, llvm::omp::Directive::OMPD_declare_variant); + const parser::OmpDirectiveName &dirName{x.v.DirName()}; + PushContextAndClauseSets(dirName.source, dirName.v); + + const parser::OmpArgumentList &args{x.v.Arguments()}; + if (args.v.size() != 1) { + context_.Say(args.source, + "DECLARE_VARIANT directive should have a single argument"_err_en_US); + return; + } + + auto InvalidArgument{[&](parser::CharBlock source) { + context_.Say(source, + "The argument to the DECLARE_MAPPER directive should be [base-name:]variant-name"_err_en_US); + }}; + + auto CheckSymbol{[&](const Symbol *sym, parser::CharBlock source) { + if (sym) { + if (!IsProcedure(*sym) && !IsFunction(*sym)) { + context_.Say(source, + "The name '%s' should refer to a procedure"_err_en_US, sym->name()); + } + if (sym->test(Symbol::Flag::Implicit)) { + context_.Say(source, + "The name '%s' has been implicitly declared"_err_en_US, + sym->name()); + } + } else { + InvalidArgument(source); + } + }}; + + const parser::OmpArgument &arg{args.v.front()}; + common::visit( // + common::visitors{ + [&](const parser::OmpBaseVariantNames &y) { + CheckSymbol(GetObjectSymbol(std::get<0>(y.t)), arg.source); + CheckSymbol(GetObjectSymbol(std::get<1>(y.t)), arg.source); + }, + [&](const parser::OmpLocator &y) { + CheckSymbol(GetArgumentSymbol(arg), arg.source); + }, + [&](auto &&y) { InvalidArgument(arg.source); }, + }, + arg.u); } void OmpStructureChecker::Leave(const parser::OmpDeclareVariantDirective &) { diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index b73d794c11d31..3a6115dae2da5 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1540,20 +1540,6 @@ class OmpVisitor : public virtual DeclarationVisitor { bool Pre(const parser::OmpDeclareVariantDirective &x) { AddOmpSourceRange(x.source); - auto FindSymbolOrError = [&](const parser::Name &procName) { - auto *symbol{FindSymbol(NonDerivedTypeScope(), procName)}; - if (!symbol) { - context().Say(procName.source, - "Implicit subroutine declaration '%s' in !$OMP DECLARE VARIANT"_err_en_US, - procName.source); - } - }; - auto &baseProcName = std::get<std::optional<parser::Name>>(x.t); - if (baseProcName) { - FindSymbolOrError(*baseProcName); - } - auto &varProcName = std::get<parser::Name>(x.t); - FindSymbolOrError(varProcName); return true; } @@ -1687,16 +1673,19 @@ class OmpVisitor : public virtual DeclarationVisitor { PopScope(); } } + + // These objects are handled explicitly, and the AST traversal should not + // reach a point where it calls the Pre functions for them. bool Pre(const parser::OmpMapperSpecifier &x) { - // OmpMapperSpecifier is handled explicitly, and the AST traversal - // should not reach a point where it calls this function. llvm_unreachable("This function should not be reached by AST traversal"); } bool Pre(const parser::OmpReductionSpecifier &x) { - // OmpReductionSpecifier is handled explicitly, and the AST traversal - // should not reach a point where it calls this function. llvm_unreachable("This function should not be reached by AST traversal"); } + bool Pre(const parser::OmpBaseVariantNames &x) { + llvm_unreachable("This function should not be reached by AST traversal"); + } + bool Pre(const parser::OmpDirectiveSpecification &x); void Post(const parser::OmpDirectiveSpecification &) { messageHandler().set_currStmtSource(std::nullopt); diff --git a/flang/test/Parser/OpenMP/declare-variant.f90 b/flang/test/Parser/OpenMP/declare-variant.f90 index 3366b143e62e6..f5c34abd84ac7 100644 --- a/flang/test/Parser/OpenMP/declare-variant.f90 +++ b/flang/test/Parser/OpenMP/declare-variant.f90 @@ -2,15 +2,19 @@ ! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s subroutine sub0 -!CHECK: !$OMP DECLARE VARIANT (sub:vsub) MATCH(CONSTRUCT={PARALLEL}) -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'sub' -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(sub:vsub) MATCH(CONSTRUCT={PARALLEL}) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpBaseVariantNames +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'sub' +!PARSE-TREE: | | OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = parallel +!PARSE-TREE: | Flags = None + !$omp declare variant (sub:vsub) match (construct={parallel}) contains subroutine vsub @@ -30,14 +34,17 @@ subroutine vsub (v1) integer, value :: v1 end subroutine sub (v1) -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH} -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub), match(construct={dispatch}) integer, value :: v1 end @@ -56,17 +63,20 @@ subroutine vsub (v1, a1, a2) integer(omp_interop_kind), value :: a2 end subroutine sub (v1) -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(T& -!CHECK: !$OMP&ARGET),INTEROP(TARGET)) -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) APPEND_ARGS(INTEROP(TA& +!CHECK: !$OMP&RGET),INTEROP(TARGET)) + +!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector !PARSE-TREE: | | | OmpTraitSelectorName -> llvm::omp::Directive = dispatch !PARSE-TREE: | OmpClause -> AppendArgs -> OmpAppendArgsClause -> OmpAppendOp -> OmpInteropType -> Value = Target !PARSE-TREE: | OmpAppendOp -> OmpInteropType -> Value = Target +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub), match(construct={dispatch}), append_args (interop(target), interop(target)) integer, value :: v1 end @@ -81,11 +91,12 @@ subroutine sb3 (x1, x2) contains subroutine sub (v1, v2) type(c_ptr), value :: v1, v2 -!CHECK: !$OMP DECLARE VARIANT (vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v& -!CHECK: !$OMP&1) ADJUST_ARGS(NEED_DEVICE_PTR:v2) -!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'vsub' +!CHECK: !$OMP DECLARE VARIANT(vsub) MATCH(CONSTRUCT={DISPATCH}) ADJUST_ARGS(NOTHING:v1& +!CHECK: !$OMP&) ADJUST_ARGS(NEED_DEVICE_PTR:v2) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'vsub' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct !PARSE-TREE: | | OmpTraitSelector @@ -96,6 +107,8 @@ subroutine sub (v1, v2) !PARSE-TREE: | OmpClause -> AdjustArgs -> OmpAdjustArgsClause !PARSE-TREE: | | OmpAdjustOp -> Value = Need_Device_Ptr !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'v2' +!PARSE-TREE: | Flags = None + !$omp declare variant(vsub) match ( construct = { dispatch } ) adjust_args(nothing : v1 ) adjust_args(need_device_ptr : v2) end subroutine vsub(v1, v2) @@ -119,13 +132,15 @@ subroutine f2 (x, y) !$omp declare variant (f1) match (construct={simd(uniform(y))}) end end subroutine -!CHECK: !$OMP DECLARE VARIANT (f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))}) -!PARSE-TREE: | | | | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE-NEXT: | | | | | Verbatim -!PARSE-TREE-NEXT: | | | | | Name = 'f1' -!PARSE-TREE-NEXT: | | | | | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector -!PARSE-TREE-NEXT: | | | | | | OmpTraitSetSelectorName -> Value = Construct -!PARSE-TREE-NEXT: | | | | | | OmpTraitSelector -!PARSE-TREE-NEXT: | | | | | | | OmpTraitSelectorName -> Value = Simd -!PARSE-TREE-NEXT: | | | | | | | Properties -!PARSE-TREE-NEXT: | | | | | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y' +!CHECK: !$OMP DECLARE VARIANT(f1) MATCH(CONSTRUCT={SIMD(UNIFORM(y))}) + +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f1' +!PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector +!PARSE-TREE: | | OmpTraitSetSelectorName -> Value = Construct +!PARSE-TREE: | | OmpTraitSelector +!PARSE-TREE: | | | OmpTraitSelectorName -> Value = Simd +!PARSE-TREE: | | | Properties +!PARSE-TREE: | | | | OmpTraitProperty -> OmpClause -> Uniform -> Name = 'y' +!PARSE-TREE: | Flags = None diff --git a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 index a25d750adc39d..f55ff958b0952 100644 --- a/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 +++ b/flang/test/Parser/OpenMP/openmp6-directive-spellings.f90 @@ -145,12 +145,12 @@ subroutine g05 !UNPARSE: SUBROUTINE g05 !UNPARSE: END SUBROUTINE !UNPARSE: END INTERFACE -!UNPARSE: !$OMP DECLARE VARIANT (g05) MATCH(USER={CONDITION(.true._4)}) +!UNPARSE: !$OMP DECLARE_VARIANT(g05) MATCH(USER={CONDITION(.true._4)}) !UNPARSE: END SUBROUTINE -!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -!PARSE-TREE: | Verbatim -!PARSE-TREE: | Name = 'g05' +!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpDeclareVariantDirective -> OmpDirectiveSpecification +!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = declare variant +!PARSE-TREE: | OmpArgumentList -> OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'g05' !PARSE-TREE: | OmpClauseList -> OmpClause -> Match -> OmpMatchClause -> OmpContextSelectorSpecification -> OmpTraitSetSelector !PARSE-TREE: | | OmpTraitSetSelectorName -> Value = User !PARSE-TREE: | | OmpTraitSelector @@ -159,6 +159,7 @@ subroutine g05 !PARSE-TREE: | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4' !PARSE-TREE: | | | | | LiteralConstant -> LogicalLiteralConstant !PARSE-TREE: | | | | | | bool = 'true' +!PARSE-TREE: | Flags = None subroutine f06 implicit none diff --git a/flang/test/Semantics/OpenMP/declare-variant.f90 b/flang/test/Semantics/OpenMP/declare-variant.f90 index 84a0cdcd10d91..59b8bda3f2a99 100644 --- a/flang/test/Semantics/OpenMP/declare-variant.f90 +++ b/flang/test/Semantics/OpenMP/declare-variant.f90 @@ -1,9 +1,11 @@ ! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51 subroutine sub0 -!ERROR: Implicit subroutine declaration 'vsub1' in !$OMP DECLARE VARIANT +!ERROR: The name 'vsub1' should refer to a procedure +!ERROR: The name 'vsub1' has been implicitly declared !$omp declare variant (sub:vsub1) match (construct={parallel}) -!ERROR: Implicit subroutine declaration 'sub1' in !$OMP DECLARE VARIANT +!ERROR: The name 'sub1' should refer to a procedure +!ERROR: The name 'sub1' has been implicitly declared !$omp declare variant (sub1:vsub) match (construct={parallel}) contains subroutine vsub |
Contributor Author
tblah approved these changes Sep 25, 2025
Contributor
tblah left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks
Base automatically changed from users/kparzysz/r07-base-variant-argument to main September 25, 2025 12:59
| ✅ With the latest revision this PR passed the C/C++ code formatter. |
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Oct 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
No description provided.