Skip to content

[Flang][OpenMP] Add Semantic Checks for Atomic Capture Construct #108516

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
merged 8 commits into from
Sep 25, 2024

Conversation

harishch4
Copy link
Contributor

This PR adds semantic checks to ensure the atomic capture construct conforms to one of the valid forms:
[capture-stmt, update-stmt], [capture-stmt, write-stmt] or [update-stmt, capture-stmt].

Functions checkForSymbolMatch and checkForSingleVariableOnRHS are moved from flang/lib/Lower/DirectivesCommon.h to flang/Semantics/tools.h for reuse.

@llvmbot
Copy link
Member

llvmbot commented Sep 13, 2024

@llvm/pr-subscribers-flang-fir-hlfir
@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-openmp

Author: None (harishch4)

Changes

This PR adds semantic checks to ensure the atomic capture construct conforms to one of the valid forms:
[capture-stmt, update-stmt], [capture-stmt, write-stmt] or [update-stmt, capture-stmt].

Functions checkForSymbolMatch and checkForSingleVariableOnRHS are moved from flang/lib/Lower/DirectivesCommon.h to flang/Semantics/tools.h for reuse.


Full diff: https://github.com/llvm/llvm-project/pull/108516.diff

7 Files Affected:

  • (modified) flang/include/flang/Semantics/tools.h (+27)
  • (modified) flang/lib/Lower/DirectivesCommon.h (+3-31)
  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+70-6)
  • (modified) flang/lib/Semantics/check-omp-structure.h (+1)
  • (modified) flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 (+40)
  • (modified) flang/test/Semantics/OpenMP/requires-atomic01.f90 (+3-3)
  • (modified) flang/test/Semantics/OpenMP/requires-atomic02.f90 (+3-3)
diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index 15c02ecc0058cc..b60514b991b727 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -736,5 +736,32 @@ std::string GetCommonBlockObjectName(const Symbol &, bool underscoring);
 // Check for ambiguous USE associations
 bool HadUseError(SemanticsContext &, SourceName at, const Symbol *);
 
+/// Checks if the assignment statement has a single variable on the RHS.
+inline bool checkForSingleVariableOnRHS(
+    const Fortran::parser::AssignmentStmt &assignmentStmt) {
+  const Fortran::parser::Expr &expr{
+      std::get<Fortran::parser::Expr>(assignmentStmt.t)};
+  const Fortran::common::Indirection<Fortran::parser::Designator> *designator =
+      std::get_if<Fortran::common::Indirection<Fortran::parser::Designator>>(
+          &expr.u);
+  return designator != nullptr;
+}
+
+/// Checks if the symbol on the LHS of the assignment statement is present in
+/// the RHS expression.
+inline bool checkForSymbolMatch(
+    const Fortran::parser::AssignmentStmt &assignmentStmt) {
+  const auto &var{std::get<Fortran::parser::Variable>(assignmentStmt.t)};
+  const auto &expr{std::get<Fortran::parser::Expr>(assignmentStmt.t)};
+  const auto *e{Fortran::semantics::GetExpr(expr)};
+  const auto *v{Fortran::semantics::GetExpr(var)};
+  auto varSyms{Fortran::evaluate::GetSymbolVector(*v)};
+  const Fortran::semantics::Symbol &varSymbol{*varSyms.front()};
+  for (const Fortran::semantics::Symbol &symbol :
+      Fortran::evaluate::GetSymbolVector(*e))
+    if (varSymbol == symbol)
+      return true;
+  return false;
+}
 } // namespace Fortran::semantics
 #endif // FORTRAN_SEMANTICS_TOOLS_H_
diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h
index d2060e77ce5305..a32f0b287e049a 100644
--- a/flang/lib/Lower/DirectivesCommon.h
+++ b/flang/lib/Lower/DirectivesCommon.h
@@ -74,34 +74,6 @@ struct AddrAndBoundsInfo {
   }
 };
 
