[flang] Add options to control IMPLICIT NONE

Add `-fimplicit-none-type-always` to treat each specification-part
like it has `IMPLICIT NONE`. This is helpful for enforcing good Fortran
programming practices. We might consider something similar for
`IMPLICIT NONE(EXTERNAL)` as well.

Add `-fimplicit-none-type-never` to ignore occurrences of `IMPLICIT NONE`
and `IMPLICIT NONE(TYPE)`. This is to handle cases like the one below,
which violates the standard but it accepted by some compilers:
```
subroutine s(a, n)
  implicit none
  real :: a(n)
  integer :: n
end
```

Differential Revision: https://reviews.llvm.org/D85363
This commit is contained in:
Tim Keith 2020-08-06 06:47:59 -07:00
parent 37894ba661
commit 08c7d570d3
6 changed files with 54 additions and 16 deletions

View File

@ -139,6 +139,10 @@ Extensions supported when enabled by options
`FINDLOC`, `MAXLOC`, and `MINLOC` in the absence of an explicit
`KIND=` actual argument. We return `INTEGER(KIND=8)` by default in
these cases when the `-flarge-sizes` option is enabled.
* Treat each specification-part like is has `IMPLICIT NONE`
[-fimplicit-none-type-always]
* Ignore occurrences of `IMPLICIT NONE` and `IMPLICIT NONE(TYPE)`
[-fimplicit-none-type-never]
Extensions and legacy features deliberately not supported
---------------------------------------------------------

View File

@ -28,7 +28,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals,
RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics,
AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment,
EmptySourceFile, ProgramReturn)
EmptySourceFile, ProgramReturn, ImplicitNoneTypeNever,
ImplicitNoneTypeAlways)
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
@ -39,6 +40,8 @@ public:
disable_.set(LanguageFeature::OldDebugLines);
disable_.set(LanguageFeature::OpenACC);
disable_.set(LanguageFeature::OpenMP);
disable_.set(LanguageFeature::ImplicitNoneTypeNever);
disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
// These features, if enabled, conflict with valid standard usage,
// so there are disabled here by default.
disable_.set(LanguageFeature::BackslashEscapes);

View File

@ -81,7 +81,8 @@ private:
ImplicitRules *parent_;
SemanticsContext &context_;
bool inheritFromParent_{false}; // look in parent if not specified here
bool isImplicitNoneType_{false};
bool isImplicitNoneType_{
context_.IsEnabled(common::LanguageFeature::ImplicitNoneTypeAlways)};
bool isImplicitNoneExternal_{false};
// map_ contains the mapping between letters and types that were defined
// by the IMPLICIT statements of the related scope. It does not contain
@ -1682,9 +1683,8 @@ bool ImplicitRulesVisitor::Pre(const parser::ImplicitStmt &x) {
Say("IMPLICIT statement after IMPLICIT NONE or "
"IMPLICIT NONE(TYPE) statement"_err_en_US);
return false;
} else {
implicitRules().set_isImplicitNoneType(false);
}
implicitRules().set_isImplicitNoneType(false);
return true;
},
},
@ -1744,12 +1744,16 @@ bool ImplicitRulesVisitor::HandleImplicitNone(
return false;
}
prevImplicitNone_ = currStmtSource();
bool implicitNoneTypeNever{
context().IsEnabled(common::LanguageFeature::ImplicitNoneTypeNever)};
if (nameSpecs.empty()) {
prevImplicitNoneType_ = currStmtSource();
implicitRules().set_isImplicitNoneType(true);
if (prevImplicit_) {
Say("IMPLICIT NONE statement after IMPLICIT statement"_err_en_US);
return false;
if (!implicitNoneTypeNever) {
prevImplicitNoneType_ = currStmtSource();
implicitRules().set_isImplicitNoneType(true);
if (prevImplicit_) {
Say("IMPLICIT NONE statement after IMPLICIT statement"_err_en_US);
return false;
}
}
} else {
int sawType{0};
@ -1761,13 +1765,15 @@ bool ImplicitRulesVisitor::HandleImplicitNone(
++sawExternal;
break;
case ImplicitNoneNameSpec::Type:
prevImplicitNoneType_ = currStmtSource();
implicitRules().set_isImplicitNoneType(true);
if (prevImplicit_) {
Say("IMPLICIT NONE(TYPE) after IMPLICIT statement"_err_en_US);
return false;
if (!implicitNoneTypeNever) {
prevImplicitNoneType_ = currStmtSource();
implicitRules().set_isImplicitNoneType(true);
if (prevImplicit_) {
Say("IMPLICIT NONE(TYPE) after IMPLICIT statement"_err_en_US);
return false;
}
++sawType;
}
++sawType;
break;
}
}

View File

@ -0,0 +1,11 @@
! RUN: %S/test_errors.sh %s %t %f18 -fimplicit-none-type-never
subroutine s1
implicit none
i = j + k ! would be error without -fimplicit-none-type-never
end
subroutine s2(a, n)
implicit none
real :: a(n) ! would be error without -fimplicit-none-type-never
integer :: n
end

View File

@ -0,0 +1,7 @@
! RUN: %S/test_errors.sh %s %t %f18 -fimplicit-none-type-always
!ERROR: No explicit type declared for 'f'
function f()
!ERROR: No explicit type declared for 'x'
f = x
end

View File

@ -503,6 +503,12 @@ int main(int argc, char *const argv[]) {
options.features.Enable(
Fortran::parser::LanguageFeature::LogicalAbbreviations,
arg == "-flogical-abbreviations");
} else if (arg == "-fimplicit-none-type-always") {
options.features.Enable(
Fortran::common::LanguageFeature::ImplicitNoneTypeAlways);
} else if (arg == "-fimplicit-none-type-never") {
options.features.Enable(
Fortran::common::LanguageFeature::ImplicitNoneTypeNever);
} else if (arg == "-fdebug-dump-provenance") {
driver.dumpProvenance = true;
options.needProvenanceRangeToCharBlockMappings = true;
@ -603,7 +609,8 @@ int main(int argc, char *const argv[]) {
driver.getSymbolsSources = true;
} else if (arg == "-byteswapio") {
driver.byteswapio = true; // TODO: Pass to lowering, generate call
} else if (arg == "-h" || arg == "-help" || arg == "--help" || arg == "-?") {
} else if (arg == "-h" || arg == "-help" || arg == "--help" ||
arg == "-?") {
llvm::errs()
<< "f18: LLVM Fortran compiler\n"
<< "\n"