New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Semantic checks to see if a DO variable is modified #860
Conversation
lib/semantics/semantics.cc
Outdated
@@ -208,6 +208,28 @@ void SemanticsContext::PopConstruct() { | |||
constructStack_.pop_back(); | |||
} | |||
|
|||
void SemanticsContext::ActivateDoVariable( | |||
const Symbol *doVariable, const parser::CharBlock location) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These doVariable
arguments should be const Symbol &
rather than const Symbol *
. I don't think they are ever null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, Tim. I'll make that change.
lib/semantics/semantics.h
Outdated
@@ -172,6 +177,7 @@ class SemanticsContext { | |||
|
|||
bool CheckError(bool); | |||
ConstructStack constructStack_; | |||
std::map<const Symbol *, const parser::CharBlock> activeDoVariables_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the do variable symbols are changed to refs, the key for this map should then be SymbolRef
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
lib/semantics/tools.h
Outdated
void CheckDoVarRedefine( | ||
const Symbol &, SemanticsContext &, const parser::CharBlock &); | ||
void CheckDoVarRedefine(const parser::Variable &, SemanticsContext &); | ||
void CheckDoVarRedefine(const parser::Name &, SemanticsContext &); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make more sense to make these be member functions of SemanticContext
as they depend on the active do variable there. It seems like that would make the new API simpler: just Activate/DeactivateDoVariable and CheckDoVarRedefine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestion. I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you did a great job chasing the places where do variable may get redefined ! I wonder if one could leverage this work for other variables that may not be defined/re-defined (e.g. intent(in)
argument (C844) and team-value
in CHANGE TEAM (11.1.5.2 par 1)). Maybe the following would allow doing so:
- Moving the map
activeDoVariables_
to theBaseChecker
and named it something likecannotBeDefinedVariables
. - Providing a way to register/de-register symbols to this map (like
ActivateDoVariable
, but attached to theBaseChecker
instead of theSemanticsContext
). - The
SemanticsVisitor
could then be in charge of checking for all the spots that may define a variable that it is not defining a variable that cannot be defined. Alternatively, checkers for the statements that may define variables could be in charge of doing this check like you did. - Checkers for constructs like
DO
orCHANGE TEAM
could then register and de-register variables that cannot be defined.
Anyway, this is an open proposal more than a request. It may just not be worth it given the other use cases (and one could make such change when the need will arise).
lib/semantics/check-deallocate.cc
Outdated
@@ -35,6 +35,8 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) { | |||
} else if (!IsAllocatableOrPointer(*symbol)) { // C932 | |||
context_.Say(name.source, | |||
"name in DEALLOCATE statement must have the ALLOCATABLE or POINTER attribute"_err_en_US); | |||
} else { | |||
CheckDoVarRedefine(name, context_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may also want to check that it is not being allocated to prevent:
integer, allocatable :: i
allocate(i)
do i=1,10
print *, i
if (i.eq.5) then
allocate(i, source=4) ! hidden i--
end if
end do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, Jean.
With respect to other similar instances of variables/names not being definable, I'll poke around and see what I can find in the standard and make a proposal for review. I may want to deal with generalizing the definability analysis to a future pull request.
With respect to not including allocation, my original analysis was based on sections 19.6.5 and 19.6.6, which specify the events that case variables to become defined or undefined. I neglected to include section 19.6.7, which specifies that contexts which imply definition or undefinition of variables. In addition to allocation, I also neglected to deal with actual arguments passed as INTENT(OUT) or INTENT(INOUT). I'll include tests and implementation for the cases described in section 19.6.7.
lib/semantics/check-do.h
Outdated
struct ExitStmt; | ||
struct InquireSpec; | ||
struct IoControlSpec; | ||
struct IoControlSpec; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IoControlSpec
seems duplicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
D'oh! Good catch. I'll fix that.
lib/semantics/check-do.cc
Outdated
context_.ActivateDoVariable(GetDoVariable(doConstruct)); | ||
} else if (doConstruct.IsDoConcurrent()) { | ||
auto &loopControl{doConstruct.GetLoopControl()}; | ||
if (loopControl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could write these two lines as:
if (const auto &loopControl{doConstruct.GetLoopControl()}) {
You should use const auto &
rather than just auto &
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, Tim. I'll change that.
lib/semantics/check-do.cc
Outdated
context_.DeactivateDoVariable(GetDoVariable(doConstruct)); | ||
} else if (doConstruct.IsDoConcurrent()) { | ||
auto &loopControl{doConstruct.GetLoopControl()}; | ||
if (loopControl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
lib/semantics/semantics.cc
Outdated
@@ -208,6 +209,70 @@ void SemanticsContext::PopConstruct() { | |||
constructStack_.pop_back(); | |||
} | |||
|
|||
void SemanticsContext::SayDoVarRedefine( | |||
const Symbol &variable, const parser::CharBlock &location) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other "Say" functions that take a CharBlock
for the location of the message have that as the first argument, so it would be consistent.
lib/semantics/semantics.cc
Outdated
void SemanticsContext::SayDoVarRedefine( | ||
const Symbol &variable, const parser::CharBlock &location) { | ||
const parser::CharBlock doLoc{GetDoVariableLocation(variable)}; | ||
Say(location, "Cannot redefine DO variable %s"_err_en_US, variable.name()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Names from the program that are mentioned in error messages are enclosed in single quotes. It makes messages easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. I'll add the quotes.
|
||
parser::CharBlock SemanticsContext::GetDoVariableLocation( | ||
const Symbol &variable) { | ||
if (IsActiveDoVariable(variable)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When would this be called on something that isn't an active do variable? If this actually did return an empty CharBlock to SayDoVarRedefine
we wouldn't get a good error message location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GetDoVariableLocation() gets called in two situations. One is to get the location for error messages. The other is to deactivate a DO variable at the end of a DO loop. In the case of nested DO loops that use the same variable, we only want to deactivate the loop variable for the outer loop when we exit it, not when we exit the inner loop. So DeactivateDoVariable() calls GetDoVariableLocation() to make sure that its deactivating the correct variable.
I don't think GetDoVariableLocation() will be called for an error message when there's not an empty location for the DO variable. But I can certainly add a check that will verify that.
lib/semantics/check-allocate.cc
Outdated
@@ -620,6 +620,7 @@ bool AllocationCheckerHelper::RunCoarrayRelatedChecks( | |||
"Allocatable object must not be coindexed in ALLOCATE"_err_en_US); | |||
return false; | |||
} | |||
context.CheckDoVarRedefine(name_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A minor point: this check is not related to coarrays yet is is done in RunCoarrayRelatedChecks
. To avoid misleading future maintainers, I would move this check just before the following line instead:
f18/lib/semantics/check-allocate.cc
Line 542 in 867dd04
return RunCoarrayRelatedChecks(context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, Jean. That's a better place. I'll move it.
I added infrastructure to SemanticsContext to track active DO variables and the source locations where they appear in DO statements. I also added code to semantics.[h,cc] to check to see if a DO variable is already defined, and, if so, to emit an error message along with a reference to the relevant DO construct. I also added calls to several places where variables are defined to determine if the definitions are happening in the context of an active DO construct. I have not yet added the checks for DO variables being redefined when passing them as actual arguments to dummy arguments with INTENT(OUT) or INTENT(INOUT). I wanted to get these changes merged first and catch up with the other changes in master.
867dd04
to
1bbfcca
Compare
I added infrastructure to SemanticsContext to track active DO variables and the source locations where they appear in DO statements. I also added code to semantics.[h,cc] to check to see if a DO variable is already defined, and, if so, to emit an error message along with a reference to the relevant DO construct. I also added calls to several places where variables are defined to determine if the definitions are happening in the context of an active DO construct. I have not yet added the checks for DO variables being redefined when passing them as actual arguments to dummy arguments with INTENT(OUT) or INTENT(INOUT). I wanted to get these changes merged first and catch up with the other changes in master. Original-commit: flang-compiler/f18@1bbfcca Reviewed-on: flang-compiler/f18#860
…/ps-do-redefine Semantic checks to see if a DO variable is modified Original-commit: flang-compiler/f18@6715b16 Reviewed-on: flang-compiler/f18#860
I added infrastructure to SemanticsContext to track active DO variables and the source locations where they appear in DO statements. I also added code to semantics.[h,cc] to check to see if a DO variable is already defined, and, if so, to emit an error message along with a reference to the relevant DO construct. I also added calls to several places where variables are defined to determine if the definitions are happening in the context of an active DO construct. I have not yet added the checks for DO variables being redefined when passing them as actual arguments to dummy arguments with INTENT(OUT) or INTENT(INOUT). I wanted to get these changes merged first and catch up with the other changes in master. Original-commit: flang-compiler/f18@1bbfcca Reviewed-on: flang-compiler/f18#860
This is driven by Section 11.1.7.4.3, paragraph 2, which states:
Except for the incrementation of the DO variable that occurs in step (3), the
DO variable shall neither be redefined nor become undefined while the DO
construct is active.
Sections 19.6.5 and 19.6.6 describe the events that can cause variables to
become defined and undefined. Section 19.6.7 describes the contexts that imply
the redefinition or undefinition of a variable. For all of these situations
that are reasonably easy to discover at compile time, we should emit messages.
I added infrastructure to SemanticsContext to track active DO variables and
the source locations where they appear in DO statements. I also added code
to tools.[h,cc] to check to see if a DO variable is already defined, and, if
so, to emit an error message along with a reference to the relevant DO
construct. I also added calls to several places where variables are defined
to determine if the definitions are happening in the context of an active DO
construct.