forked from OSchip/llvm-project
[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:
parent
37894ba661
commit
08c7d570d3
|
@ -139,6 +139,10 @@ Extensions supported when enabled by options
|
||||||
`FINDLOC`, `MAXLOC`, and `MINLOC` in the absence of an explicit
|
`FINDLOC`, `MAXLOC`, and `MINLOC` in the absence of an explicit
|
||||||
`KIND=` actual argument. We return `INTEGER(KIND=8)` by default in
|
`KIND=` actual argument. We return `INTEGER(KIND=8)` by default in
|
||||||
these cases when the `-flarge-sizes` option is enabled.
|
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
|
Extensions and legacy features deliberately not supported
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
|
|
|
@ -28,7 +28,8 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
|
||||||
CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals,
|
CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals,
|
||||||
RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics,
|
RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics,
|
||||||
AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment,
|
AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment,
|
||||||
EmptySourceFile, ProgramReturn)
|
EmptySourceFile, ProgramReturn, ImplicitNoneTypeNever,
|
||||||
|
ImplicitNoneTypeAlways)
|
||||||
|
|
||||||
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
|
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
|
||||||
|
|
||||||
|
@ -39,6 +40,8 @@ public:
|
||||||
disable_.set(LanguageFeature::OldDebugLines);
|
disable_.set(LanguageFeature::OldDebugLines);
|
||||||
disable_.set(LanguageFeature::OpenACC);
|
disable_.set(LanguageFeature::OpenACC);
|
||||||
disable_.set(LanguageFeature::OpenMP);
|
disable_.set(LanguageFeature::OpenMP);
|
||||||
|
disable_.set(LanguageFeature::ImplicitNoneTypeNever);
|
||||||
|
disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
|
||||||
// These features, if enabled, conflict with valid standard usage,
|
// These features, if enabled, conflict with valid standard usage,
|
||||||
// so there are disabled here by default.
|
// so there are disabled here by default.
|
||||||
disable_.set(LanguageFeature::BackslashEscapes);
|
disable_.set(LanguageFeature::BackslashEscapes);
|
||||||
|
|
|
@ -81,7 +81,8 @@ private:
|
||||||
ImplicitRules *parent_;
|
ImplicitRules *parent_;
|
||||||
SemanticsContext &context_;
|
SemanticsContext &context_;
|
||||||
bool inheritFromParent_{false}; // look in parent if not specified here
|
bool inheritFromParent_{false}; // look in parent if not specified here
|
||||||
bool isImplicitNoneType_{false};
|
bool isImplicitNoneType_{
|
||||||
|
context_.IsEnabled(common::LanguageFeature::ImplicitNoneTypeAlways)};
|
||||||
bool isImplicitNoneExternal_{false};
|
bool isImplicitNoneExternal_{false};
|
||||||
// map_ contains the mapping between letters and types that were defined
|
// map_ contains the mapping between letters and types that were defined
|
||||||
// by the IMPLICIT statements of the related scope. It does not contain
|
// 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 "
|
Say("IMPLICIT statement after IMPLICIT NONE or "
|
||||||
"IMPLICIT NONE(TYPE) statement"_err_en_US);
|
"IMPLICIT NONE(TYPE) statement"_err_en_US);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
implicitRules().set_isImplicitNoneType(false);
|
|
||||||
}
|
}
|
||||||
|
implicitRules().set_isImplicitNoneType(false);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1744,12 +1744,16 @@ bool ImplicitRulesVisitor::HandleImplicitNone(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
prevImplicitNone_ = currStmtSource();
|
prevImplicitNone_ = currStmtSource();
|
||||||
|
bool implicitNoneTypeNever{
|
||||||
|
context().IsEnabled(common::LanguageFeature::ImplicitNoneTypeNever)};
|
||||||
if (nameSpecs.empty()) {
|
if (nameSpecs.empty()) {
|
||||||
prevImplicitNoneType_ = currStmtSource();
|
if (!implicitNoneTypeNever) {
|
||||||
implicitRules().set_isImplicitNoneType(true);
|
prevImplicitNoneType_ = currStmtSource();
|
||||||
if (prevImplicit_) {
|
implicitRules().set_isImplicitNoneType(true);
|
||||||
Say("IMPLICIT NONE statement after IMPLICIT statement"_err_en_US);
|
if (prevImplicit_) {
|
||||||
return false;
|
Say("IMPLICIT NONE statement after IMPLICIT statement"_err_en_US);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int sawType{0};
|
int sawType{0};
|
||||||
|
@ -1761,13 +1765,15 @@ bool ImplicitRulesVisitor::HandleImplicitNone(
|
||||||
++sawExternal;
|
++sawExternal;
|
||||||
break;
|
break;
|
||||||
case ImplicitNoneNameSpec::Type:
|
case ImplicitNoneNameSpec::Type:
|
||||||
prevImplicitNoneType_ = currStmtSource();
|
if (!implicitNoneTypeNever) {
|
||||||
implicitRules().set_isImplicitNoneType(true);
|
prevImplicitNoneType_ = currStmtSource();
|
||||||
if (prevImplicit_) {
|
implicitRules().set_isImplicitNoneType(true);
|
||||||
Say("IMPLICIT NONE(TYPE) after IMPLICIT statement"_err_en_US);
|
if (prevImplicit_) {
|
||||||
return false;
|
Say("IMPLICIT NONE(TYPE) after IMPLICIT statement"_err_en_US);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++sawType;
|
||||||
}
|
}
|
||||||
++sawType;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -503,6 +503,12 @@ int main(int argc, char *const argv[]) {
|
||||||
options.features.Enable(
|
options.features.Enable(
|
||||||
Fortran::parser::LanguageFeature::LogicalAbbreviations,
|
Fortran::parser::LanguageFeature::LogicalAbbreviations,
|
||||||
arg == "-flogical-abbreviations");
|
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") {
|
} else if (arg == "-fdebug-dump-provenance") {
|
||||||
driver.dumpProvenance = true;
|
driver.dumpProvenance = true;
|
||||||
options.needProvenanceRangeToCharBlockMappings = true;
|
options.needProvenanceRangeToCharBlockMappings = true;
|
||||||
|
@ -603,7 +609,8 @@ int main(int argc, char *const argv[]) {
|
||||||
driver.getSymbolsSources = true;
|
driver.getSymbolsSources = true;
|
||||||
} else if (arg == "-byteswapio") {
|
} else if (arg == "-byteswapio") {
|
||||||
driver.byteswapio = true; // TODO: Pass to lowering, generate call
|
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()
|
llvm::errs()
|
||||||
<< "f18: LLVM Fortran compiler\n"
|
<< "f18: LLVM Fortran compiler\n"
|
||||||
<< "\n"
|
<< "\n"
|
||||||
|
|
Loading…
Reference in New Issue