From: Peter Klausler Date: Mon, 15 Aug 2022 20:24:46 +0000 (-0700) Subject: [flang] Compile-time checks for shape conformance on assignments X-Git-Tag: upstream/17.0.6~36085 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=75f9b189889aae31de209e0554b3ba20998cf659;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index dacfe79..39f3fb8 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -150,6 +150,7 @@ public: 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(x.t)); + const auto &variable{std::get(x.t)}; + analyzer.Analyze(variable); analyzer.Analyze(std::get(x.t)); std::optional assignment; if (!analyzer.fatalErrors()) { + auto restorer{GetContextualMessages().SetLocation(variable.GetSource())}; std::optional 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 &arg : actuals_) { if (arg) { @@ -3579,6 +3604,9 @@ std::optional 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 dedd09c..2c1211d 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>{{.*}}, %[[Y:.*]]: !fir.ref>{{.*}}, %[[Z:.*]]: !fir.ref>{{.*}}) +! CHECK-SAME: (%[[X:.*]]: !fir.ref>{{.*}}, %[[Y:.*]]: !fir.ref>{{.*}}, %[[Z:.*]]: !fir.ref>{{.*}}) ! CHECK: %[[RESULT_BOX_ADDR:.*]] = fir.alloca !fir.box>> ! 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.shape<2>) -> !fir.array<2x2xf32> +! CHECK: %[[Z_BOX:.*]] = fir.array_load %[[Z]]({{.*}}) : (!fir.ref>, !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.shape<2>) -> !fir.box> ! 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> +! CHECK: fir.array_merge_store %[[Z_BOX]], %[[Z_COPY_FROM_RESULT]] to %[[Z]] : !fir.array<3x3xf32>, !fir.array<3x3xf32>, !fir.ref> ! CHECK: fir.freemem %[[RESULT_TMP]] : !fir.heap> 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 b99b97e..a54ec54 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 2b5198f..860a3a3 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 0000000..6b98097b --- /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