[flang-commits] [flang] [flang][semantics] fix crash involving equivalences (PR #168909)
Andre Kuhlenschmidt via flang-commits
flang-commits at lists.llvm.org
Thu Nov 20 09:14:55 PST 2025
https://github.com/akuhlens created https://github.com/llvm/llvm-project/pull/168909
This PR does three things.
0. Adds a test case that before this PR caused the compiler to crash.
1. It makes `ProcessScopes` more resilient to data that hasn't had it's size set, instead it now just returns false to indicate that it encountered an error during processing instead of signalling an internal compiler error.
- If we decide to omit the reduction in the number of times we run `ProcessScopes` we will need to keep this change.
- Otherwise, I think this code should be unreachable, if it is reachable we should have some semantic error that covers the
reason we were unable to give the variable a size.
- This might be unacceptable hardening because there might be the possibility of having zero sized arrays that flow to this code. If so, I would appreciate suggestion about how to correct this hardening.
2. It only runs ProcessScopes at the end of the semantic analysis, therefore
- If we decide to keep this, we should be able to get rid of the first change.
Mostly presenting both fixes, because I am not sure if there are missing test cases that don't cover why the code wasn't changed to be there second option from the beginning.
>From 777416025ba70793e12ff94ebc8733dc417678ec Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 19 Nov 2025 16:11:18 -0800
Subject: [PATCH 1/3] initial commit
---
flang/lib/Semantics/data-to-inits.cpp | 20 ++++++++--
flang/test/Semantics/equivalence02.f90 | 51 ++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 3 deletions(-)
create mode 100644 flang/test/Semantics/equivalence02.f90
diff --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index bbf3b28fe03e6..6ccf44405e299 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -863,8 +863,17 @@ static bool ProcessScopes(const Scope &scope,
if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
return IsInitialized(*ref);
}) != associated.end()) {
- result &=
- CombineEquivalencedInitialization(associated, exprAnalyzer, inits);
+ if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
+ return !ref->size();
+ }) != associated.end()) {
+ // If a symbol has a non-legacy initialization, it won't have a size, so we can't combine its initializations
+ // the DataChecker Runs after this size is computed and runs this code again so it will have a size when encountered
+ // later.
+ result = false;
+ } else {
+ result &=
+ CombineEquivalencedInitialization(associated, exprAnalyzer, inits);
+ }
}
}
if constexpr (makeDefaultInitializationExplicit) {
@@ -945,7 +954,7 @@ void ConstructInitializer(const Symbol &symbol,
}
void ConvertToInitializers(
- DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {
+ DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {\
// Process DATA-style component /initializers/ now, so that they appear as
// default values in time for EQUIVALENCE processing in ProcessScopes.
for (auto &[symbolPtr, initialization] : inits) {
@@ -953,6 +962,11 @@ void ConvertToInitializers(
ConstructInitializer(*symbolPtr, initialization, exprAnalyzer);
}
}
+ // FIXME: It is kinda weird that we need to repeatedly process the entire symbol table
+ // each time this is called by LegacyDataInitialization in ResolveNames. Could we do this
+ // once before the DataChecker and once after to combine initializations from Non-Legacy
+ // Initialization?
+ // Note, it passes all tests with just Running this code in CompileDataInitializationsIntoInitializers.
if (ProcessScopes(
exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) {
for (auto &[symbolPtr, initialization] : inits) {
diff --git a/flang/test/Semantics/equivalence02.f90 b/flang/test/Semantics/equivalence02.f90
new file mode 100644
index 0000000000000..6087f43d8c2c3
--- /dev/null
+++ b/flang/test/Semantics/equivalence02.f90
@@ -0,0 +1,51 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+
+program main
+type t1
+ sequence
+ integer, dimension(2):: i/42, 1/
+end type
+type t2
+ sequence
+ integer :: j(2) = [41, 1]
+end type
+
+! ERROR: Distinct default component initializations of equivalenced objects affect 'a%i(1_8)' more than once
+type (t1) :: A
+! ERROR: Distinct default component initializations of equivalenced objects affect 'b%j(1_8)' more than once
+type (t2) :: B
+! ERROR: Distinct default component initializations of equivalenced objects affect 'x' more than once
+integer :: x
+data x/42/
+equivalence (A, B, x)
+call p(x)
+call s()
+end
+
+subroutine s()
+ type g1
+ sequence
+ integer(kind=8)::d/1_8/
+ end type
+ type g2
+ sequence
+ integer(kind=8)::d = 2_8
+ end type
+ ! ERROR: Distinct default component initializations of equivalenced objects affect 'c%d' more than once
+ type (g1) :: C
+ ! ERROR: Distinct default component initializations of equivalenced objects affect 'd%d' more than once
+ type (g2) :: D
+ ! ERROR: Distinct default component initializations of equivalenced objects affect 'x' more than once
+ ! ERROR: Distinct default component initializations of equivalenced objects affect 'y' more than once
+ integer :: x, y
+ data x/1/, y/2/
+ equivalence (C, x)
+ equivalence (D, y)
+ equivalence (x, y)
+ print *, x, y
+end subroutine
+
+subroutine p(x)
+ integer :: x
+ print *, x
+end subroutine
>From 10219ceac7dcd0e87ed610bd6f97dd0f46959968 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 20 Nov 2025 08:54:50 -0800
Subject: [PATCH 2/3] reduce running process scopes to once
---
flang/lib/Semantics/check-data.cpp | 2 +-
flang/lib/Semantics/data-to-inits.cpp | 4 ++--
flang/lib/Semantics/data-to-inits.h | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp
index 3bcf711735158..af89fd7a29e37 100644
--- a/flang/lib/Semantics/check-data.cpp
+++ b/flang/lib/Semantics/check-data.cpp
@@ -273,7 +273,7 @@ void DataChecker::Leave(const parser::EntityDecl &decl) {
}
void DataChecker::CompileDataInitializationsIntoInitializers() {
- ConvertToInitializers(inits_, exprAnalyzer_);
+ ConvertToInitializers(inits_, exprAnalyzer_, /*processScopes=*/true);
}
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index 6ccf44405e299..47347e5912254 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -954,7 +954,7 @@ void ConstructInitializer(const Symbol &symbol,
}
void ConvertToInitializers(
- DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {\
+ DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer, bool processScopes) {
// Process DATA-style component /initializers/ now, so that they appear as
// default values in time for EQUIVALENCE processing in ProcessScopes.
for (auto &[symbolPtr, initialization] : inits) {
@@ -967,7 +967,7 @@ void ConvertToInitializers(
// once before the DataChecker and once after to combine initializations from Non-Legacy
// Initialization?
// Note, it passes all tests with just Running this code in CompileDataInitializationsIntoInitializers.
- if (ProcessScopes(
+ if (processScopes && ProcessScopes(
exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) {
for (auto &[symbolPtr, initialization] : inits) {
if (!symbolPtr->owner().IsDerivedType()) {
diff --git a/flang/lib/Semantics/data-to-inits.h b/flang/lib/Semantics/data-to-inits.h
index 7486ac8113e90..7e8779d4faaec 100644
--- a/flang/lib/Semantics/data-to-inits.h
+++ b/flang/lib/Semantics/data-to-inits.h
@@ -63,7 +63,7 @@ void AccumulateDataInitializations(DataInitializations &,
const std::list<common::Indirection<parser::DataStmtValue>> &);
void ConvertToInitializers(
- DataInitializations &, evaluate::ExpressionAnalyzer &);
+ DataInitializations &, evaluate::ExpressionAnalyzer &, bool ProcessScopes = false);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_DATA_TO_INITS_H_
>From fcae214b7e8dc96e10df283ab4d00d9387646bd8 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Thu, 20 Nov 2025 08:55:33 -0800
Subject: [PATCH 3/3] clang format
---
flang/lib/Semantics/data-to-inits.cpp | 35 +++++++++++++++------------
flang/lib/Semantics/data-to-inits.h | 4 +--
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp
index 47347e5912254..af4fffaf9f23b 100644
--- a/flang/lib/Semantics/data-to-inits.cpp
+++ b/flang/lib/Semantics/data-to-inits.cpp
@@ -863,16 +863,17 @@ static bool ProcessScopes(const Scope &scope,
if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
return IsInitialized(*ref);
}) != associated.end()) {
- if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
- return !ref->size();
- }) != associated.end()) {
- // If a symbol has a non-legacy initialization, it won't have a size, so we can't combine its initializations
- // the DataChecker Runs after this size is computed and runs this code again so it will have a size when encountered
- // later.
+ if (std::find_if(associated.begin(), associated.end(),
+ [](SymbolRef ref) { return !ref->size(); }) !=
+ associated.end()) {
+ // If a symbol has a non-legacy initialization, it won't have a size,
+ // so we can't combine its initializations the DataChecker Runs after
+ // this size is computed and runs this code again so it will have a
+ // size when encountered later.
result = false;
} else {
- result &=
- CombineEquivalencedInitialization(associated, exprAnalyzer, inits);
+ result &= CombineEquivalencedInitialization(
+ associated, exprAnalyzer, inits);
}
}
}
@@ -953,8 +954,8 @@ void ConstructInitializer(const Symbol &symbol,
}
}
-void ConvertToInitializers(
- DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer, bool processScopes) {
+void ConvertToInitializers(DataInitializations &inits,
+ evaluate::ExpressionAnalyzer &exprAnalyzer, bool processScopes) {
// Process DATA-style component /initializers/ now, so that they appear as
// default values in time for EQUIVALENCE processing in ProcessScopes.
for (auto &[symbolPtr, initialization] : inits) {
@@ -962,12 +963,14 @@ void ConvertToInitializers(
ConstructInitializer(*symbolPtr, initialization, exprAnalyzer);
}
}
- // FIXME: It is kinda weird that we need to repeatedly process the entire symbol table
- // each time this is called by LegacyDataInitialization in ResolveNames. Could we do this
- // once before the DataChecker and once after to combine initializations from Non-Legacy
- // Initialization?
- // Note, it passes all tests with just Running this code in CompileDataInitializationsIntoInitializers.
- if (processScopes && ProcessScopes(
+ // FIXME: It is kinda weird that we need to repeatedly process the entire
+ // symbol table each time this is called by LegacyDataInitialization in
+ // ResolveNames. Could we do this once before the DataChecker and once after
+ // to combine initializations from Non-Legacy Initialization? Note, it passes
+ // all tests with just Running this code in
+ // CompileDataInitializationsIntoInitializers.
+ if (processScopes &&
+ ProcessScopes(
exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) {
for (auto &[symbolPtr, initialization] : inits) {
if (!symbolPtr->owner().IsDerivedType()) {
diff --git a/flang/lib/Semantics/data-to-inits.h b/flang/lib/Semantics/data-to-inits.h
index 7e8779d4faaec..57fce123ee325 100644
--- a/flang/lib/Semantics/data-to-inits.h
+++ b/flang/lib/Semantics/data-to-inits.h
@@ -62,8 +62,8 @@ void AccumulateDataInitializations(DataInitializations &,
evaluate::ExpressionAnalyzer &, const Symbol &,
const std::list<common::Indirection<parser::DataStmtValue>> &);
-void ConvertToInitializers(
- DataInitializations &, evaluate::ExpressionAnalyzer &, bool ProcessScopes = false);
+void ConvertToInitializers(DataInitializations &,
+ evaluate::ExpressionAnalyzer &, bool ProcessScopes = false);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_DATA_TO_INITS_H_
More information about the flang-commits
mailing list