Skip to content
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

Merged
merged 1 commit into from Dec 24, 2019

Conversation

psteinfeld
Copy link
Collaborator

@psteinfeld psteinfeld commented Dec 7, 2019

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.

@@ -208,6 +208,28 @@ void SemanticsContext::PopConstruct() {
constructStack_.pop_back();
}

void SemanticsContext::ActivateDoVariable(
const Symbol *doVariable, const parser::CharBlock location) {
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

@@ -172,6 +177,7 @@ class SemanticsContext {

bool CheckError(bool);
ConstructStack constructStack_;
std::map<const Symbol *, const parser::CharBlock> activeDoVariables_;
Copy link
Collaborator

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

void CheckDoVarRedefine(
const Symbol &, SemanticsContext &, const parser::CharBlock &);
void CheckDoVarRedefine(const parser::Variable &, SemanticsContext &);
void CheckDoVarRedefine(const parser::Name &, SemanticsContext &);
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator

@jeanPerier jeanPerier left a 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 the BaseChecker and named it something like cannotBeDefinedVariables.
  • Providing a way to register/de-register symbols to this map (like ActivateDoVariable, but attached to the BaseChecker instead of the SemanticsContext).
  • 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 or CHANGE 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).

@@ -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_);
Copy link
Collaborator

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

Copy link
Collaborator Author

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.

struct ExitStmt;
struct InquireSpec;
struct IoControlSpec;
struct IoControlSpec;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IoControlSpec seems duplicated.

Copy link
Collaborator Author

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.

context_.ActivateDoVariable(GetDoVariable(doConstruct));
} else if (doConstruct.IsDoConcurrent()) {
auto &loopControl{doConstruct.GetLoopControl()};
if (loopControl) {
Copy link
Collaborator

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 &.

Copy link
Collaborator Author

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.

context_.DeactivateDoVariable(GetDoVariable(doConstruct));
} else if (doConstruct.IsDoConcurrent()) {
auto &loopControl{doConstruct.GetLoopControl()};
if (loopControl) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

@@ -208,6 +209,70 @@ void SemanticsContext::PopConstruct() {
constructStack_.pop_back();
}

void SemanticsContext::SayDoVarRedefine(
const Symbol &variable, const parser::CharBlock &location) {
Copy link
Collaborator

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.

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())
Copy link
Collaborator

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.

Copy link
Collaborator Author

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)) {
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

@@ -620,6 +620,7 @@ bool AllocationCheckerHelper::RunCoarrayRelatedChecks(
"Allocatable object must not be coindexed in ALLOCATE"_err_en_US);
return false;
}
context.CheckDoVarRedefine(name_);
Copy link
Collaborator

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:

return RunCoarrayRelatedChecks(context);

Copy link
Collaborator Author

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.
@psteinfeld psteinfeld merged commit 6715b16 into master Dec 24, 2019
@psteinfeld psteinfeld deleted the ps-do-redefine branch December 24, 2019 23:19
swift-ci pushed a commit to apple/llvm-project that referenced this pull request Apr 9, 2020
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
swift-ci pushed a commit to apple/llvm-project that referenced this pull request Apr 9, 2020
…/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
mem-frob pushed a commit to draperlaboratory/hope-llvm-project that referenced this pull request Oct 7, 2022
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants