-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[flang][OpenMP] Use OmpDirectiveSpecification in METADIRECTIVE #159577
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
[flang][OpenMP] Use OmpDirectiveSpecification in METADIRECTIVE #159577
Conversation
@llvm/pr-subscribers-flang-openmp @llvm/pr-subscribers-flang-semantics Author: Krzysztof Parzyszek (kparzysz) ChangesFull diff: https://github.com/llvm/llvm-project/pull/159577.diff 10 Files Affected:
diff --git a/flang/include/flang/Parser/openmp-utils.h b/flang/include/flang/Parser/openmp-utils.h
index 032fb8996fe48..7032652c88b9c 100644
--- a/flang/include/flang/Parser/openmp-utils.h
+++ b/flang/include/flang/Parser/openmp-utils.h
@@ -40,7 +40,6 @@ struct ConstructId {
MAKE_CONSTR_ID(OmpDeclareVariantDirective, D::OMPD_declare_variant);
MAKE_CONSTR_ID(OmpErrorDirective, D::OMPD_error);
-MAKE_CONSTR_ID(OmpMetadirectiveDirective, D::OMPD_metadirective);
MAKE_CONSTR_ID(OpenMPDeclarativeAllocate, D::OMPD_allocate);
MAKE_CONSTR_ID(OpenMPDeclarativeAssumes, D::OMPD_assumes);
MAKE_CONSTR_ID(OpenMPDeclareMapperConstruct, D::OMPD_declare_mapper);
@@ -103,7 +102,6 @@ struct DirectiveNameScope {
return std::get<OmpBeginDirective>(x.t).DirName();
} else if constexpr (std::is_same_v<T, OmpDeclareVariantDirective> ||
std::is_same_v<T, OmpErrorDirective> ||
- std::is_same_v<T, OmpMetadirectiveDirective> ||
std::is_same_v<T, OpenMPDeclarativeAllocate> ||
std::is_same_v<T, OpenMPDeclarativeAssumes> ||
std::is_same_v<T, OpenMPDeclareMapperConstruct> ||
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 7307283eb91ec..fc2c83e022939 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4827,9 +4827,8 @@ struct OmpBlockConstruct {
};
struct OmpMetadirectiveDirective {
- TUPLE_CLASS_BOILERPLATE(OmpMetadirectiveDirective);
- std::tuple<Verbatim, OmpClauseList> t;
- CharBlock source;
+ WRAPPER_CLASS_BOILERPLATE(
+ OmpMetadirectiveDirective, OmpDirectiveSpecification);
};
// Ref: [5.1:89-90], [5.2:216]
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index c6d4de108fb59..694ca08d5bf8b 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1008,11 +1008,11 @@ TYPE_PARSER(construct<OmpMatchClause>(
Parser<traits::OmpContextSelectorSpecification>{}))
TYPE_PARSER(construct<OmpOtherwiseClause>(
- maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
+ maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
TYPE_PARSER(construct<OmpWhenClause>(
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
- maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
+ maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
TYPE_PARSER(construct<OmpGrainsizeClause>(
@@ -1281,6 +1281,16 @@ TYPE_PARSER(sourced(construct<OmpErrorDirective>(
// --- Parsers for directives and constructs --------------------------
+static inline constexpr auto IsDirective(llvm::omp::Directive dir) {
+ return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; };
+}
+
+static inline constexpr auto IsMemberOf(const DirectiveSet &dirs) {
+ return [&dirs](const OmpDirectiveName &name) -> bool {
+ return dirs.test(llvm::to_underlying(name.v));
+ };
+}
+
TYPE_PARSER(sourced(construct<OmpDirectiveName>(OmpDirectiveNameParser{})))
OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text,
@@ -1293,7 +1303,7 @@ OmpDirectiveSpecification static makeFlushFromOldSyntax(Verbatim &&text,
TYPE_PARSER(sourced(
// Parse the old syntax: FLUSH [clauses] [(objects)]
- construct<OmpDirectiveSpecification>(
+ sourced(construct<OmpDirectiveSpecification>(
// Force this old-syntax parser to fail for FLUSH followed by '('.
// Otherwise it could succeed on the new syntax but have one of
// lists absent in the parsed result.
@@ -1303,13 +1313,13 @@ TYPE_PARSER(sourced(
verbatim("FLUSH"_tok) / !lookAhead("("_tok),
maybe(Parser<OmpClauseList>{}),
maybe(parenthesized(Parser<OmpArgumentList>{})),
- pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax))) ||
+ pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) ||
// Parse the standard syntax: directive [(arguments)] [clauses]
- construct<OmpDirectiveSpecification>( //
+ sourced(construct<OmpDirectiveSpecification>( //
sourced(OmpDirectiveNameParser{}),
maybe(parenthesized(Parser<OmpArgumentList>{})),
maybe(Parser<OmpClauseList>{}),
- pure(OmpDirectiveSpecification::Flags::None))))
+ pure(OmpDirectiveSpecification::Flags::None)))))
static bool IsStandaloneOrdered(const OmpDirectiveSpecification &dirSpec) {
// An ORDERED construct is standalone if it has DOACROSS or DEPEND clause.
@@ -1363,18 +1373,10 @@ TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>(
sourced(construct<OpenMPUtilityConstruct>(
sourced(Parser<OmpNothingDirective>{}))))))
-TYPE_PARSER(sourced(construct<OmpMetadirectiveDirective>(
- verbatim("METADIRECTIVE"_tok), Parser<OmpClauseList>{})))
-
-static inline constexpr auto IsDirective(llvm::omp::Directive dir) {
- return [dir](const OmpDirectiveName &name) -> bool { return dir == name.v; };
-}
-
-static inline constexpr auto IsMemberOf(const DirectiveSet &dirs) {
- return [&dirs](const OmpDirectiveName &name) -> bool {
- return dirs.test(llvm::to_underlying(name.v));
- };
-}
+TYPE_PARSER(construct<OmpMetadirectiveDirective>(
+ predicated(Parser<OmpDirectiveName>{},
+ IsDirective(llvm::omp::Directive::OMPD_metadirective)) >=
+ Parser<OmpDirectiveSpecification>{}))
struct OmpBeginDirectiveParser {
using resultType = OmpDirectiveSpecification;
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 73bbbc04f46b1..bcbd99112835f 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2675,8 +2675,8 @@ class UnparseVisitor {
void Unparse(const OmpFailClause &x) { Walk(x.v); }
void Unparse(const OmpMetadirectiveDirective &x) {
BeginOpenMP();
- Word("!$OMP METADIRECTIVE ");
- Walk(std::get<OmpClauseList>(x.t));
+ Word("!$OMP ");
+ Walk(x.v);
Put("\n");
EndOpenMP();
}
diff --git a/flang/lib/Semantics/check-omp-metadirective.cpp b/flang/lib/Semantics/check-omp-metadirective.cpp
index cf5ea9028edc7..499fb8452a154 100644
--- a/flang/lib/Semantics/check-omp-metadirective.cpp
+++ b/flang/lib/Semantics/check-omp-metadirective.cpp
@@ -536,7 +536,8 @@ void OmpStructureChecker::CheckTraitSimd(
void OmpStructureChecker::Enter(const parser::OmpMetadirectiveDirective &x) {
EnterDirectiveNest(MetadirectiveNest);
- PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_metadirective);
+ PushContextAndClauseSets(
+ x.v.source, llvm::omp::Directive::OMPD_metadirective);
}
void OmpStructureChecker::Leave(const parser::OmpMetadirectiveDirective &) {
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 4c7cd1734e0e7..2794eef025c3d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -624,11 +624,6 @@ template <typename Checker> struct DirectiveSpellingVisitor {
checker_(GetDirName(x.t).source, Directive::OMPD_allocators);
return false;
}
- bool Pre(const parser::OmpMetadirectiveDirective &x) {
- checker_(
- std::get<parser::Verbatim>(x.t).source, Directive::OMPD_metadirective);
- return false;
- }
bool Pre(const parser::OpenMPDeclarativeAssumes &x) {
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_assumes);
return false;
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index abb8f6430b29b..14326539f2217 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -413,7 +413,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
}
bool Pre(const parser::OmpMetadirectiveDirective &x) {
- PushContext(x.source, llvm::omp::Directive::OMPD_metadirective);
+ PushContext(x.v.source, llvm::omp::Directive::OMPD_metadirective);
return true;
}
void Post(const parser::OmpMetadirectiveDirective &) { PopContext(); }
diff --git a/flang/test/Parser/OpenMP/metadirective-dirspec.f90 b/flang/test/Parser/OpenMP/metadirective-dirspec.f90
index baa8b2e08c539..84064a0353678 100644
--- a/flang/test/Parser/OpenMP/metadirective-dirspec.f90
+++ b/flang/test/Parser/OpenMP/metadirective-dirspec.f90
@@ -11,7 +11,7 @@ subroutine f00(x)
!UNPARSE: SUBROUTINE f00 (x)
!UNPARSE: INTEGER x(10_4)
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: ALLOCATE(x))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: ALLOCATE(x))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -37,7 +37,7 @@ subroutine f01(x)
!UNPARSE: SUBROUTINE f01 (x)
!UNPARSE: INTEGER x
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: CRITICAL(x))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: CRITICAL(x))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -61,8 +61,8 @@ subroutine f02
end
!UNPARSE: SUBROUTINE f02
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE MAPPER(mymapper:INTEGER:&
-!UNPARSE: !$OMP&:v) MAP(TOFROM: v))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE MAPPER(mymapper:INTEGER::&
+!UNPARSE: !$OMP&v) MAP(TOFROM: v))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -105,7 +105,7 @@ subroutine f03
!UNPARSE: TYPE :: tt2
!UNPARSE: REAL :: x
!UNPARSE: END TYPE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE REDUCTION(+:tt1,tt2: omp_out%x=omp_in%x+omp_out%x
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE REDUCTION(+:tt1,tt2: omp_out%x=omp_in%x+omp_out%x
!UNPARSE: ))
!UNPARSE: END SUBROUTINE
@@ -149,7 +149,7 @@ subroutine f04
end
!UNPARSE: SUBROUTINE f04
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE SIMD(f04))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE SIMD(f04))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -174,7 +174,7 @@ subroutine f05
end
!UNPARSE: SUBROUTINE f05
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE TARGET(f05))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE TARGET(f05))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -201,7 +201,7 @@ subroutine f06(x, y)
!UNPARSE: SUBROUTINE f06 (x, y)
!UNPARSE: INTEGER x, y
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: FLUSH(x, y))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: FLUSH(x, y))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
@@ -228,7 +228,7 @@ subroutine f07
!UNPARSE: SUBROUTINE f07
!UNPARSE: INTEGER t
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: THREADPRIVATE(t))
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: THREADPRIVATE(t))
!UNPARSE: END SUBROUTINE
!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
diff --git a/flang/test/Parser/OpenMP/metadirective.f90 b/flang/test/Parser/OpenMP/metadirective.f90
index 1185ac897ecf6..0d43a32039421 100644
--- a/flang/test/Parser/OpenMP/metadirective.f90
+++ b/flang/test/Parser/OpenMP/metadirective.f90
@@ -8,7 +8,7 @@ subroutine f00
!UNPARSE: SUBROUTINE f00
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(CONSTRUCT={TARGET, PARALLEL}: NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(CONSTRUCT={TARGET, PARALLEL}: NOTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -30,7 +30,7 @@ subroutine f01
!UNPARSE: SUBROUTINE f01
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(TARGET_DEVICE={KIND(host), DEVICE_NUM(1_4)}: NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(TARGET_DEVICE={KIND(host), DEVICE_NUM(1_4)}: NOTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -57,7 +57,7 @@ subroutine f02
!UNPARSE: SUBROUTINE f02
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(TARGET_DEVICE={KIND(any), DEVICE_NUM(7_4)}: NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(TARGET_DEVICE={KIND(any), DEVICE_NUM(7_4)}: NOTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -85,8 +85,8 @@ subroutine f03
!UNPARSE: SUBROUTINE f03
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={ATOMIC_DEFAULT_MEM_ORDER(ACQ_REL)}: &
-!UNPARSE: !$OMP&NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={ATOMIC_DEFAULT_MEM_ORDER(ACQ_REL)}: N&
+!UNPARSE: !$OMP&OTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -109,8 +109,8 @@ subroutine f04
!UNPARSE: SUBROUTINE f04
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={extension_trait(haha(1_4), foo(baz,bar(1_4&
-!UNPARSE: !$OMP&)))}: NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={extension_trait(haha(1_4), foo(baz,bar(1_4)&
+!UNPARSE: !$OMP&))}: NOTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -149,8 +149,8 @@ subroutine f05(x)
!UNPARSE: SUBROUTINE f05 (x)
!UNPARSE: INTEGER x
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(SCORE(100_4): .true._4)}: PARALLEL DO REDUCTION(+&
-!UNPARSE: !$OMP&: x)) OTHERWISE(NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(SCORE(100_4): .true._4)}: PARALLEL DO REDUCTION(+:&
+!UNPARSE: !$OMP& x)) OTHERWISE(NOTHING)
!UNPARSE: DO i=1_4,10_4
!UNPARSE: END DO
!UNPARSE: END SUBROUTINE
@@ -186,8 +186,8 @@ subroutine f06
!UNPARSE: SUBROUTINE f06
!UNPARSE: CONTINUE
-!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={VENDOR(amd)}, USER={CONDITION(.true._4)}: NO&
-!UNPARSE: !$OMP&THING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={VENDOR(amd)}, USER={CONDITION(.true._4)}: NOT&
+!UNPARSE: !$OMP&HING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OmpMetadirectiveDirective
@@ -219,8 +219,8 @@ subroutine f07
end
!UNPARSE: SUBROUTINE f07
-!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={VENDOR(amd)}: DECLARE SIMD) WHEN(USE&
-!UNPARSE: !$OMP&R={CONDITION(.true._4)}: DECLARE TARGET) OTHERWISE(NOTHING)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(IMPLEMENTATION={VENDOR(amd)}: DECLARE SIMD) WHEN(USER&
+!UNPARSE: !$OMP&={CONDITION(.true._4)}: DECLARE TARGET) OTHERWISE(NOTHING)
!UNPARSE: END SUBROUTINE
!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
diff --git a/flang/test/Preprocessing/omp-sentinel-fixed-form.F b/flang/test/Preprocessing/omp-sentinel-fixed-form.F
index c8271682a5b92..30579af4dbad9 100644
--- a/flang/test/Preprocessing/omp-sentinel-fixed-form.F
+++ b/flang/test/Preprocessing/omp-sentinel-fixed-form.F
@@ -6,8 +6,8 @@ program test
implicit none
integer i,j,n
n = 100
-! CHECK: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: TARGET TEAMS DISTRIBUTE PARALLEL&
-! CHECK: !$OMP& DO) DEFAULT(TARGET TEAMS LOOP)
+! CHECK: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: TARGET TEAMS DISTRIBUTE PARALLEL &
+! CHECK: !$OMP&DO) DEFAULT(TARGET TEAMS LOOP)
!$omp metadirective
!$omp& when(user={condition(OMP_TARGET.or.OMP_SIMD)}:
!$omp& target teams distribute parallel do )
|
|
||
// --- Parsers for directives and constructs -------------------------- | ||
|
||
static inline constexpr auto IsDirective(llvm::omp::Directive dir) { |
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.
I am seeing this change a few times in your recent patches for OmpDirectiveSpecification
. I think this should be done in a NFC commit before submitting these other patches. It will reduce the diff of these patches and means this non functional change is not attached to a functional change.
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.
Done: #159803
TYPE_PARSER(sourced( | ||
// Parse the old syntax: FLUSH [clauses] [(objects)] | ||
construct<OmpDirectiveSpecification>( | ||
sourced(construct<OmpDirectiveSpecification>( |
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.
Isn't this already inside of a sourced
parser?
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.
It is. Let me fix this...
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.
Done
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
No description provided.