-/// Checks if the assignment statement has a single variable on the RHS.
-static inline bool checkForSingleVariableOnRHS(
-    const Fortran::parser::AssignmentStmt &assignmentStmt) {
-  const Fortran::parser::Expr &expr{
-      std::get<Fortran::parser::Expr>(assignmentStmt.t)};
-  const Fortran::common::Indirection<Fortran::parser::Designator> *designator =
-      std::get_if<Fortran::common::Indirection<Fortran::parser::Designator>>(
-          &expr.u);
-  return designator != nullptr;
-}
-
-/// Checks if the symbol on the LHS of the assignment statement is present in
-/// the RHS expression.
-static inline bool
-checkForSymbolMatch(const Fortran::parser::AssignmentStmt &assignmentStmt) {
-  const auto &var{std::get<Fortran::parser::Variable>(assignmentStmt.t)};
-  const auto &expr{std::get<Fortran::parser::Expr>(assignmentStmt.t)};
-  const auto *e{Fortran::semantics::GetExpr(expr)};
-  const auto *v{Fortran::semantics::GetExpr(var)};
-  auto varSyms{Fortran::evaluate::GetSymbolVector(*v)};
-  const Fortran::semantics::Symbol &varSymbol{*varSyms.front()};
-  for (const Fortran::semantics::Symbol &symbol :
-       Fortran::evaluate::GetSymbolVector(*e))
-    if (varSymbol == symbol)
-      return true;
-  return false;
-}
-
 /// Populates \p hint and \p memoryOrder with appropriate clause information
 /// if present on atomic construct.
 static inline void genOmpAtomicHintAndMemoryOrderClauses(
@@ -537,7 +509,7 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
   stmt2LHSArg = fir::getBase(converter.genExprAddr(assign2.lhs, stmtCtx));
 
   // Operation specific RHS evaluations
-  if (checkForSingleVariableOnRHS(stmt1)) {
+  if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) {
     // Atomic capture construct is of the form [capture-stmt, update-stmt] or
     // of the form [capture-stmt, write-stmt]
     stmt1RHSArg = fir::getBase(converter.genExprAddr(assign1.rhs, stmtCtx));
@@ -573,8 +545,8 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
   firOpBuilder.createBlock(&(atomicCaptureOp->getRegion(0)));
   mlir::Block &block = atomicCaptureOp->getRegion(0).back();
   firOpBuilder.setInsertionPointToStart(&block);
-  if (checkForSingleVariableOnRHS(stmt1)) {
-    if (checkForSymbolMatch(stmt2)) {
+  if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) {
+    if (Fortran::semantics::checkForSymbolMatch(stmt2)) {
       // Atomic capture construct is of the form [capture-stmt, update-stmt]
       const Fortran::semantics::SomeExpr &fromExpr =
           *Fortran::semantics::GetExpr(stmt1Expr);
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 643b713b32e29d..662e6c10bd4e03 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1977,6 +1977,70 @@ void OmpStructureChecker::CheckAtomicUpdateStmt(
   ErrIfAllocatableVariable(var);
 }
 
+void OmpStructureChecker::CheckAtomicCaptureConstruct(
+    const parser::OmpAtomicCapture &atomicCaptureConstruct) {
+  const Fortran::parser::AssignmentStmt &stmt1 =
+      std::get<Fortran::parser::OmpAtomicCapture::Stmt1>(
+          atomicCaptureConstruct.t)
+          .v.statement;
+  const auto &stmt1Var{std::get<Fortran::parser::Variable>(stmt1.t)};
+  const auto &stmt1Expr{std::get<Fortran::parser::Expr>(stmt1.t)};
+
+  const Fortran::parser::AssignmentStmt &stmt2 =
+      std::get<Fortran::parser::OmpAtomicCapture::Stmt2>(
+          atomicCaptureConstruct.t)
+          .v.statement;
+  const auto &stmt2Var{std::get<Fortran::parser::Variable>(stmt2.t)};
+  const auto &stmt2Expr{std::get<Fortran::parser::Expr>(stmt2.t)};
+
+  if (Fortran::semantics::checkForSingleVariableOnRHS(stmt1)) {
+    CheckAtomicCaptureStmt(stmt1);
+    if (Fortran::semantics::checkForSymbolMatch(stmt2)) {
+      // Atomic capture construct is of the form [capture-stmt, update-stmt]
+      CheckAtomicUpdateStmt(stmt2);
+    } else {
+      // Atomic capture construct is of the form [capture-stmt, write-stmt]
+      CheckAtomicWriteStmt(stmt2);
+    }
+    // Variable captured in stmt1 should be assigned in stmt2
+    const auto *e{GetExpr(context_, stmt1Expr)};
+    const auto *v{GetExpr(context_, stmt2Var)};
+    if (e && v) {
+      const Symbol &stmt2VarSymbol = evaluate::GetSymbolVector(*v).front();
+      const Symbol &stmt1ExprSymbol = evaluate::GetSymbolVector(*e).front();
+      if (stmt2VarSymbol != stmt1ExprSymbol)
+        context_.Say(stmt1Expr.source,
+            "Captured variable %s "
+            "expected to be assigned in statement 2 of "
+            "atomic capture construct"_err_en_US,
+            stmt1ExprSymbol.name().ToString());
+    }
+  } else if (Fortran::semantics::checkForSymbolMatch(stmt1) &&
+      Fortran::semantics::checkForSingleVariableOnRHS(stmt2)) {
+    // Atomic capture construct is of the form [update-stmt, capture-stmt]
+    CheckAtomicUpdateStmt(stmt1);
+    CheckAtomicCaptureStmt(stmt2);
+    // Variable updated in stmt1 should be captured in stmt2
+    const auto *e{GetExpr(context_, stmt2Expr)};
+    const auto *v{GetExpr(context_, stmt1Var)};
+    if (e && v) {
+      const Symbol &stmt1VarSymbol = evaluate::GetSymbolVector(*v).front();
+      const Symbol &stmt2ExprSymbol = evaluate::GetSymbolVector(*e).front();
+      if (stmt1VarSymbol != stmt2ExprSymbol)
+        context_.Say(stmt1Var.GetSource(),
+            "Updated variable %s "
+            "expected to be captured in statement 2 of "
+            "atomic capture construct"_err_en_US,
+            stmt1Var.GetSource().ToString());
+    }
+  } else {
+    context_.Say(stmt1Expr.source,
+        "Invalid atomic capture construct statements. "
+        "Expected one of [update-stmt, capture-stmt], "
+        "[capture-stmt, update-stmt], or [capture-stmt, write-stmt]"_err_en_US);
+  }
+}
+
 void OmpStructureChecker::CheckAtomicMemoryOrderClause(
     const parser::OmpAtomicClauseList *leftHandClauseList,
     const parser::OmpAtomicClauseList *rightHandClauseList) {
@@ -2060,15 +2124,15 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
                     atomicWrite.t)
                     .statement);
           },
-          [&](const auto &atomicConstruct) {
-            const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
+          [&](const parser::OmpAtomicCapture &atomicCapture) {
+            const auto &dir{std::get<parser::Verbatim>(atomicCapture.t)};
             PushContextAndClauseSets(
                 dir.source, llvm::omp::Directive::OMPD_atomic);
-            CheckAtomicMemoryOrderClause(&std::get<0>(atomicConstruct.t),
-                &std::get<2>(atomicConstruct.t));
+            CheckAtomicMemoryOrderClause(
+                &std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t));
             CheckHintClause<const parser::OmpAtomicClauseList>(
-                &std::get<0>(atomicConstruct.t),
-                &std::get<2>(atomicConstruct.t));
+                &std::get<0>(atomicCapture.t), &std::get<2>(atomicCapture.t));
+            CheckAtomicCaptureConstruct(atomicCapture);
           },
       },
       x.u);
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 2cc1a78068f540..8bfd4d594b028e 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -193,6 +193,7 @@ class OmpStructureChecker
   void CheckAtomicUpdateStmt(const parser::AssignmentStmt &);
   void CheckAtomicCaptureStmt(const parser::AssignmentStmt &);
   void CheckAtomicWriteStmt(const parser::AssignmentStmt &);
