Skip to content

Commit 5a402c5

Browse files
authored
[flang] USE-associated explicit INTRINSIC names (#76199)
The compiler doesn't USE-associate names of intrinsic procedures from modules (in the absence of ONLY:), so that the associating scope doesn't get populated with names of intrinsics that were used only in declarations (e.g., SELECTED_REAL_KIND). A recent bug report (below) shows that we should modify that policy in the case of names that appear in explicit INTRINSIC attribute statements. The behaviors of other Fortran compilers are not consistent and the requirements of the standard are not clear; this fix follows the precedent set by gfortran and nvfortran. Fixes #72084.
1 parent c86fe3e commit 5a402c5

File tree

5 files changed

+81
-23
lines changed

5 files changed

+81
-23
lines changed

flang/docs/Extensions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,10 @@ module m
641641
end
642642
```
643643

644+
* When an intrinsic procedure appears in the specification part of a module
645+
only in function references, but not an explicit `INTRINSIC` statement,
646+
its name is not brought into other scopes by a `USE` statement.
647+
644648
## De Facto Standard Features
645649

646650
* `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the

flang/lib/Semantics/resolve-names.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2904,7 +2904,7 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
29042904
}
29052905
for (const auto &[name, symbol] : *useModuleScope_) {
29062906
if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) &&
2907-
(!symbol->attrs().test(Attr::INTRINSIC) ||
2907+
(!symbol->implicitAttrs().test(Attr::INTRINSIC) ||
29082908
symbol->has<UseDetails>()) &&
29092909
!symbol->has<MiscDetails>() && useNames.count(name) == 0) {
29102910
SourceName location{x.moduleName.source};
@@ -2998,7 +2998,7 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
29982998
details->add_occurrence(location, *useModuleScope_);
29992999
return;
30003000
}
3001-
3001+
const Symbol &useUltimate{useSymbol.GetUltimate()};
30023002
if (localSymbol.has<UnknownDetails>()) {
30033003
localSymbol.set_details(UseDetails{localName, useSymbol});
30043004
localSymbol.attrs() =
@@ -3010,7 +3010,6 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30103010
}
30113011

