[flang-commits] [flang] 75f9b18 - [flang] Compile-time checks for shape conformance on assignments
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Thu Aug 18 14:57:24 PDT 2022
Author: Peter Klausler
Date: 2022-08-18T14:52:38-07:00
New Revision: 75f9b189889aae31de209e0554b3ba20998cf659
URL: https://github.com/llvm/llvm-project/commit/75f9b189889aae31de209e0554b3ba20998cf659
DIFF: https://github.com/llvm/llvm-project/commit/75f9b189889aae31de209e0554b3ba20998cf659.diff
LOG: [flang] Compile-time checks for shape conformance on assignments
Assignment statements need to check for array shape conformance
errors that are discernable at compilation time.
Differential Revision: https://reviews.llvm.org/D132161
Added:
flang/test/Semantics/assign10.f90
Modified:
flang/lib/Semantics/expression.cpp
flang/test/Lower/Intrinsics/matmul.f90
flang/test/Lower/array-constructor-2.f90
flang/test/Semantics/array-constr-values.f90
Removed:
################################################################################
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index dacfe796f3627..39f3fb8bfc0b6 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -150,6 +150,7 @@ class ArgumentAnalyzer {
bool IsIntrinsicConcat() const;
bool CheckConformance();
+ bool CheckAssignmentConformance();
bool CheckForNullPointer(const char *where = "as an operand here");
// Find and return a user-defined operator or report an error.
@@ -2558,10 +2559,12 @@ void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
if (!x.typedAssignment) {
ArgumentAnalyzer analyzer{*this};
- analyzer.Analyze(std::get<parser::Variable>(x.t));
+ const auto &variable{std::get<parser::Variable>(x.t)};
+ analyzer.Analyze(variable);
analyzer.Analyze(std::get<parser::Expr>(x.t));
std::optional<Assignment> assignment;
if (!analyzer.fatalErrors()) {
+ auto restorer{GetContextualMessages().SetLocation(variable.GetSource())};
std::optional<ProcedureRef> procRef{analyzer.TryDefinedAssignment()};
if (!procRef) {
analyzer.CheckForNullPointer(
@@ -3478,6 +3481,28 @@ bool ArgumentAnalyzer::CheckConformance() {
return true; // no proven problem
}
+bool ArgumentAnalyzer::CheckAssignmentConformance() {
+ if (actuals_.size() == 2) {
+ const auto *lhs{actuals_.at(0).value().UnwrapExpr()};
+ const auto *rhs{actuals_.at(1).value().UnwrapExpr()};
+ if (lhs && rhs) {
+ auto &foldingContext{context_.GetFoldingContext()};
+ auto lhShape{GetShape(foldingContext, *lhs)};
+ auto rhShape{GetShape(foldingContext, *rhs)};
+ if (lhShape && rhShape) {
+ if (!evaluate::CheckConformance(foldingContext.messages(), *lhShape,
+ *rhShape, CheckConformanceFlags::RightScalarExpandable,
+ "left-hand side", "right-hand side")
+ .value_or(true /*ok when conformance is not known now*/)) {
+ fatalErrors_ = true;
+ return false;
+ }
+ }
+ }
+ }
+ return true; // no proven problem
+}
+
bool ArgumentAnalyzer::CheckForNullPointer(const char *where) {
for (const std::optional<ActualArgument> &arg : actuals_) {
if (arg) {
@@ -3579,6 +3604,9 @@ std::optional<ProcedureRef> ArgumentAnalyzer::TryDefinedAssignment() {
if (lhsType && rhsType) {
AddAssignmentConversion(*lhsType, *rhsType);
}
+ if (!fatalErrors_) {
+ CheckAssignmentConformance();
+ }
return std::nullopt; // user-defined assignment not allowed for these args
}
auto restorer{context_.GetContextualMessages().SetLocation(source_)};
diff --git a/flang/test/Lower/Intrinsics/matmul.f90 b/flang/test/Lower/Intrinsics/matmul.f90
index dedd09cae99fe..2c1211d10e1d9 100644
--- a/flang/test/Lower/Intrinsics/matmul.f90
+++ b/flang/test/Lower/Intrinsics/matmul.f90
@@ -4,13 +4,13 @@
! Test matmul intrinsic
! CHECK-LABEL: matmul_test
-! CHECK-SAME: (%[[X:.*]]: !fir.ref<!fir.array<3x1xf32>>{{.*}}, %[[Y:.*]]: !fir.ref<!fir.array<1x3xf32>>{{.*}}, %[[Z:.*]]: !fir.ref<!fir.array<2x2xf32>>{{.*}})
+! CHECK-SAME: (%[[X:.*]]: !fir.ref<!fir.array<3x1xf32>>{{.*}}, %[[Y:.*]]: !fir.ref<!fir.array<1x3xf32>>{{.*}}, %[[Z:.*]]: !fir.ref<!fir.array<3x3xf32>>{{.*}})
! CHECK: %[[RESULT_BOX_ADDR:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?x?xf32>>>
! CHECK: %[[C3:.*]] = arith.constant 3 : index
! CHECK: %[[C1:.*]] = arith.constant 1 : index
! CHECK: %[[C1_0:.*]] = arith.constant 1 : index
! CHECK: %[[C3_1:.*]] = arith.constant 3 : index
-! CHECK: %[[Z_BOX:.*]] = fir.array_load %[[Z]]({{.*}}) : (!fir.ref<!fir.array<2x2xf32>>, !fir.shape<2>) -> !fir.array<2x2xf32>
+! CHECK: %[[Z_BOX:.*]] = fir.array_load %[[Z]]({{.*}}) : (!fir.ref<!fir.array<3x3xf32>>, !fir.shape<2>) -> !fir.array<3x3xf32>
! CHECK: %[[X_SHAPE:.*]] = fir.shape %[[C3]], %[[C1]] : (index, index) -> !fir.shape<2>
! CHECK: %[[X_BOX:.*]] = fir.embox %[[X]](%[[X_SHAPE]]) : (!fir.ref<!fir.array<3x1xf32>>, !fir.shape<2>) -> !fir.box<!fir.array<3x1xf32>>
! CHECK: %[[Y_SHAPE:.*]] = fir.shape %[[C1_0]], %[[C3_1]] : (index, index) -> !fir.shape<2>
@@ -31,10 +31,10 @@
! CHECK: {{.*}}fir.array_update
! CHECK: fir.result
! CHECK: }
-! CHECK: fir.array_merge_store %[[Z_BOX]], %[[Z_COPY_FROM_RESULT]] to %[[Z]] : !fir.array<2x2xf32>, !fir.array<2x2xf32>, !fir.ref<!fir.array<2x2xf32>>
+! CHECK: fir.array_merge_store %[[Z_BOX]], %[[Z_COPY_FROM_RESULT]] to %[[Z]] : !fir.array<3x3xf32>, !fir.array<3x3xf32>, !fir.ref<!fir.array<3x3xf32>>
! CHECK: fir.freemem %[[RESULT_TMP]] : !fir.heap<!fir.array<?x?xf32>>
subroutine matmul_test(x,y,z)
- real :: x(3,1), y(1,3), z(2,2)
+ real :: x(3,1), y(1,3), z(3,3)
z = matmul(x,y)
end subroutine
diff --git a/flang/test/Lower/array-constructor-2.f90 b/flang/test/Lower/array-constructor-2.f90
index b99b97e96213d..a54ec5483d532 100644
--- a/flang/test/Lower/array-constructor-2.f90
+++ b/flang/test/Lower/array-constructor-2.f90
@@ -146,7 +146,7 @@ end subroutine test5
! CHECK-LABEL: func @_QPtest6(
subroutine test6(c, d, e)
- character(5) :: c(3)
+ character(5) :: c(2)
character(5) :: d, e
! CHECK: = fir.allocmem !fir.array<2x!fir.char<1,5>>
! CHECK: fir.call @realloc
diff --git a/flang/test/Semantics/array-constr-values.f90 b/flang/test/Semantics/array-constr-values.f90
index 2b5198f6dea78..860a3a3d98b32 100644
--- a/flang/test/Semantics/array-constr-values.f90
+++ b/flang/test/Semantics/array-constr-values.f90
@@ -3,7 +3,7 @@
! C7110, C7111, C7112, C7113, C7114, C7115
subroutine arrayconstructorvalues()
- integer :: intarray(5)
+ integer :: intarray(4)
integer(KIND=8) :: k8 = 20
TYPE EMPLOYEE
diff --git a/flang/test/Semantics/assign10.f90 b/flang/test/Semantics/assign10.f90
new file mode 100644
index 0000000000000..6b98097bfe62c
--- /dev/null
+++ b/flang/test/Semantics/assign10.f90
@@ -0,0 +1,23 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Shape conformance checks on assignments
+program test
+ real :: a0, a1a(2), a1b(3), a2a(2,3), a2b(3,2)
+ a0 = 0. ! ok
+ !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches scalar REAL(4) and rank 1 array of REAL(4)
+ a0 = [0.]
+ a1a = 0. ! ok
+ a1a = [(real(j),j=1,2)] ! ok
+ !ERROR: Dimension 1 of left-hand side has extent 2, but right-hand side has extent 3
+ a1a = [(real(j),j=1,3)]
+ !ERROR: Dimension 1 of left-hand side has extent 3, but right-hand side has extent 2
+ a1b = a1a
+ !ERROR: No intrinsic or user-defined ASSIGNMENT(=) matches rank 1 array of REAL(4) and rank 2 array of REAL(4)
+ a1a = a2a
+ a1a = a2a(:,1) ! ok
+ a2a = 0. ! ok
+ a2a(:,1) = a1a ! ok
+ !ERROR: Dimension 1 of left-hand side has extent 3, but right-hand side has extent 2
+ a2a(1,:) = a1a
+ !ERROR: Dimension 1 of left-hand side has extent 2, but right-hand side has extent 3
+ a2a = a2b
+end
More information about the flang-commits
mailing list