+  void CheckAtomicCaptureConstruct(const parser::OmpAtomicCapture &);
   void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &);
   void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
   void CheckSIMDNest(const parser::OpenMPConstruct &x);
diff --git a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90 b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
index a346056dee383b..09921944e7fc06 100644
--- a/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
+++ b/flang/test/Semantics/OpenMP/omp-atomic-assignment-stmt.f90
@@ -84,4 +84,44 @@ program sample
     !$omp atomic write
     !ERROR: Expected scalar variable on the LHS of atomic assignment statement
         a = x
+
+    !$omp atomic capture
+        v = x
+        x = x + 1
+    !$omp end atomic
+
+    !$omp atomic release capture
+        v = x
+    !ERROR: Atomic update statement should be of form `x = x operator expr` OR `x = expr operator x`
+        x = b + (x*1)
+    !$omp end atomic
+
+    !$omp atomic capture hint(0)
+        v = x
+        x = 1
+    !$omp end atomic
+
+    !$omp atomic capture
+    !ERROR: Captured variable x expected to be assigned in statement 2 of atomic capture construct
+        v = x
+        b = b + 1
+    !$omp end atomic
+
+    !$omp atomic capture
+    !ERROR: Captured variable x expected to be assigned in statement 2 of atomic capture construct
+        v = x
+        b = 10
+    !$omp end atomic
+
+    !$omp atomic capture
+    !ERROR: Updated variable x expected to be captured in statement 2 of atomic capture construct
+        x = x + 10
+        v = b
+    !$omp end atomic
+
+    !$omp atomic capture
+    !ERROR: Invalid atomic capture construct statements. Expected one of [update-stmt, capture-stmt], [capture-stmt, update-stmt], or [capture-stmt, write-stmt]
+        v = 1
+        x = 4
+    !$omp end atomic
 end program
