Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 44 additions & 17 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,10 @@ class FuncResultStack {
// Result symbol
Symbol *resultSymbol{nullptr};
bool inFunctionStmt{false}; // true between Pre/Post of FunctionStmt
// Functions with previous implicitly-typed references get those types
// checked against their later definitions.
const DeclTypeSpec *previousImplicitType{nullptr};
SourceName previousName;
};

// Completes the definition of the top function's result.
Expand Down Expand Up @@ -943,7 +947,7 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
// Edits an existing symbol created for earlier calls to a subprogram or ENTRY
// so that it can be replaced by a later definition.
bool HandlePreviousCalls(const parser::Name &, Symbol &, Symbol::Flag);
void CheckExtantProc(const parser::Name &, Symbol::Flag);
const Symbol *CheckExtantProc(const parser::Name &, Symbol::Flag);
// Create a subprogram symbol in the current scope and push a new scope.
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag,
const parser::LanguageBindingSpec * = nullptr,
Expand Down Expand Up @@ -2691,11 +2695,17 @@ void ArraySpecVisitor::PostAttrSpec() {

FuncResultStack::~FuncResultStack() { CHECK(stack_.empty()); }

static bool TypesMismatchIfNonNull(
const DeclTypeSpec *type1, const DeclTypeSpec *type2) {
return type1 && type2 && *type1 != *type2;
}

void FuncResultStack::CompleteFunctionResultType() {
// If the function has a type in the prefix, process it now.
FuncInfo *info{Top()};
if (info && &info->scope == &scopeHandler_.currScope()) {
if (info->parsedType && info->resultSymbol) {
if (info && &info->scope == &scopeHandler_.currScope() &&
info->resultSymbol) {
if (info->parsedType) {
scopeHandler_.messageHandler().set_currStmtSource(info->source);
if (const auto *type{
scopeHandler_.ProcessTypeSpec(*info->parsedType, true)}) {
Expand All @@ -2712,6 +2722,16 @@ void FuncResultStack::CompleteFunctionResultType() {
}
info->parsedType = nullptr;
}
if (TypesMismatchIfNonNull(
info->resultSymbol->GetType(), info->previousImplicitType)) {
scopeHandler_
.Say(info->resultSymbol->name(),
"Function '%s' has a result type that differs from the implicit type it obtained in a previous reference"_err_en_US,
info->previousName)
.Attach(info->previousName,
"Previous reference implicitly typed as %s\n"_en_US,
info->previousImplicitType->AsFortran());
}
}
}

Expand Down Expand Up @@ -4761,9 +4781,7 @@ void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
if (info.resultName && !distinctResultName) {
context().Warn(common::UsageWarning::HomonymousResult,
info.resultName->source,
"The function name should not appear in RESULT; references to '%s' "
"inside the function will be considered as references to the "
"result only"_warn_en_US,
"The function name should not appear in RESULT; references to '%s' inside the function will be considered as references to the result only"_warn_en_US,
name.source);
// RESULT name was ignored above, the only side effect from doing so will be
// the inability to make recursive calls. The related parser::Name is still
Expand Down Expand Up @@ -5074,8 +5092,7 @@ bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
if (hasModulePrefix && !currScope().IsModule() &&
!currScope().IsSubmodule()) { // C1547
Say(name,
"'%s' is a MODULE procedure which must be declared within a "
"MODULE or SUBMODULE"_err_en_US);
"'%s' is a MODULE procedure which must be declared within a MODULE or SUBMODULE"_err_en_US);
// Don't return here because it can be useful to have the scope set for
// other semantic checks run before we print the errors
isValid = false;
Expand Down Expand Up @@ -5196,9 +5213,10 @@ bool SubprogramVisitor::HandlePreviousCalls(
}
}

void SubprogramVisitor::CheckExtantProc(
const Symbol *SubprogramVisitor::CheckExtantProc(
const parser::Name &name, Symbol::Flag subpFlag) {
if (auto *prev{FindSymbol(name)}) {
Symbol *prev{FindSymbol(name)};
if (prev) {
if (IsDummy(*prev)) {
} else if (auto *entity{prev->detailsIf<EntityDetails>()};
IsPointer(*prev) && entity && !entity->type()) {
Expand All @@ -5210,12 +5228,15 @@ void SubprogramVisitor::CheckExtantProc(
SayAlreadyDeclared(name, *prev);
}
}
return prev;
}

Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
Symbol::Flag subpFlag, const parser::LanguageBindingSpec *bindingSpec,
bool hasModulePrefix) {
Symbol *symbol{GetSpecificFromGeneric(name)};
const DeclTypeSpec *previousImplicitType{nullptr};
SourceName previousName;
if (!symbol) {
if (bindingSpec && currScope().IsGlobal() &&
std::get<std::optional<parser::ScalarDefaultCharConstantExpr>>(
Expand All @@ -5228,14 +5249,25 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
&MakeSymbol(context().GetTempName(currScope()), Attrs{},
MiscDetails{MiscDetails::Kind::ScopeName}));
}
CheckExtantProc(name, subpFlag);
if (const Symbol *previous{CheckExtantProc(name, subpFlag)}) {
if (previous->test(Symbol::Flag::Function) &&
previous->test(Symbol::Flag::Implicit)) {
// Function was implicitly typed in previous compilation unit.
previousImplicitType = previous->GetType();
previousName = previous->name();
}
}
symbol = &MakeSymbol(name, SubprogramDetails{});
}
symbol->ReplaceName(name.source);
symbol->set(subpFlag);
PushScope(Scope::Kind::Subprogram, symbol);
if (subpFlag == Symbol::Flag::Function) {
funcResultStack().Push(currScope(), name.source);
auto &funcResultTop{funcResultStack().Push(currScope(), name.source)};
funcResultTop.previousImplicitType = previousImplicitType;
;
funcResultTop.previousName = previousName;
;
}
if (inInterfaceBlock()) {
auto &details{symbol->get<SubprogramDetails>()};
Expand Down Expand Up @@ -8669,11 +8701,6 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
x.u);
}

static bool TypesMismatchIfNonNull(
const DeclTypeSpec *type1, const DeclTypeSpec *type2) {
return type1 && type2 && *type1 != *type2;
}

// If implicit types are allowed, ensure name is in the symbol table.
// Otherwise, report an error if it hasn't been declared.
const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
Expand Down
37 changes: 37 additions & 0 deletions flang/test/Semantics/global02.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
! RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
! Catch discrepancies between implicit result types and a global definition

complex function zbefore()
zbefore = (0.,0.)
end

program main
!ERROR: Implicit declaration of function 'zbefore' has a different result type than in previous declaration
print *, zbefore()
print *, zafter()
print *, zafter2()
print *, zafter3()
end

subroutine another
implicit integer(z)
!ERROR: Implicit declaration of function 'zafter' has a different result type than in previous declaration
print *, zafter()
end

!ERROR: Function 'zafter' has a result type that differs from the implicit type it obtained in a previous reference
complex function zafter()
zafter = (0.,0.)
end

function zafter2()
!ERROR: Function 'zafter2' has a result type that differs from the implicit type it obtained in a previous reference
complex zafter2
zafter2 = (0.,0.)
end

function zafter3() result(res)
!ERROR: Function 'zafter3' has a result type that differs from the implicit type it obtained in a previous reference
complex res
res = (0.,0.)
end
Loading