Skip to content

Commit e2ee91e

Browse files
authored
[flang] Clean up some optional<bool> usage (#161925)
Audit the use of std::optional<bool> as a tri-state logical value in flang, correct a couple cases that need ".value_or()", add some explicit ".has_value()" calls, and document the possible pitfalls.
1 parent 8b93089 commit e2ee91e

File tree

9 files changed

+42
-31
lines changed

9 files changed

+42
-31
lines changed

flang/docs/C++17.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,8 @@ signifies a successful recognition and absence denotes a failed parse.
153153
It is used in data structures in place of nullable pointers to
154154
avoid indirection as well as the possible confusion over whether a pointer
155155
is allowed to be null.
156+
157+
`std::optional<bool>` is commonly used to denote a "tri-state"
158+
logical value that might be unknown.
159+
Please try to avoid implicit casts of `std::optional<bool>` to `bool`,
160+
and use `.value_or(default)` or `.has_value()` instead as appropriate.

flang/docs/C++style.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,13 @@ contents, and it is assumed that the contents are present, validate that
205205
assumption by using `x.value()` instead.
206206
1. We use `c_str()` rather than `data()` when converting a `std::string`
207207
to a `const char *` when the result is expected to be NUL-terminated.
208-
1. Avoid explicit comparisions of pointers to `nullptr` and tests of
208+
1. Avoid explicit comparisons of pointers to `nullptr` and tests of
209209
presence of `optional<>` values with `.has_value()` in the predicate
210210
expressions of control flow statements, but prefer them to implicit
211211
conversions to `bool` when initializing `bool` variables and arguments,
212212
and to the use of the idiom `!!`.
213+
(But please use `.has_value()` or `.value_or()` with `optional<bool>`
214+
to avoid a common pitfall or the appearance of having fallen into it.)
213215

214216
#### Classes
215217
1. Define POD structures with `struct`.

flang/include/flang/Semantics/type.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ class ParamValue {
120120
bool IsEquivalentInInterface(const ParamValue &that) const {
121121
return (category_ == that.category_ &&
122122
expr_.has_value() == that.expr_.has_value() &&
123-
(!expr_ || evaluate::AreEquivalentInInterface(*expr_, *that.expr_)));
123+
(!expr_ ||
124+
evaluate::AreEquivalentInInterface(*expr_, *that.expr_)
125+
.value_or(false)));
124126
}
125127
std::string AsFortran() const;
126128

flang/lib/Evaluate/check-expression.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,10 +1304,12 @@ std::optional<bool> IsContiguous(const A &x, FoldingContext &context,
13041304
std::optional<bool> IsContiguous(const ActualArgument &actual,
13051305
FoldingContext &fc, bool namedConstantSectionsAreContiguous,
13061306
bool firstDimensionStride1) {
1307-
auto *expr{actual.UnwrapExpr()};
1308-
return expr &&
1309-
IsContiguous(
1310-
*expr, fc, namedConstantSectionsAreContiguous, firstDimensionStride1);
1307+
if (auto *expr{actual.UnwrapExpr()}) {
1308+
return IsContiguous(
1309+
*expr, fc, namedConstantSectionsAreContiguous, firstDimensionStride1);
1310+
} else {
1311+
return std::nullopt;
1312+
}
13111313
}
13121314

13131315
template std::optional<bool> IsContiguous(const Expr<SomeType> &,

flang/lib/Evaluate/fold-logical.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -799,22 +799,20 @@ Expr<Type<TypeCategory::Logical, KIND>> FoldIntrinsicFunction(
799799
}
800800
} else if (name == "is_contiguous") {
801801
if (args.at(0)) {
802-
auto warnContiguous{[&]() {
803-
if (auto source{args[0]->sourceLocation()}) {
804-
context.Warn(common::UsageWarning::ConstantIsContiguous, *source,
805-
"is_contiguous() is always true for named constants and subobjects of named constants"_warn_en_US);
806-
}
807-
}};
802+
std::optional<bool> knownContiguous;
808803
if (auto *expr{args[0]->UnwrapExpr()}) {
809-
if (auto contiguous{IsContiguous(*expr, context)}) {
810-
warnContiguous();
811-
return Expr<T>{*contiguous};
812-
}
804+
knownContiguous = IsContiguous(*expr, context);
813805
} else if (auto *assumedType{args[0]->GetAssumedTypeDummy()}) {
814-
if (auto contiguous{IsContiguous(*assumedType, context)}) {
815-
warnContiguous();
816-
return Expr<T>{*contiguous};
806+
knownContiguous = IsContiguous(*assumedType, context);
807+
}
808+
if (knownContiguous) {
809+
if (*knownContiguous) {
810+
if (auto source{args[0]->sourceLocation()}) {
811+
context.Warn(common::UsageWarning::ConstantIsContiguous, *source,
812+
"is_contiguous() is always true for named constants and subobjects of named constants"_warn_en_US);
813+
}
817814
}
815+
return Expr<T>{*knownContiguous};
818816
}
819817
}
820818
} else if (name == "is_iostat_end") {

flang/lib/Semantics/check-call.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ static void CheckCharacterActual(evaluate::Expr<evaluate::SomeType> &actual,
185185
} else if (static_cast<std::size_t>(actualOffset->offset()) >=
186186
actualOffset->symbol().size() ||
187187
!evaluate::IsContiguous(
188-
actualOffset->symbol(), foldingContext)) {
188+
actualOffset->symbol(), foldingContext)
189+
.value_or(false)) {
189190
// If substring, take rest of substring
190191
if (*actualLength > 0) {
191192
actualChars -=
@@ -598,7 +599,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
598599
context.IsEnabled(
599600
common::LanguageFeature::ContiguousOkForSeqAssociation) &&
600601
actualLastSymbol &&
601-
evaluate::IsContiguous(*actualLastSymbol, foldingContext)};
602+
evaluate::IsContiguous(*actualLastSymbol, foldingContext)
603+
.value_or(false)};
602604
if (actualIsArrayElement && actualLastSymbol &&
603605
!dummy.ignoreTKR.test(common::IgnoreTKR::Contiguous)) {
604606
if (IsPointer(*actualLastSymbol)) {
@@ -663,7 +665,8 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
663665
} else if (static_cast<std::size_t>(actualOffset->offset()) >=
664666
actualOffset->symbol().size() ||
665667
!evaluate::IsContiguous(
666-
actualOffset->symbol(), foldingContext)) {
668+
actualOffset->symbol(), foldingContext)
669+
.value_or(false)) {
667670
actualElements = 1;
668671
} else if (auto actualSymType{evaluate::DynamicType::From(
669672
actualOffset->symbol())}) {
@@ -1566,10 +1569,10 @@ static bool CheckElementalConformance(parser::ContextualMessages &messages,
15661569
") corresponding to dummy argument #" + std::to_string(index) +
15671570
" ('" + dummy.name + "')"};
15681571
if (shape) {
1569-
auto tristate{evaluate::CheckConformance(messages, *shape,
1570-
*argShape, evaluate::CheckConformanceFlags::None,
1571-
shapeName.c_str(), argName.c_str())};
1572-
if (tristate && !*tristate) {
1572+
if (!evaluate::CheckConformance(messages, *shape, *argShape,
1573+
evaluate::CheckConformanceFlags::None, shapeName.c_str(),
1574+
argName.c_str())
1575+
.value_or(true)) {
15731576
return false;
15741577
}
15751578
} else {

flang/lib/Semantics/check-declarations.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,9 +1984,8 @@ bool CheckHelper::CheckDistinguishableFinals(const Symbol &f1,
19841984
const Procedure *p1{Characterize(f1)};
19851985
const Procedure *p2{Characterize(f2)};
19861986
if (p1 && p2) {
1987-
std::optional<bool> areDistinct{characteristics::Distinguishable(
1988-
context_.languageFeatures(), *p1, *p2)};
1989-
if (areDistinct.value_or(false)) {
1987+
if (characteristics::Distinguishable(context_.languageFeatures(), *p1, *p2)
1988+
.value_or(false)) {
19901989
return true;
19911990
}
19921991
if (auto *msg{messages_.Say(f1Name,

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5085,7 +5085,7 @@ void OmpStructureChecker::CheckWorkdistributeBlockStmts(
50855085
}
50865086

50875087
void OmpStructureChecker::CheckIfContiguous(const parser::OmpObject &object) {
5088-
if (auto contig{IsContiguous(context_, object)}; contig && !*contig) {
5088+
if (!IsContiguous(context_, object).value_or(true)) { // known discontiguous
50895089
const parser::Name *name{GetObjectName(object)};
50905090
assert(name && "Expecting name component");
50915091
context_.Say(name->source,

flang/lib/Semantics/expression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2329,7 +2329,7 @@ MaybeExpr ExpressionAnalyzer::CheckStructureConstructor(
23292329
auto checked{CheckConformance(messages, *componentShape,
23302330
*valueShape, CheckConformanceFlags::RightIsExpandableDeferred,
23312331
"component", "value")};
2332-
if (checked && *checked && GetRank(*componentShape) > 0 &&
2332+
if (checked.value_or(false) && GetRank(*componentShape) > 0 &&
23332333
GetRank(*valueShape) == 0 &&
23342334
(IsDeferredShape(*symbol) ||
23352335
!IsExpandableScalar(*converted, foldingContext,

0 commit comments

Comments
 (0)