diff --git a/flang/test/Semantics/OpenMP/requires-atomic01.f90 b/flang/test/Semantics/OpenMP/requires-atomic01.f90
index b39c9cdcc0bb33..cb7b1bc1ac52ab 100644
--- a/flang/test/Semantics/OpenMP/requires-atomic01.f90
+++ b/flang/test/Semantics/OpenMP/requires-atomic01.f90
@@ -88,7 +88,7 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> SeqCst
   !$omp atomic capture
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 
   ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture
@@ -96,7 +96,7 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed
   !$omp atomic relaxed capture
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 
   ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture
@@ -104,6 +104,6 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed
   !$omp atomic capture relaxed
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 end program requires
diff --git a/flang/test/Semantics/OpenMP/requires-atomic02.f90 b/flang/test/Semantics/OpenMP/requires-atomic02.f90
index 3af83970e7927a..5a4249794f7b50 100644
--- a/flang/test/Semantics/OpenMP/requires-atomic02.f90
+++ b/flang/test/Semantics/OpenMP/requires-atomic02.f90
@@ -88,7 +88,7 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> AcqRel
   !$omp atomic capture
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 
   ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture
@@ -96,7 +96,7 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed
   !$omp atomic relaxed capture
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 
   ! CHECK-LABEL: OpenMPAtomicConstruct -> OmpAtomicCapture
@@ -104,6 +104,6 @@ program requires
   ! CHECK: OmpMemoryOrderClause -> OmpClause -> Relaxed
   !$omp atomic capture relaxed
   i = j
-  i = j
+  j = j + 1
   !$omp end atomic
 end program requires

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 5.2 standard also appears to allow a conditional update statement as well as write or update. Is that handled here?

I am looking at section 4.3.1.3 page 83

@harishch4
Copy link
Contributor Author

The 5.2 standard also appears to allow a conditional update statement as well as write or update. Is that handled here?

I am looking at section 4.3.1.3 page 83

No, this patch is based on the 5.0 standard. AFAIK flang-new doesn't support compare clause(5.1) fully yet. Please correct me if I'm wrong.

@tblah
Copy link
Contributor

tblah commented Sep 17, 2024

No, this patch is based on the 5.0 standard. AFAIK flang-new doesn't support compare clause(5.1) fully yet. Please correct me if I'm wrong.

If we can parse it then it is worth getting semantics right too. Otherwise adding a TODO in the code is okay.

@harishch4
Copy link
Contributor Author

No, this patch is based on the 5.0 standard. AFAIK flang-new doesn't support compare clause(5.1) fully yet. Please correct me if I'm wrong.

If we can parse it then it is worth getting semantics right too. Otherwise adding a TODO in the code is okay.

Missing parser support as well, added a TODO for now.

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the change. This LGTM but please wait for another reviewer

Comment on lines 760 to 763
for (const Fortran::semantics::Symbol &symbol :
Fortran::evaluate::GetSymbolVector(*e))
if (varSymbol == symbol)
return true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add braces in frontend code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines 2012 to 2017
if (stmt2VarSymbol != stmt1ExprSymbol)
context_.Say(stmt1Expr.source,
"Captured variable %s "
"expected to be assigned in statement 2 of "
"atomic capture construct"_err_en_US,
stmt1ExprSymbol.name().ToString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add braces in frontend code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors are not emitted for the following program. Is that expected?

program mn
  type :: tp
    real :: r1
    real :: r2
  end type
  type(tp) :: r
  real :: cr

  integer :: v1(10), ci

  !$omp atomic capture
    cr = r%r1
    r%r2 = r%r2 + 1.0
  !$omp end atomic

  !$omp atomic capture
  ci = v1(2)
  v1(1) = v1(1) + 1
  !$omp end atomic
end

"Captured variable %s "
"expected to be assigned in the second statement of "
"atomic capture construct"_err_en_US,
stmt1ExprSymbol.name().ToString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToString() is not needed.

"Updated variable %s "
"expected to be captured in the second statement of "
"atomic capture construct"_err_en_US,
stmt1Var.GetSource().ToString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToString() is not needed.

Comment on lines 105 to 117
!ERROR: Captured variable x expected to be assigned in statement 2 of atomic capture construct
v = x
b = b + 1
!$omp end atomic

!$omp atomic capture
!ERROR: Captured variable x expected to be assigned in statement 2 of atomic capture construct
v = x
b = 10
!$omp end atomic

!$omp atomic capture
!ERROR: Updated variable x expected to be captured in statement 2 of atomic capture construct
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR messages have to be updated.

@harishch4
Copy link
Contributor Author

Errors are not emitted for the following program. Is that expected?

Thanks for the review. This is not expected, it looks like gfortran and ifx compilers are also not throwing an error. https://godbolt.org/z/sbYW9Tv3E

@kiranchandramohan
Copy link
Contributor

Errors are not emitted for the following program. Is that expected?

Thanks for the review. This is not expected, it looks like gfortran and ifx compilers are also not throwing an error. https://godbolt.org/z/sbYW9Tv3E

I think it is the use of taking the first symbol from the SymbolVector that is leading to this situation. Could you check the lowering code to see what is used there to match the variable in the atomic update on the RHS?

@harishch4
Copy link
Contributor Author

Errors are not emitted for the following program. Is that expected?

Thanks for the review. This is not expected, it looks like gfortran and ifx compilers are also not throwing an error. https://godbolt.org/z/sbYW9Tv3E

I think it is the use of taking the first symbol from the SymbolVector that is leading to this situation. Could you check the lowering code to see what is used there to match the variable in the atomic update on the RHS?

Even lowering is generating incorrect code, r1 is being used in atomic update instead of r2. Similarly V1(2) instead of V1(1) : https://godbolt.org/z/j4G18938n

@NimishMishra
Copy link
Contributor

I think it is the use of taking the first symbol from the SymbolVector that is leading to this situation. Could you check the lowering code to see what is used there to match the variable in the atomic update on the RHS?

Usage of typed expressions should be able to handle this issue, is it?

@harishch4
Copy link
Contributor Author

@kiranchandramohan I've added the given test cases and it's working as expected. Could you please review it?

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the change. Minor comments inline. LGTM.

Comment on lines 2010 to 2011
"Captured variable %s "
"expected to be assigned in the second statement of "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have this in the same line so that the error message can be easily searched for?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For derived type components and array elements specifying them as variable is not probably accurate.
It is probably variable/array element/derived-type component.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have this in the same line so that the error message can be easily searched for?

Wouldn't it violate the column width limit? Another error message is going to 170 columns. if that's okay, I'll change it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is alrite if it passes the code formatting checks. I think for strings in "" "", the code formatting is lenient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification. I've updated the error messages.

context_.Say(stmt1Expr.source,
"Captured variable %s "
"expected to be assigned in the second statement of "
"atomic capture construct"_err_en_US,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"atomic capture construct"_err_en_US,
"ATOMIC CAPTURE construct"_err_en_US,

@harishch4 harishch4 merged commit 81dac7d into llvm:main Sep 25, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:openmp flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants