[flang][semantics] fix crash involving equivalences (#168909)

This PR fixes
[#166463](https://github.com/llvm/llvm-project/issues/166463) by only
running ProcessScopes at the end of the semantic analysis. ProcessScopes
does an analysis of the entire symbol table to determine which
equivalence statements have conflicting initializations, but it requires
that all symbols in the equivalence statement have valid sizes. Running
before computing the size and offset made this an invalid assumption.
This commit is contained in:
Andre Kuhlenschmidt 2025-12-11 09:16:09 -08:00 committed by GitHub
parent 3d1f04425a
commit dfed044c67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 107 additions and 6 deletions

View file

@ -273,7 +273,7 @@ void DataChecker::Leave(const parser::EntityDecl &decl) {
}
void DataChecker::CompileDataInitializationsIntoInitializers() {
ConvertToInitializers(inits_, exprAnalyzer_);
ConvertToInitializers(inits_, exprAnalyzer_, /*forDerivedTypesOnly=*/false);
}
} // namespace Fortran::semantics

View file

@ -863,6 +863,14 @@ static bool ProcessScopes(const Scope &scope,
if (std::find_if(associated.begin(), associated.end(), [](SymbolRef ref) {
return IsInitialized(*ref);
}) != associated.end()) {
// If a symbol whose size has not been computed it is possible to get an
// assertion failure when trying to contruct the initializer. The lack
// of a size is assumed to be because there was an error reported that
// blocked computing the size. As of writing this comment, this is only
// called after all of semantics analysis has run without errors. If
// this needs to be called earlier, then we need to skip equivalence
// checking if there are any sizeless symbols and assert that there is
// an error reported.
result &=
CombineEquivalencedInitialization(associated, exprAnalyzer, inits);
}
@ -944,8 +952,8 @@ void ConstructInitializer(const Symbol &symbol,
}
}
void ConvertToInitializers(
DataInitializations &inits, evaluate::ExpressionAnalyzer &exprAnalyzer) {
void ConvertToInitializers(DataInitializations &inits,
evaluate::ExpressionAnalyzer &exprAnalyzer, bool forDerivedTypesOnly) {
// 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,7 +961,8 @@ void ConvertToInitializers(
ConstructInitializer(*symbolPtr, initialization, exprAnalyzer);
}
}
if (ProcessScopes(
if (!forDerivedTypesOnly &&
ProcessScopes(
exprAnalyzer.context().globalScope(), exprAnalyzer, inits)) {
for (auto &[symbolPtr, initialization] : inits) {
if (!symbolPtr->owner().IsDerivedType()) {

View file

@ -62,8 +62,8 @@ void AccumulateDataInitializations(DataInitializations &,
evaluate::ExpressionAnalyzer &, const Symbol &,
const std::list<common::Indirection<parser::DataStmtValue>> &);
void ConvertToInitializers(
DataInitializations &, evaluate::ExpressionAnalyzer &);
void ConvertToInitializers(DataInitializations &,
evaluate::ExpressionAnalyzer &, bool forDerivedTypes = true);
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_DATA_TO_INITS_H_

View file

@ -0,0 +1,58 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
program main
! ERROR: A sequence type should have at least one component [-Wempty-sequence-type]
type t0
sequence
end type
type t1
sequence
integer, dimension(2):: i/41, 2/
end type
type t2
sequence
integer :: j(2) = [42, 2]
end type
! ERROR: Distinct default component initializations of equivalenced objects affect 'o1' more than once
type (t0) :: O1
! 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
! ERROR: Distinct default component initializations of equivalenced objects affect 'o2(1_8)' more than once
integer :: x, O2(0)
data x/42/
! ERROR: Distinct default component initializations of equivalenced objects affect 'undeclared' more than once
equivalence (A, B, x, O1, O2, Undeclared)
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

View file

@ -0,0 +1,34 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
! Make sure parameterized derived types can't be used in equivalence sets or contain legacy DATA-style initializations.
program main
type t1
sequence
integer, dimension(2):: i/41, 2/
end type
type pdt(k)
integer, kind :: k
integer, dimension(k + 1):: x = [43, (i, i=2, k+1, 1)]
end type
type pdt1(k)
integer, kind :: k
!ERROR: Component 'x' in a parameterized data type may not be initialized with a legacy DATA-style value list
integer, dimension(k + 1):: x/42, 2/
end type
!ERROR: A sequence type may not have type parameters
type pdt2(k)
integer, kind :: k
sequence
integer, dimension(k + 1):: x = [43, (i, i=2, k+1, 1)]
end type
type (t1) :: A
type (pdt(2)) :: P2
type (pdt(3)) :: P3
type (pdt1(4)) :: P4
type (pdt2(5)) :: P5
! ERROR: Nonsequence derived type object 'p2' is not allowed in an equivalence set
! ERROR: Nonsequence derived type object 'p3' is not allowed in an equivalence set
! ERROR: Nonsequence derived type object 'p4' is not allowed in an equivalence set
equivalence (A, B, P2, P3, P4, P5)
end