diff options
Diffstat (limited to 'flang/lib/Semantics')
-rw-r--r-- | flang/lib/Semantics/assignment.cpp | 3 | ||||
-rw-r--r-- | flang/lib/Semantics/check-allocate.cpp | 13 | ||||
-rw-r--r-- | flang/lib/Semantics/check-case.cpp | 2 | ||||
-rw-r--r-- | flang/lib/Semantics/check-coarray.cpp | 9 | ||||
-rw-r--r-- | flang/lib/Semantics/check-data.cpp | 10 | ||||
-rw-r--r-- | flang/lib/Semantics/check-deallocate.cpp | 3 | ||||
-rw-r--r-- | flang/lib/Semantics/check-do-forall.cpp | 50 | ||||
-rw-r--r-- | flang/lib/Semantics/check-io.cpp | 6 | ||||
-rw-r--r-- | flang/lib/Semantics/check-omp-structure.cpp | 8 | ||||
-rw-r--r-- | flang/lib/Semantics/data-to-inits.cpp | 17 | ||||
-rw-r--r-- | flang/lib/Semantics/expression.cpp | 107 | ||||
-rw-r--r-- | flang/lib/Semantics/resolve-names-utils.cpp | 9 | ||||
-rw-r--r-- | flang/lib/Semantics/resolve-names.cpp | 32 |
13 files changed, 159 insertions, 110 deletions
diff --git a/flang/lib/Semantics/assignment.cpp b/flang/lib/Semantics/assignment.cpp index f4aa496..1824a7d 100644 --- a/flang/lib/Semantics/assignment.cpp +++ b/flang/lib/Semantics/assignment.cpp @@ -194,7 +194,8 @@ void AssignmentContext::CheckShape(parser::CharBlock at, const SomeExpr *expr) { template <typename A> void AssignmentContext::PushWhereContext(const A &x) { const auto &expr{std::get<parser::LogicalExpr>(x.t)}; - CheckShape(expr.thing.value().source, GetExpr(context_, expr)); + CheckShape( + parser::UnwrapRef<parser::Expr>(expr).source, GetExpr(context_, expr)); ++whereDepth_; } diff --git a/flang/lib/Semantics/check-allocate.cpp b/flang/lib/Semantics/check-allocate.cpp index 823aa4e..e019bbd 100644 --- a/flang/lib/Semantics/check-allocate.cpp +++ b/flang/lib/Semantics/check-allocate.cpp @@ -151,7 +151,9 @@ static std::optional<AllocateCheckerInfo> CheckAllocateOptions( [&](const parser::MsgVariable &var) { WarnOnDeferredLengthCharacterScalar(context, GetExpr(context, var), - var.v.thing.thing.GetSource(), "ERRMSG="); + parser::UnwrapRef<parser::Variable>(var) + .GetSource(), + "ERRMSG="); if (info.gotMsg) { // C943 context.Say( "ERRMSG may not be duplicated in a ALLOCATE statement"_err_en_US); @@ -439,7 +441,7 @@ static bool HaveCompatibleLengths( evaluate::ToInt64(type1.characterTypeSpec().length().GetExplicit())}; auto v2{ evaluate::ToInt64(type2.characterTypeSpec().length().GetExplicit())}; - return !v1 || !v2 || *v1 == *v2; + return !v1 || !v2 || (*v1 >= 0 ? *v1 : 0) == (*v2 >= 0 ? *v2 : 0); } else { return true; } @@ -452,7 +454,7 @@ static bool HaveCompatibleLengths( auto v1{ evaluate::ToInt64(type1.characterTypeSpec().length().GetExplicit())}; auto v2{type2.knownLength()}; - return !v1 || !v2 || *v1 == *v2; + return !v1 || !v2 || (*v1 >= 0 ? *v1 : 0) == (*v2 >= 0 ? *v2 : 0); } else { return true; } @@ -598,7 +600,7 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) { std::optional<evaluate::ConstantSubscript> lbound; if (const auto &lb{std::get<0>(shapeSpec.t)}) { lbound.reset(); - const auto &lbExpr{lb->thing.thing.value()}; + const auto &lbExpr{parser::UnwrapRef<parser::Expr>(lb)}; if (const auto *expr{GetExpr(context, lbExpr)}) { auto folded{ evaluate::Fold(context.foldingContext(), SomeExpr(*expr))}; @@ -609,7 +611,8 @@ bool AllocationCheckerHelper::RunChecks(SemanticsContext &context) { lbound = 1; } if (lbound) { - const auto &ubExpr{std::get<1>(shapeSpec.t).thing.thing.value()}; + const auto &ubExpr{ + parser::UnwrapRef<parser::Expr>(std::get<1>(shapeSpec.t))}; if (const auto *expr{GetExpr(context, ubExpr)}) { auto folded{ evaluate::Fold(context.foldingContext(), SomeExpr(*expr))}; diff --git a/flang/lib/Semantics/check-case.cpp b/flang/lib/Semantics/check-case.cpp index 5ce143c..7593154 100644 --- a/flang/lib/Semantics/check-case.cpp +++ b/flang/lib/Semantics/check-case.cpp @@ -72,7 +72,7 @@ private: } std::optional<Value> GetValue(const parser::CaseValue &caseValue) { - const parser::Expr &expr{caseValue.thing.thing.value()}; + const auto &expr{parser::UnwrapRef<parser::Expr>(caseValue)}; auto *x{expr.typedExpr.get()}; if (x && x->v) { // C1147 auto type{x->v->GetType()}; diff --git a/flang/lib/Semantics/check-coarray.cpp b/flang/lib/Semantics/check-coarray.cpp index 0e444f1..9113369 100644 --- a/flang/lib/Semantics/check-coarray.cpp +++ b/flang/lib/Semantics/check-coarray.cpp @@ -112,7 +112,7 @@ static void CheckTeamType( static void CheckTeamStat( SemanticsContext &context, const parser::ImageSelectorSpec::Stat &stat) { - const parser::Variable &var{stat.v.thing.thing.value()}; + const auto &var{parser::UnwrapRef<parser::Variable>(stat)}; if (parser::GetCoindexedNamedObject(var)) { context.Say(parser::FindSourceLocation(var), // C931 "Image selector STAT variable must not be a coindexed " @@ -147,7 +147,8 @@ static void CheckSyncStat(SemanticsContext &context, }, [&](const parser::MsgVariable &var) { WarnOnDeferredLengthCharacterScalar(context, GetExpr(context, var), - var.v.thing.thing.GetSource(), "ERRMSG="); + parser::UnwrapRef<parser::Variable>(var).GetSource(), + "ERRMSG="); if (gotMsg) { context.Say( // C1172 "The errmsg-variable in a sync-stat-list may not be repeated"_err_en_US); @@ -260,7 +261,9 @@ static void CheckEventWaitSpecList(SemanticsContext &context, [&](const parser::MsgVariable &var) { WarnOnDeferredLengthCharacterScalar(context, GetExpr(context, var), - var.v.thing.thing.GetSource(), "ERRMSG="); + parser::UnwrapRef<parser::Variable>(var) + .GetSource(), + "ERRMSG="); if (gotMsg) { context.Say( // C1178 "A errmsg-variable in a event-wait-spec-list may not be repeated"_err_en_US); diff --git a/flang/lib/Semantics/check-data.cpp b/flang/lib/Semantics/check-data.cpp index 5459290..3bcf711 100644 --- a/flang/lib/Semantics/check-data.cpp +++ b/flang/lib/Semantics/check-data.cpp @@ -25,9 +25,10 @@ namespace Fortran::semantics { // Ensures that references to an implied DO loop control variable are // represented as such in the "body" of the implied DO loop. void DataChecker::Enter(const parser::DataImpliedDo &x) { - auto name{std::get<parser::DataImpliedDo::Bounds>(x.t).name.thing.thing}; + const auto &name{parser::UnwrapRef<parser::Name>( + std::get<parser::DataImpliedDo::Bounds>(x.t).name)}; int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind}; - if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) { + if (const auto dynamicType{evaluate::DynamicType::From(DEREF(name.symbol))}) { if (dynamicType->category() == TypeCategory::Integer) { kind = dynamicType->kind(); } @@ -36,7 +37,8 @@ void DataChecker::Enter(const parser::DataImpliedDo &x) { } void DataChecker::Leave(const parser::DataImpliedDo &x) { - auto name{std::get<parser::DataImpliedDo::Bounds>(x.t).name.thing.thing}; + const auto &name{parser::UnwrapRef<parser::Name>( + std::get<parser::DataImpliedDo::Bounds>(x.t).name)}; exprAnalyzer_.RemoveImpliedDo(name.source); } @@ -211,7 +213,7 @@ void DataChecker::Leave(const parser::DataIDoObject &object) { std::get_if<parser::Scalar<common::Indirection<parser::Designator>>>( &object.u)}) { if (MaybeExpr expr{exprAnalyzer_.Analyze(*designator)}) { - auto source{designator->thing.value().source}; + auto source{parser::UnwrapRef<parser::Designator>(*designator).source}; DataVarChecker checker{exprAnalyzer_.context(), source}; if (checker(*expr)) { if (checker.HasComponentWithoutSubscripts()) { // C880 diff --git a/flang/lib/Semantics/check-deallocate.cpp b/flang/lib/Semantics/check-deallocate.cpp index c45b585..c1ebc5f 100644 --- a/flang/lib/Semantics/check-deallocate.cpp +++ b/flang/lib/Semantics/check-deallocate.cpp @@ -114,7 +114,8 @@ void DeallocateChecker::Leave(const parser::DeallocateStmt &deallocateStmt) { }, [&](const parser::MsgVariable &var) { WarnOnDeferredLengthCharacterScalar(context_, - GetExpr(context_, var), var.v.thing.thing.GetSource(), + GetExpr(context_, var), + parser::UnwrapRef<parser::Variable>(var).GetSource(), "ERRMSG="); if (gotMsg) { context_.Say( diff --git a/flang/lib/Semantics/check-do-forall.cpp b/flang/lib/Semantics/check-do-forall.cpp index a2f3685..8a47340 100644 --- a/flang/lib/Semantics/check-do-forall.cpp +++ b/flang/lib/Semantics/check-do-forall.cpp @@ -535,7 +535,8 @@ private: if (const SomeExpr * expr{GetExpr(context_, scalarExpression)}) { if (!ExprHasTypeCategory(*expr, TypeCategory::Integer)) { // No warnings or errors for type INTEGER - const parser::CharBlock &loc{scalarExpression.thing.value().source}; + parser::CharBlock loc{ + parser::UnwrapRef<parser::Expr>(scalarExpression).source}; CheckDoControl(loc, ExprHasTypeCategory(*expr, TypeCategory::Real)); } } @@ -552,7 +553,7 @@ private: CheckDoExpression(*bounds.step); if (IsZero(*bounds.step)) { context_.Warn(common::UsageWarning::ZeroDoStep, - bounds.step->thing.value().source, + parser::UnwrapRef<parser::Expr>(bounds.step).source, "DO step expression should not be zero"_warn_en_US); } } @@ -615,7 +616,7 @@ private: // C1121 - procedures in mask must be pure void CheckMaskIsPure(const parser::ScalarLogicalExpr &mask) const { UnorderedSymbolSet references{ - GatherSymbolsFromExpression(mask.thing.thing.value())}; + GatherSymbolsFromExpression(parser::UnwrapRef<parser::Expr>(mask))}; for (const Symbol &ref : OrderBySourcePosition(references)) { if (IsProcedure(ref) && !IsPureProcedure(ref)) { context_.SayWithDecl(ref, parser::Unwrap<parser::Expr>(mask)->source, @@ -639,32 +640,33 @@ private: } void HasNoReferences(const UnorderedSymbolSet &indexNames, - const parser::ScalarIntExpr &expr) const { - CheckNoCollisions(GatherSymbolsFromExpression(expr.thing.thing.value()), - indexNames, + const parser::ScalarIntExpr &scalarIntExpr) const { + const auto &expr{parser::UnwrapRef<parser::Expr>(scalarIntExpr)}; + CheckNoCollisions(GatherSymbolsFromExpression(expr), indexNames, "%s limit expression may not reference index variable '%s'"_err_en_US, - expr.thing.thing.value().source); + expr.source); } // C1129, names in local locality-specs can't be in mask expressions void CheckMaskDoesNotReferenceLocal(const parser::ScalarLogicalExpr &mask, const UnorderedSymbolSet &localVars) const { - CheckNoCollisions(GatherSymbolsFromExpression(mask.thing.thing.value()), - localVars, + const auto &expr{parser::UnwrapRef<parser::Expr>(mask)}; + CheckNoCollisions(GatherSymbolsFromExpression(expr), localVars, "%s mask expression references variable '%s'" " in LOCAL locality-spec"_err_en_US, - mask.thing.thing.value().source); + expr.source); } // C1129, names in local locality-specs can't be in limit or step // expressions - void CheckExprDoesNotReferenceLocal(const parser::ScalarIntExpr &expr, + void CheckExprDoesNotReferenceLocal( + const parser::ScalarIntExpr &scalarIntExpr, const UnorderedSymbolSet &localVars) const { - CheckNoCollisions(GatherSymbolsFromExpression(expr.thing.thing.value()), - localVars, + const auto &expr{parser::UnwrapRef<parser::Expr>(scalarIntExpr)}; + CheckNoCollisions(GatherSymbolsFromExpression(expr), localVars, "%s expression references variable '%s'" " in LOCAL locality-spec"_err_en_US, - expr.thing.thing.value().source); + expr.source); } // C1130, DEFAULT(NONE) locality requires names to be in locality-specs to @@ -772,7 +774,7 @@ private: HasNoReferences(indexNames, std::get<2>(control.t)); if (const auto &intExpr{ std::get<std::optional<parser::ScalarIntExpr>>(control.t)}) { - const parser::Expr &expr{intExpr->thing.thing.value()}; + const auto &expr{parser::UnwrapRef<parser::Expr>(intExpr)}; CheckNoCollisions(GatherSymbolsFromExpression(expr), indexNames, "%s step expression may not reference index variable '%s'"_err_en_US, expr.source); @@ -840,7 +842,7 @@ private: } void CheckForImpureCall(const parser::ScalarIntExpr &x, std::optional<IndexVarKind> nesting) const { - const auto &parsedExpr{x.thing.thing.value()}; + const auto &parsedExpr{parser::UnwrapRef<parser::Expr>(x)}; auto oldLocation{context_.location()}; context_.set_location(parsedExpr.source); if (const auto &typedExpr{parsedExpr.typedExpr}) { @@ -1124,7 +1126,8 @@ void DoForallChecker::Leave(const parser::ConnectSpec &connectSpec) { const auto *newunit{ std::get_if<parser::ConnectSpec::Newunit>(&connectSpec.u)}; if (newunit) { - context_.CheckIndexVarRedefine(newunit->v.thing.thing); + context_.CheckIndexVarRedefine( + parser::UnwrapRef<parser::Variable>(newunit)); } } @@ -1166,14 +1169,14 @@ void DoForallChecker::Leave(const parser::InquireSpec &inquireSpec) { const auto *intVar{std::get_if<parser::InquireSpec::IntVar>(&inquireSpec.u)}; if (intVar) { const auto &scalar{std::get<parser::ScalarIntVariable>(intVar->t)}; - context_.CheckIndexVarRedefine(scalar.thing.thing); + context_.CheckIndexVarRedefine(parser::UnwrapRef<parser::Variable>(scalar)); } } void DoForallChecker::Leave(const parser::IoControlSpec &ioControlSpec) { const auto *size{std::get_if<parser::IoControlSpec::Size>(&ioControlSpec.u)}; if (size) { - context_.CheckIndexVarRedefine(size->v.thing.thing); + context_.CheckIndexVarRedefine(parser::UnwrapRef<parser::Variable>(size)); } } @@ -1190,16 +1193,19 @@ static void CheckIoImpliedDoIndex( void DoForallChecker::Leave(const parser::OutputImpliedDo &outputImpliedDo) { CheckIoImpliedDoIndex(context_, - std::get<parser::IoImpliedDoControl>(outputImpliedDo.t).name.thing.thing); + parser::UnwrapRef<parser::Name>( + std::get<parser::IoImpliedDoControl>(outputImpliedDo.t).name)); } void DoForallChecker::Leave(const parser::InputImpliedDo &inputImpliedDo) { CheckIoImpliedDoIndex(context_, - std::get<parser::IoImpliedDoControl>(inputImpliedDo.t).name.thing.thing); + parser::UnwrapRef<parser::Name>( + std::get<parser::IoImpliedDoControl>(inputImpliedDo.t).name)); } void DoForallChecker::Leave(const parser::StatVariable &statVariable) { - context_.CheckIndexVarRedefine(statVariable.v.thing.thing); + context_.CheckIndexVarRedefine( + parser::UnwrapRef<parser::Variable>(statVariable)); } } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/check-io.cpp b/flang/lib/Semantics/check-io.cpp index a1ff4b9..19059ad 100644 --- a/flang/lib/Semantics/check-io.cpp +++ b/flang/lib/Semantics/check-io.cpp @@ -424,8 +424,8 @@ void IoChecker::Enter(const parser::InquireSpec::CharVar &spec) { specKind = IoSpecKind::Dispose; break; } - const parser::Variable &var{ - std::get<parser::ScalarDefaultCharVariable>(spec.t).thing.thing}; + const auto &var{parser::UnwrapRef<parser::Variable>( + std::get<parser::ScalarDefaultCharVariable>(spec.t))}; std::string what{parser::ToUpperCaseLetters(common::EnumToString(specKind))}; CheckForDefinableVariable(var, what); WarnOnDeferredLengthCharacterScalar( @@ -627,7 +627,7 @@ void IoChecker::Enter(const parser::IoUnit &spec) { } void IoChecker::Enter(const parser::MsgVariable &msgVar) { - const parser::Variable &var{msgVar.v.thing.thing}; + const auto &var{parser::UnwrapRef<parser::Variable>(msgVar)}; if (stmt_ == IoStmtKind::None) { // allocate, deallocate, image control CheckForDefinableVariable(var, "ERRMSG"); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index b4c1bf7..ea6fe43 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2358,7 +2358,7 @@ private: } if (auto &repl{std::get<parser::OmpClause::Replayable>(clause.u).v}) { // Scalar<Logical<Constant<indirection<Expr>>>> - const parser::Expr &parserExpr{repl->v.thing.thing.thing.value()}; + const auto &parserExpr{parser::UnwrapRef<parser::Expr>(repl)}; if (auto &&expr{GetEvaluateExpr(parserExpr)}) { return GetLogicalValue(*expr).value_or(true); } @@ -2372,7 +2372,7 @@ private: bool isTransparent{true}; if (auto &transp{std::get<parser::OmpClause::Transparent>(clause.u).v}) { // Scalar<Integer<indirection<Expr>>> - const parser::Expr &parserExpr{transp->v.thing.thing.value()}; + const auto &parserExpr{parser::UnwrapRef<parser::Expr>(transp)}; if (auto &&expr{GetEvaluateExpr(parserExpr)}) { // If the argument is omp_not_impex (defined as 0), then // the task is not transparent, otherwise it is. @@ -2411,8 +2411,8 @@ private: } } // Scalar<Logical<indirection<Expr>>> - auto &parserExpr{ - std::get<parser::ScalarLogicalExpr>(ifc.v.t).thing.thing.value()}; + const auto &parserExpr{parser::UnwrapRef<parser::Expr>( + std::get<parser::ScalarLogicalExpr>(ifc.v.t))}; if (auto &&expr{GetEvaluateExpr(parserExpr)}) { // If the value is known to be false, an undeferred task will be // generated. diff --git a/flang/lib/Semantics/data-to-inits.cpp b/flang/lib/Semantics/data-to-inits.cpp index 1e46dab..bbf3b28 100644 --- a/flang/lib/Semantics/data-to-inits.cpp +++ b/flang/lib/Semantics/data-to-inits.cpp @@ -179,13 +179,14 @@ bool DataInitializationCompiler<DSV>::Scan( template <typename DSV> bool DataInitializationCompiler<DSV>::Scan(const parser::DataImpliedDo &ido) { const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)}; - auto name{bounds.name.thing.thing}; - const auto *lowerExpr{ - GetExpr(exprAnalyzer_.context(), bounds.lower.thing.thing)}; - const auto *upperExpr{ - GetExpr(exprAnalyzer_.context(), bounds.upper.thing.thing)}; + const auto &name{parser::UnwrapRef<parser::Name>(bounds.name)}; + const auto *lowerExpr{GetExpr( + exprAnalyzer_.context(), parser::UnwrapRef<parser::Expr>(bounds.lower))}; + const auto *upperExpr{GetExpr( + exprAnalyzer_.context(), parser::UnwrapRef<parser::Expr>(bounds.upper))}; const auto *stepExpr{bounds.step - ? GetExpr(exprAnalyzer_.context(), bounds.step->thing.thing) + ? GetExpr(exprAnalyzer_.context(), + parser::UnwrapRef<parser::Expr>(bounds.step)) : nullptr}; if (lowerExpr && upperExpr) { // Fold the bounds expressions (again) in case any of them depend @@ -240,7 +241,9 @@ bool DataInitializationCompiler<DSV>::Scan( return common::visit( common::visitors{ [&](const parser::Scalar<common::Indirection<parser::Designator>> - &var) { return Scan(var.thing.value()); }, + &var) { + return Scan(parser::UnwrapRef<parser::Designator>(var)); + }, [&](const common::Indirection<parser::DataImpliedDo> &ido) { return Scan(ido.value()); }, diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 2feec98..4aeb9a4 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -176,8 +176,8 @@ public: // Find and return a user-defined operator or report an error. // The provided message is used if there is no such operator. - MaybeExpr TryDefinedOp( - const char *, parser::MessageFixedText, bool isUserOp = false); + MaybeExpr TryDefinedOp(const char *, parser::MessageFixedText, + bool isUserOp = false, bool checkForNullPointer = true); template <typename E> MaybeExpr TryDefinedOp(E opr, parser::MessageFixedText msg) { return TryDefinedOp( @@ -211,7 +211,8 @@ private: void SayNoMatch( const std::string &, bool isAssignment = false, bool isAmbiguous = false); std::string TypeAsFortran(std::size_t); - bool AnyUntypedOrMissingOperand() const; + bool AnyUntypedOperand() const; + bool AnyMissingOperand() const; ExpressionAnalyzer &context_; ActualArguments actuals_; @@ -1954,9 +1955,10 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) { const auto &control{std::get<parser::AcImpliedDoControl>(impliedDo.t)}; const auto &bounds{std::get<parser::AcImpliedDoControl::Bounds>(control.t)}; exprAnalyzer_.Analyze(bounds.name); - parser::CharBlock name{bounds.name.thing.thing.source}; + const auto &parsedName{parser::UnwrapRef<parser::Name>(bounds.name)}; + parser::CharBlock name{parsedName.source}; int kind{ImpliedDoIntType::kind}; - if (const Symbol * symbol{bounds.name.thing.thing.symbol}) { + if (const Symbol *symbol{parsedName.symbol}) { if (auto dynamicType{DynamicType::From(symbol)}) { if (dynamicType->category() == TypeCategory::Integer) { kind = dynamicType->kind(); @@ -1981,7 +1983,7 @@ void ArrayConstructorContext::Add(const parser::AcImpliedDo &impliedDo) { auto cUpper{ToInt64(upper)}; auto cStride{ToInt64(stride)}; if (!(messageDisplayedSet_ & 0x10) && cStride && *cStride == 0) { - exprAnalyzer_.SayAt(bounds.step.value().thing.thing.value().source, + exprAnalyzer_.SayAt(parser::UnwrapRef<parser::Expr>(bounds.step).source, "The stride of an implied DO loop must not be zero"_err_en_US); messageDisplayedSet_ |= 0x10; } @@ -2526,7 +2528,7 @@ static const Symbol *GetBindingResolution( auto ExpressionAnalyzer::AnalyzeProcedureComponentRef( const parser::ProcComponentRef &pcr, ActualArguments &&arguments, bool isSubroutine) -> std::optional<CalleeAndArguments> { - const parser::StructureComponent &sc{pcr.v.thing}; + const auto &sc{parser::UnwrapRef<parser::StructureComponent>(pcr)}; if (MaybeExpr base{Analyze(sc.base)}) { if (const Symbol *sym{sc.component.symbol}) { if (context_.HasError(sym)) { @@ -3695,11 +3697,12 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall( MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::Parentheses &x) { if (MaybeExpr operand{Analyze(x.v.value())}) { - if (const semantics::Symbol *symbol{GetLastSymbol(*operand)}) { + if (IsNullPointerOrAllocatable(&*operand)) { + Say("NULL() may not be parenthesized"_err_en_US); + } else if (const semantics::Symbol *symbol{GetLastSymbol(*operand)}) { if (const semantics::Symbol *result{FindFunctionResult(*symbol)}) { if (semantics::IsProcedurePointer(*result)) { - Say("A function reference that returns a procedure " - "pointer may not be parenthesized"_err_en_US); // C1003 + Say("A function reference that returns a procedure pointer may not be parenthesized"_err_en_US); // C1003 } } } @@ -3788,7 +3791,7 @@ MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr::DefinedUnary &x) { ArgumentAnalyzer analyzer{*this, name.source}; analyzer.Analyze(std::get<1>(x.t)); return analyzer.TryDefinedOp(name.source.ToString().c_str(), - "No operator %s defined for %s"_err_en_US, true); + "No operator %s defined for %s"_err_en_US, /*isUserOp=*/true); } // Binary (dyadic) operations @@ -3997,7 +4000,9 @@ static bool CheckFuncRefToArrayElement(semantics::SemanticsContext &context, auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)}; const auto *name{std::get_if<parser::Name>(&proc.u)}; if (!name) { - name = &std::get<parser::ProcComponentRef>(proc.u).v.thing.component; + name = &parser::UnwrapRef<parser::StructureComponent>( + std::get<parser::ProcComponentRef>(proc.u)) + .component; } if (!name->symbol) { return false; @@ -4047,14 +4052,16 @@ static void FixMisparsedFunctionReference( } } auto &proc{std::get<parser::ProcedureDesignator>(funcRef.v.t)}; - if (Symbol *origSymbol{ - common::visit(common::visitors{ - [&](parser::Name &name) { return name.symbol; }, - [&](parser::ProcComponentRef &pcr) { - return pcr.v.thing.component.symbol; - }, - }, - proc.u)}) { + if (Symbol * + origSymbol{common::visit( + common::visitors{ + [&](parser::Name &name) { return name.symbol; }, + [&](parser::ProcComponentRef &pcr) { + return parser::UnwrapRef<parser::StructureComponent>(pcr) + .component.symbol; + }, + }, + proc.u)}) { Symbol &symbol{origSymbol->GetUltimate()}; if (symbol.has<semantics::ObjectEntityDetails>() || symbol.has<semantics::AssocEntityDetails>()) { @@ -4176,15 +4183,23 @@ MaybeExpr ExpressionAnalyzer::IterativelyAnalyzeSubexpressions( } while (!queue.empty()); // Analyze the collected subexpressions in bottom-up order. // On an error, bail out and leave partial results in place. - MaybeExpr result; - for (auto riter{finish.rbegin()}; riter != finish.rend(); ++riter) { - const parser::Expr &expr{**riter}; - result = ExprOrVariable(expr, expr.source); - if (!result) { - return result; + if (finish.size() == 1) { + const parser::Expr &expr{DEREF(finish.front())}; + return ExprOrVariable(expr, expr.source); + } else { + // NULL() operand catching is deferred to operation analysis so + // that they can be accepted by defined operators. + auto restorer{AllowNullPointer()}; + MaybeExpr result; + for (auto riter{finish.rbegin()}; riter != finish.rend(); ++riter) { + const parser::Expr &expr{**riter}; + result = ExprOrVariable(expr, expr.source); + if (!result) { + return result; + } } + return result; // last value was from analysis of "top" } - return result; // last value was from analysis of "top" } MaybeExpr ExpressionAnalyzer::Analyze(const parser::Expr &expr) { @@ -4681,7 +4696,7 @@ bool ArgumentAnalyzer::AnyCUDADeviceData() const { // attribute. bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride( const char *opr) const { - if (AnyCUDADeviceData() && !AnyUntypedOrMissingOperand()) { + if (AnyCUDADeviceData() && !AnyUntypedOperand() && !AnyMissingOperand()) { std::string oprNameString{"operator("s + opr + ')'}; parser::CharBlock oprName{oprNameString}; parser::Messages buffer; @@ -4709,9 +4724,9 @@ bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride( return false; } -MaybeExpr ArgumentAnalyzer::TryDefinedOp( - const char *opr, parser::MessageFixedText error, bool isUserOp) { - if (AnyUntypedOrMissingOperand()) { +MaybeExpr ArgumentAnalyzer::TryDefinedOp(const char *opr, + parser::MessageFixedText error, bool isUserOp, bool checkForNullPointer) { + if (AnyMissingOperand()) { context_.Say(error, ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1)); return std::nullopt; } @@ -4790,7 +4805,9 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp( context_.Say( "Operands of %s are not conformable; have rank %d and rank %d"_err_en_US, ToUpperCase(opr), actuals_[0]->Rank(), actuals_[1]->Rank()); - } else if (CheckForNullPointer() && CheckForAssumedRank()) { + } else if (!CheckForAssumedRank()) { + } else if (checkForNullPointer && !CheckForNullPointer()) { + } else { // use the supplied error context_.Say(error, ToUpperCase(opr), TypeAsFortran(0), TypeAsFortran(1)); } return result; @@ -4808,15 +4825,16 @@ MaybeExpr ArgumentAnalyzer::TryDefinedOp( for (std::size_t i{0}; i < oprs.size(); ++i) { parser::Messages buffer; auto restorer{context_.GetContextualMessages().SetMessages(buffer)}; - if (MaybeExpr thisResult{TryDefinedOp(oprs[i], error)}) { + if (MaybeExpr thisResult{TryDefinedOp(oprs[i], error, /*isUserOp=*/false, + /*checkForNullPointer=*/false)}) { result = std::move(thisResult); hit.push_back(oprs[i]); hitBuffer = std::move(buffer); } } } - if (hit.empty()) { // for the error - result = TryDefinedOp(oprs[0], error); + if (hit.empty()) { // run TryDefinedOp() again just to emit errors + CHECK(!TryDefinedOp(oprs[0], error).has_value()); } else if (hit.size() > 1) { context_.Say( "Matching accessible definitions were found with %zd variant spellings of the generic operator ('%s', '%s')"_err_en_US, @@ -5232,10 +5250,19 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) { } } -bool ArgumentAnalyzer::AnyUntypedOrMissingOperand() const { +bool ArgumentAnalyzer::AnyUntypedOperand() const { + for (const auto &actual : actuals_) { + if (actual && !actual->GetType() && + !IsBareNullPointer(actual->UnwrapExpr())) { + return true; + } + } + return false; +} + +bool ArgumentAnalyzer::AnyMissingOperand() const { for (const auto &actual : actuals_) { - if (!actual || - (!actual->GetType() && !IsBareNullPointer(actual->UnwrapExpr()))) { + if (!actual) { return true; } } @@ -5268,9 +5295,9 @@ void ExprChecker::Post(const parser::DataStmtObject &obj) { bool ExprChecker::Pre(const parser::DataImpliedDo &ido) { parser::Walk(std::get<parser::DataImpliedDo::Bounds>(ido.t), *this); const auto &bounds{std::get<parser::DataImpliedDo::Bounds>(ido.t)}; - auto name{bounds.name.thing.thing}; + const auto &name{parser::UnwrapRef<parser::Name>(bounds.name)}; int kind{evaluate::ResultType<evaluate::ImpliedDoIndex>::kind}; - if (const auto dynamicType{evaluate::DynamicType::From(*name.symbol)}) { + if (const auto dynamicType{evaluate::DynamicType::From(DEREF(name.symbol))}) { if (dynamicType->category() == TypeCategory::Integer) { kind = dynamicType->kind(); } diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp index 742bb74..ac67799 100644 --- a/flang/lib/Semantics/resolve-names-utils.cpp +++ b/flang/lib/Semantics/resolve-names-utils.cpp @@ -492,12 +492,14 @@ bool EquivalenceSets::CheckDesignator(const parser::Designator &designator) { const auto &range{std::get<parser::SubstringRange>(x.t)}; bool ok{CheckDataRef(designator.source, dataRef)}; if (const auto &lb{std::get<0>(range.t)}) { - ok &= CheckSubstringBound(lb->thing.thing.value(), true); + ok &= CheckSubstringBound( + parser::UnwrapRef<parser::Expr>(lb), true); } else { currObject_.substringStart = 1; } if (const auto &ub{std::get<1>(range.t)}) { - ok &= CheckSubstringBound(ub->thing.thing.value(), false); + ok &= CheckSubstringBound( + parser::UnwrapRef<parser::Expr>(ub), false); } return ok; }, @@ -528,7 +530,8 @@ bool EquivalenceSets::CheckDataRef( return false; }, [&](const parser::IntExpr &y) { - return CheckArrayBound(y.thing.value()); + return CheckArrayBound( + parser::UnwrapRef<parser::Expr>(y)); }, }, subscript.u); diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index ae0ff9ca..699de41 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1140,7 +1140,7 @@ protected: std::optional<SourceName> BeginCheckOnIndexUseInOwnBounds( const parser::DoVariable &name) { std::optional<SourceName> result{checkIndexUseInOwnBounds_}; - checkIndexUseInOwnBounds_ = name.thing.thing.source; + checkIndexUseInOwnBounds_ = parser::UnwrapRef<parser::Name>(name).source; return result; } void EndCheckOnIndexUseInOwnBounds(const std::optional<SourceName> &restore) { @@ -2130,7 +2130,7 @@ public: void Post(const parser::SubstringInquiry &); template <typename A, typename B> void Post(const parser::LoopBounds<A, B> &x) { - ResolveName(*parser::Unwrap<parser::Name>(x.name)); + ResolveName(parser::UnwrapRef<parser::Name>(x.name)); } void Post(const parser::ProcComponentRef &); bool Pre(const parser::FunctionReference &); @@ -2560,7 +2560,7 @@ KindExpr DeclTypeSpecVisitor::GetKindParamExpr( CHECK(!state_.originalKindParameter); // Save a pointer to the KIND= expression in the parse tree // in case we need to reanalyze it during PDT instantiation. - state_.originalKindParameter = &expr->thing.thing.thing.value(); + state_.originalKindParameter = parser::Unwrap<parser::Expr>(expr); } } // Inhibit some errors now that will be caught later during instantiations. @@ -5649,6 +5649,7 @@ bool DeclarationVisitor::Pre(const parser::NamedConstantDef &x) { if (details->init() || symbol.test(Symbol::Flag::InDataStmt)) { Say(name, "Named constant '%s' already has a value"_err_en_US); } + parser::CharBlock at{parser::UnwrapRef<parser::Expr>(expr).source}; if (inOldStyleParameterStmt_) { // non-standard extension PARAMETER statement (no parentheses) Walk(expr); @@ -5657,7 +5658,6 @@ bool DeclarationVisitor::Pre(const parser::NamedConstantDef &x) { SayWithDecl(name, symbol, "Alternative style PARAMETER '%s' must not already have an explicit type"_err_en_US); } else if (folded) { - auto at{expr.thing.value().source}; if (evaluate::IsActuallyConstant(*folded)) { if (const auto *type{currScope().GetType(*folded)}) { if (type->IsPolymorphic()) { @@ -5682,8 +5682,7 @@ bool DeclarationVisitor::Pre(const parser::NamedConstantDef &x) { // standard-conforming PARAMETER statement (with parentheses) ApplyImplicitRules(symbol); Walk(expr); - if (auto converted{EvaluateNonPointerInitializer( - symbol, expr, expr.thing.value().source)}) { + if (auto converted{EvaluateNonPointerInitializer(symbol, expr, at)}) { details->set_init(std::move(*converted)); } } @@ -6149,7 +6148,7 @@ bool DeclarationVisitor::Pre(const parser::KindParam &x) { if (const auto *kind{std::get_if< parser::Scalar<parser::Integer<parser::Constant<parser::Name>>>>( &x.u)}) { - const parser::Name &name{kind->thing.thing.thing}; + const auto &name{parser::UnwrapRef<parser::Name>(kind)}; if (!FindSymbol(name)) { Say(name, "Parameter '%s' not found"_err_en_US); } @@ -7460,7 +7459,7 @@ void DeclarationVisitor::DeclareLocalEntity( Symbol *DeclarationVisitor::DeclareStatementEntity( const parser::DoVariable &doVar, const std::optional<parser::IntegerTypeSpec> &type) { - const parser::Name &name{doVar.thing.thing}; + const auto &name{parser::UnwrapRef<parser::Name>(doVar)}; const DeclTypeSpec *declTypeSpec{nullptr}; if (auto *prev{FindSymbol(name)}) { if (prev->owner() == currScope()) { @@ -7893,13 +7892,14 @@ bool ConstructVisitor::Pre(const parser::DataIDoObject &x) { common::visit( common::visitors{ [&](const parser::Scalar<Indirection<parser::Designator>> &y) { - Walk(y.thing.value()); - const parser::Name &first{parser::GetFirstName(y.thing.value())}; + const auto &designator{parser::UnwrapRef<parser::Designator>(y)}; + Walk(designator); + const parser::Name &first{parser::GetFirstName(designator)}; if (first.symbol) { first.symbol->set(Symbol::Flag::InDataStmt); } }, - [&](const Indirection<parser::DataImpliedDo> &y) { Walk(y.value()); }, + [&](const Indirection<parser::DataImpliedDo> &y) { Walk(y); }, }, x.u); return false; @@ -8582,8 +8582,7 @@ public: void Post(const parser::WriteStmt &) { inAsyncIO_ = false; } void Post(const parser::IoControlSpec::Size &size) { if (const auto *designator{ - std::get_if<common::Indirection<parser::Designator>>( - &size.v.thing.thing.u)}) { + parser::Unwrap<common::Indirection<parser::Designator>>(size)}) { NoteAsyncIODesignator(designator->value()); } } @@ -9175,16 +9174,17 @@ bool DeclarationVisitor::CheckNonPointerInitialization( } void DeclarationVisitor::NonPointerInitialization( - const parser::Name &name, const parser::ConstantExpr &expr) { + const parser::Name &name, const parser::ConstantExpr &constExpr) { if (CheckNonPointerInitialization( name, /*inLegacyDataInitialization=*/false)) { Symbol &ultimate{name.symbol->GetUltimate()}; auto &details{ultimate.get<ObjectEntityDetails>()}; + const auto &expr{parser::UnwrapRef<parser::Expr>(constExpr)}; if (ultimate.owner().IsParameterizedDerivedType()) { // Save the expression for per-instantiation analysis. - details.set_unanalyzedPDTComponentInit(&expr.thing.value()); + details.set_unanalyzedPDTComponentInit(&expr); } else if (MaybeExpr folded{EvaluateNonPointerInitializer( - ultimate, expr, expr.thing.value().source)}) { + ultimate, constExpr, expr.source)}) { details.set_init(std::move(*folded)); ultimate.set(Symbol::Flag::InDataStmt, false); } |