30123012
Symbol &localUltimate{localSymbol.GetUltimate()};
3013-
const Symbol &useUltimate{useSymbol.GetUltimate()};
30143013
if (&localUltimate == &useUltimate) {
30153014
// use-associating the same symbol again -- ok
30163015
return;
@@ -3044,37 +3043,42 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
30443043
checkAmbiguousDerivedType(&useUltimate, localGeneric->derivedType());
30453044
} else if (&useUltimate == &BypassGeneric(localUltimate).GetUltimate()) {
30463045
return; // nothing to do; used subprogram is local's specific
3046+
} else if (useUltimate.attrs().test(Attr::INTRINSIC) &&
3047+
useUltimate.name() == localSymbol.name()) {
3048+
return; // local generic can extend intrinsic
30473049
}
30483050
} else if (useGeneric) {
30493051
if (localUltimate.has<DerivedTypeDetails>()) {
30503052
combine =
30513053
checkAmbiguousDerivedType(&localUltimate, useGeneric->derivedType());
3052-
} else if (&localUltimate == &BypassGeneric(useUltimate).GetUltimate()) {
3053-
// Local is the specific of the used generic; replace it.
3054+
} else if (&localUltimate == &BypassGeneric(useUltimate).GetUltimate() ||
3055+
(localSymbol.attrs().test(Attr::INTRINSIC) &&
3056+
localUltimate.name() == useUltimate.name())) {
3057+
// Local is the specific of the used generic or an intrinsic with the
3058+
// same name; replace it.
30543059
EraseSymbol(localSymbol);
30553060
Symbol &newSymbol{MakeSymbol(localName,
30563061
useUltimate.attrs() & ~Attrs{Attr::PUBLIC, Attr::PRIVATE},
30573062
UseDetails{localName, useUltimate})};
30583063
newSymbol.flags() = useSymbol.flags();
30593064
return;
30603065
}
3066+
} else if (localUltimate.name() != useUltimate.name()) {
3067+
// not the same procedure
3068+
} else if (localUltimate.attrs().test(Attr::INTRINSIC) &&
3069+
useUltimate.attrs().test(Attr::INTRINSIC)) {
3070+
return;
30613071
} else {
30623072
auto localClass{ClassifyProcedure(localUltimate)};
30633073
auto useClass{ClassifyProcedure(useUltimate)};
3064-
if (localClass == useClass &&
3065-
(localClass == ProcedureDefinitionClass::Intrinsic ||
3066-
localClass == ProcedureDefinitionClass::External) &&
3067-
localUltimate.name() == useUltimate.name()) {
3074+
if (localClass == ProcedureDefinitionClass::External &&
3075+
useClass == ProcedureDefinitionClass::External) {
30683076
auto localChars{evaluate::characteristics::Procedure::Characterize(
30693077
localUltimate, GetFoldingContext())};
30703078
auto useChars{evaluate::characteristics::Procedure::Characterize(
30713079
useUltimate, GetFoldingContext())};
3072-
if (localChars && useChars) {
3073-
if (*localChars == *useChars) {
3074-
// Same intrinsic or external procedure defined identically in two
3075-
// modules
3076-
return;
3077-
}
3080+
if (localChars && useChars && *localChars == *useChars) {
3081+
return; // same procedure defined identically in two modules
30783082
}
30793083
}
30803084
}
@@ -4794,9 +4798,15 @@ Symbol &DeclarationVisitor::HandleAttributeStmt(
47944798
}
47954799
}
47964800
} else if (symbol && symbol->has<UseDetails>()) {
4797-
Say(currStmtSource().value(),
4798-
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
4799-
EnumToString(attr), name.source);
4801+
if (symbol->GetUltimate().attrs().test(attr)) {
4802+
Say(currStmtSource().value(),
4803+
"Use-associated '%s' already has '%s' attribute"_warn_en_US,
4804+
name.source, EnumToString(attr));
4805+
} else {
4806+
Say(currStmtSource().value(),
4807+
"Cannot change %s attribute on use-associated '%s'"_err_en_US,
4808+
EnumToString(attr), name.source);
4809+
}
48004810
return *symbol;
48014811
}
48024812
if (!symbol) {
@@ -6244,8 +6254,8 @@ bool DeclarationVisitor::HandleUnrestrictedSpecificIntrinsicFunction(
62446254
// recreated for it later on demand, but capturing its result type here
62456255
// will make GetType() return a correct result without having to
62466256
// probe the intrinsics table again.
6247-
Symbol &symbol{
6248-
MakeSymbol(InclusiveScope(), name.source, Attrs{Attr::INTRINSIC})};
6257+
Symbol &symbol{MakeSymbol(InclusiveScope(), name.source, Attrs{})};
6258+
SetImplicitAttr(symbol, Attr::INTRINSIC);
62496259
CHECK(interface->functionResult.has_value());
62506260
evaluate::DynamicType dyType{
62516261
DEREF(interface->functionResult->GetTypeAndShape()).type()};
@@ -7708,8 +7718,8 @@ void ResolveNamesVisitor::HandleProcedureName(
77087718
auto *symbol{FindSymbol(NonDerivedTypeScope(), name)};
77097719
if (!symbol) {
77107720
if (IsIntrinsic(name.source, flag)) {
7711-
symbol =
7712-
&MakeSymbol(InclusiveScope(), name.source, Attrs{Attr::INTRINSIC});
7721+
symbol = &MakeSymbol(InclusiveScope(), name.source, Attrs{});
7722+
SetImplicitAttr(*symbol, Attr::INTRINSIC);
77137723
} else if (const auto ppcBuiltinScope =
77147724
currScope().context().GetPPCBuiltinsScope()) {
77157725
// Check if it is a builtin from the predefined module
@@ -8047,6 +8057,11 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
80478057
} else if (ultimate.has<SubprogramDetails>() ||
80488058
ultimate.has<SubprogramNameDetails>()) {
80498059
genericDetails.set_specific(*existing);
8060+
} else if (ultimate.has<ProcEntityDetails>()) {
8061+
if (existing->name() != symbolName ||
8062+
!ultimate.attrs().test(Attr::INTRINSIC)) {
8063+
genericDetails.set_specific(*existing);
8064+
}
80508065
} else if (ultimate.has<DerivedTypeDetails>()) {
80518066
genericDetails.set_derivedType(*existing);
80528067
} else if (&existing->owner() == &currScope()) {

flang/module/iso_fortran_env.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module iso_fortran_env
2323
compiler_version => __builtin_compiler_version
2424

2525
implicit none
26+
private count
2627

2728
! TODO: Use PACK([x],test) in place of the array constructor idiom
2829
! [(x, integer::j=1,COUNT([test]))] below once PACK() can be folded.

flang/test/Semantics/contiguous01.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module m0
55
end
66
module m
77
use m0
8-
!ERROR: Cannot change CONTIGUOUS attribute on use-associated 'p1'
8+
!WARNING: Use-associated 'p1' already has 'CONTIGUOUS' attribute
99
contiguous p1
1010
!ERROR: Cannot change CONTIGUOUS attribute on use-associated 'p2'
1111
contiguous p2

flang/test/Semantics/intrinsics02.f90

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
module explicit
3+
intrinsic cos
4+
end
5+
subroutine testExplicit
6+
use explicit
7+
!ERROR: 'cos' is use-associated from module 'explicit' and cannot be re-declared
8+
real :: cos = 2.
9+
end
10+
subroutine extendsUsedIntrinsic
11+
use explicit
12+
interface cos
13+
pure real function mycos(x)
14+
real, intent(in) :: x
15+
end
16+
end interface
17+
end
18+
subroutine sameIntrinsic1
19+
use explicit
20+
!WARNING: Use-associated 'cos' already has 'INTRINSIC' attribute
21+
intrinsic cos
22+
real :: one = cos(0.)
23+
end
24+
module renamer
25+
use explicit, renamedCos => cos
26+
end
27+
subroutine sameIntrinsic2
28+
use explicit
29+
use renamer, cos => renamedCos
30+
real :: one = cos(0.)
31+
end
32+
module implicit
33+
real :: one = cos(0.)
34+
end
35+
subroutine testImplicit
36+
use implicit
37+
real :: cos = 2.
38+
end

0 commit comments

Comments
 (0)