diff options
Diffstat (limited to 'flang/lib/Semantics')
-rw-r--r-- | flang/lib/Semantics/check-acc-structure.cpp | 226 | ||||
-rw-r--r-- | flang/lib/Semantics/check-acc-structure.h | 16 | ||||
-rw-r--r-- | flang/lib/Semantics/check-cuda.cpp | 9 | ||||
-rw-r--r-- | flang/lib/Semantics/check-declarations.cpp | 4 | ||||
-rw-r--r-- | flang/lib/Semantics/check-omp-atomic.cpp | 13 | ||||
-rw-r--r-- | flang/lib/Semantics/expression.cpp | 77 | ||||
-rw-r--r-- | flang/lib/Semantics/openmp-utils.cpp | 26 | ||||
-rw-r--r-- | flang/lib/Semantics/openmp-utils.h | 1 | ||||
-rw-r--r-- | flang/lib/Semantics/pointer-assignment.cpp | 16 | ||||
-rw-r--r-- | flang/lib/Semantics/resolve-directives.cpp | 4 |
10 files changed, 325 insertions, 67 deletions
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp index 9cbea97..77e2b01 100644 --- a/flang/lib/Semantics/check-acc-structure.cpp +++ b/flang/lib/Semantics/check-acc-structure.cpp @@ -7,8 +7,15 @@ //===----------------------------------------------------------------------===// #include "check-acc-structure.h" #include "flang/Common/enum-set.h" +#include "flang/Evaluate/tools.h" #include "flang/Parser/parse-tree.h" +#include "flang/Semantics/symbol.h" #include "flang/Semantics/tools.h" +#include "flang/Semantics/type.h" +#include "flang/Support/Fortran.h" +#include "llvm/Support/AtomicOrdering.h" + +#include <optional> #define CHECK_SIMPLE_CLAUSE(X, Y) \ void AccStructureChecker::Enter(const parser::AccClause::X &) { \ @@ -342,20 +349,219 @@ void AccStructureChecker::Leave(const parser::OpenACCAtomicConstruct &x) { dirContext_.pop_back(); } -void AccStructureChecker::Enter(const parser::AccAtomicUpdate &x) { - const parser::AssignmentStmt &assignment{ - std::get<parser::Statement<parser::AssignmentStmt>>(x.t).statement}; - const auto &var{std::get<parser::Variable>(assignment.t)}; - const auto &expr{std::get<parser::Expr>(assignment.t)}; +void AccStructureChecker::CheckAtomicStmt( + const parser::AssignmentStmt &assign, const std::string &construct) { + const auto &var{std::get<parser::Variable>(assign.t)}; + const auto &expr{std::get<parser::Expr>(assign.t)}; const auto *rhs{GetExpr(context_, expr)}; const auto *lhs{GetExpr(context_, var)}; - if (lhs && rhs) { - if (lhs->Rank() != 0) + + if (lhs) { + if (lhs->Rank() != 0) { context_.Say(expr.source, - "LHS of atomic update statement must be scalar"_err_en_US); - if (rhs->Rank() != 0) + "LHS of atomic %s statement must be scalar"_err_en_US, construct); + } + // TODO: Check if lhs is intrinsic type. + } + if (rhs) { + if (rhs->Rank() != 0) { context_.Say(var.GetSource(), - "RHS of atomic update statement must be scalar"_err_en_US); + "RHS of atomic %s statement must be scalar"_err_en_US, construct); + } + // TODO: Check if rhs is intrinsic type. + } +} + +static constexpr evaluate::operation::OperatorSet validAccAtomicUpdateOperators{ + evaluate::operation::Operator::Add, evaluate::operation::Operator::Mul, + evaluate::operation::Operator::Sub, evaluate::operation::Operator::Div, + evaluate::operation::Operator::And, evaluate::operation::Operator::Or, + evaluate::operation::Operator::Eqv, evaluate::operation::Operator::Neqv, + evaluate::operation::Operator::Max, evaluate::operation::Operator::Min}; + +static bool IsValidAtomicUpdateOperation( + const evaluate::operation::Operator &op) { + return validAccAtomicUpdateOperators.test(op); +} + +// Couldn't reproduce this behavior with evaluate::UnwrapConvertedExpr which +// is similar but only works within a single type category. +static SomeExpr GetExprModuloConversion(const SomeExpr &expr) { + const auto [op, args]{evaluate::GetTopLevelOperation(expr)}; + // Check: if it is a conversion then it must have at least one argument. + CHECK(((op != evaluate::operation::Operator::Convert && + op != evaluate::operation::Operator::Resize) || + args.size() >= 1) && + "Invalid conversion operation"); + if ((op == evaluate::operation::Operator::Convert || + op == evaluate::operation::Operator::Resize) && + args.size() >= 1) { + return args[0]; + } + return expr; +} + +void AccStructureChecker::CheckAtomicUpdateStmt( + const parser::AssignmentStmt &assign, const SomeExpr &updateVar, + const SomeExpr *captureVar) { + CheckAtomicStmt(assign, "update"); + const auto &expr{std::get<parser::Expr>(assign.t)}; + const auto *rhs{GetExpr(context_, expr)}; + if (rhs) { + const auto [op, args]{ + evaluate::GetTopLevelOperation(GetExprModuloConversion(*rhs))}; + if (!IsValidAtomicUpdateOperation(op)) { + context_.Say(expr.source, + "Invalid atomic update operation, can only use: *, +, -, *, /, and, or, eqv, neqv, max, min, iand, ior, ieor"_err_en_US); + } else { + bool foundUpdateVar{false}; + for (const auto &arg : args) { + if (updateVar == GetExprModuloConversion(arg)) { + if (foundUpdateVar) { + context_.Say(expr.source, + "The updated variable, %s, cannot appear more than once in the atomic update operation"_err_en_US, + updateVar.AsFortran()); + } else { + foundUpdateVar = true; + } + } else if (evaluate::IsVarSubexpressionOf(updateVar, arg)) { + // TODO: Get the source location of arg and point to the individual + // argument. + context_.Say(expr.source, + "Arguments to the atomic update operation cannot reference the updated variable, %s, as a subexpression"_err_en_US, + updateVar.AsFortran()); + } + } + if (!foundUpdateVar) { + context_.Say(expr.source, + "The RHS of this atomic update statement must reference the updated variable: %s"_err_en_US, + updateVar.AsFortran()); + } + } + } +} + +void AccStructureChecker::CheckAtomicWriteStmt( + const parser::AssignmentStmt &assign, const SomeExpr &updateVar, + const SomeExpr *captureVar) { + CheckAtomicStmt(assign, "write"); + const auto &expr{std::get<parser::Expr>(assign.t)}; + const auto *rhs{GetExpr(context_, expr)}; + if (rhs) { + if (evaluate::IsVarSubexpressionOf(updateVar, *rhs)) { + context_.Say(expr.source, + "The RHS of this atomic write statement cannot reference the atomic variable: %s"_err_en_US, + updateVar.AsFortran()); + } + } +} + +void AccStructureChecker::CheckAtomicCaptureStmt( + const parser::AssignmentStmt &assign, const SomeExpr *updateVar, + const SomeExpr &captureVar) { + CheckAtomicStmt(assign, "capture"); +} + +void AccStructureChecker::Enter(const parser::AccAtomicCapture &capture) { + const Fortran::parser::AssignmentStmt &stmt1{ + std::get<Fortran::parser::AccAtomicCapture::Stmt1>(capture.t) + .v.statement}; + const Fortran::parser::AssignmentStmt &stmt2{ + std::get<Fortran::parser::AccAtomicCapture::Stmt2>(capture.t) + .v.statement}; + const auto &var1{std::get<parser::Variable>(stmt1.t)}; + const auto &var2{std::get<parser::Variable>(stmt2.t)}; + const auto *lhs1{GetExpr(context_, var1)}; + const auto *lhs2{GetExpr(context_, var2)}; + if (!lhs1 || !lhs2) { + // Not enough information to check. + return; + } + if (*lhs1 == *lhs2) { + context_.Say(std::get<parser::Verbatim>(capture.t).source, + "The variables assigned in this atomic capture construct must be distinct"_err_en_US); + return; + } + const auto &expr1{std::get<parser::Expr>(stmt1.t)}; + const auto &expr2{std::get<parser::Expr>(stmt2.t)}; + const auto *rhs1{GetExpr(context_, expr1)}; + const auto *rhs2{GetExpr(context_, expr2)}; + if (!rhs1 || !rhs2) { + return; + } + bool stmt1CapturesLhs2{*lhs2 == GetExprModuloConversion(*rhs1)}; + bool stmt2CapturesLhs1{*lhs1 == GetExprModuloConversion(*rhs2)}; + if (stmt1CapturesLhs2 && !stmt2CapturesLhs1) { + if (*lhs2 == GetExprModuloConversion(*rhs2)) { + // a = b; b = b: Doesn't fit the spec. + context_.Say(std::get<parser::Verbatim>(capture.t).source, + "The assignments in this atomic capture construct do not update a variable and capture either its initial or final value"_err_en_US); + // TODO: Add attatchment that a = b seems to be a capture, + // but b = b is not a valid update or write. + } else if (evaluate::IsVarSubexpressionOf(*lhs2, *rhs2)) { + // Take v = x; x = <expr w/ x> as capture; update + const auto &updateVar{*lhs2}; + const auto &captureVar{*lhs1}; + CheckAtomicCaptureStmt(stmt1, &updateVar, captureVar); + CheckAtomicUpdateStmt(stmt2, updateVar, &captureVar); + } else { + // Take v = x; x = <expr w/o x> as capture; write + const auto &updateVar{*lhs2}; + const auto &captureVar{*lhs1}; + CheckAtomicCaptureStmt(stmt1, &updateVar, captureVar); + CheckAtomicWriteStmt(stmt2, updateVar, &captureVar); + } + } else if (stmt2CapturesLhs1 && !stmt1CapturesLhs2) { + if (*lhs1 == GetExprModuloConversion(*rhs1)) { + // Error a = a; b = a; + context_.Say(var1.GetSource(), + "The first assignment in this atomic capture construct doesn't perform a valid update"_err_en_US); + // Add attatchment that a = a is not considered an update, + // but b = a seems to be a capture. + } else { + // Take x = <expr>; v = x: as update; capture + const auto &updateVar{*lhs1}; + const auto &captureVar{*lhs2}; + CheckAtomicUpdateStmt(stmt1, updateVar, &captureVar); + CheckAtomicCaptureStmt(stmt2, &updateVar, captureVar); + } + } else if (stmt1CapturesLhs2 && stmt2CapturesLhs1) { + // x1 = x2; x2 = x1; Doesn't fit the spec. + context_.Say(std::get<parser::Verbatim>(capture.t).source, + "The assignments in this atomic capture construct do not update a variable and capture either its initial or final value"_err_en_US); + // TODO: Add attatchment that both assignments seem to be captures. + } else { // !stmt1CapturesLhs2 && !stmt2CapturesLhs1 + // a = <expr != b>; b = <expr != a>; Doesn't fit the spec + context_.Say(std::get<parser::Verbatim>(capture.t).source, + "The assignments in this atomic capture construct do not update a variable and capture either its initial or final value"_err_en_US); + // TODO: Add attatchment that neither assignment seems to be a capture. + } +} + +void AccStructureChecker::Enter(const parser::AccAtomicUpdate &x) { + const auto &assign{ + std::get<parser::Statement<parser::AssignmentStmt>>(x.t).statement}; + const auto &var{std::get<parser::Variable>(assign.t)}; + if (const auto *updateVar{GetExpr(context_, var)}) { + CheckAtomicUpdateStmt(assign, *updateVar, /*captureVar=*/nullptr); + } +} + +void AccStructureChecker::Enter(const parser::AccAtomicWrite &x) { + const auto &assign{ + std::get<parser::Statement<parser::AssignmentStmt>>(x.t).statement}; + const auto &var{std::get<parser::Variable>(assign.t)}; + if (const auto *updateVar{GetExpr(context_, var)}) { + CheckAtomicWriteStmt(assign, *updateVar, /*captureVar=*/nullptr); + } +} + +void AccStructureChecker::Enter(const parser::AccAtomicRead &x) { + const auto &assign{ + std::get<parser::Statement<parser::AssignmentStmt>>(x.t).statement}; + const auto &var{std::get<parser::Variable>(assign.t)}; + if (const auto *captureVar{GetExpr(context_, var)}) { + CheckAtomicCaptureStmt(assign, /*updateVar=*/nullptr, *captureVar); } } diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h index 6a9aa01..359f155 100644 --- a/flang/lib/Semantics/check-acc-structure.h +++ b/flang/lib/Semantics/check-acc-structure.h @@ -63,6 +63,9 @@ public: void Enter(const parser::OpenACCCacheConstruct &); void Leave(const parser::OpenACCCacheConstruct &); void Enter(const parser::AccAtomicUpdate &); + void Enter(const parser::AccAtomicCapture &); + void Enter(const parser::AccAtomicWrite &); + void Enter(const parser::AccAtomicRead &); void Enter(const parser::OpenACCEndConstruct &); // Clauses @@ -80,6 +83,19 @@ public: #include "llvm/Frontend/OpenACC/ACC.inc" private: + void CheckAtomicStmt( + const parser::AssignmentStmt &assign, const std::string &construct); + void CheckAtomicUpdateStmt(const parser::AssignmentStmt &assign, + const SomeExpr &updateVar, const SomeExpr *captureVar); + void CheckAtomicCaptureStmt(const parser::AssignmentStmt &assign, + const SomeExpr *updateVar, const SomeExpr &captureVar); + void CheckAtomicWriteStmt(const parser::AssignmentStmt &assign, + const SomeExpr &updateVar, const SomeExpr *captureVar); + void CheckAtomicUpdateVariable( + const parser::Variable &updateVar, const parser::Variable &captureVar); + void CheckAtomicCaptureVariable( + const parser::Variable &captureVar, const parser::Variable &updateVar); + bool CheckAllowedModifier(llvm::acc::Clause clause); bool IsComputeConstruct(llvm::acc::Directive directive) const; bool IsInsideComputeConstruct() const; diff --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp index b011476..9b48432 100644 --- a/flang/lib/Semantics/check-cuda.cpp +++ b/flang/lib/Semantics/check-cuda.cpp @@ -761,14 +761,13 @@ void CUDAChecker::Enter(const parser::AssignmentStmt &x) { // legal. if (nbLhs == 0 && nbRhs > 1) { context_.Say(lhsLoc, - "More than one reference to a CUDA object on the right hand side of the assigment"_err_en_US); + "More than one reference to a CUDA object on the right hand side of the assignment"_err_en_US); } - if (Fortran::evaluate::HasCUDADeviceAttrs(assign->lhs) && - Fortran::evaluate::HasCUDAImplicitTransfer(assign->rhs)) { + if (evaluate::HasCUDADeviceAttrs(assign->lhs) && + evaluate::HasCUDAImplicitTransfer(assign->rhs)) { if (GetNbOfCUDAManagedOrUnifiedSymbols(assign->lhs) == 1 && - GetNbOfCUDAManagedOrUnifiedSymbols(assign->rhs) == 1 && - GetNbOfCUDADeviceSymbols(assign->rhs) == 1) { + GetNbOfCUDAManagedOrUnifiedSymbols(assign->rhs) == 1 && nbRhs == 1) { return; // This is a special case handled on the host. } context_.Say(lhsLoc, "Unsupported CUDA data transfer"_err_en_US); diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index a2f2906..d769f22 100644 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -2081,7 +2081,7 @@ static bool ConflictsWithIntrinsicAssignment(const Procedure &proc) { } static bool ConflictsWithIntrinsicOperator( - const GenericKind &kind, const Procedure &proc) { + const GenericKind &kind, const Procedure &proc, SemanticsContext &context) { if (!kind.IsIntrinsicOperator()) { return false; } @@ -2167,7 +2167,7 @@ bool CheckHelper::CheckDefinedOperator(SourceName opName, GenericKind kind, } } else if (!checkDefinedOperatorArgs(opName, specific, proc)) { return false; // error was reported - } else if (ConflictsWithIntrinsicOperator(kind, proc)) { + } else if (ConflictsWithIntrinsicOperator(kind, proc, context_)) { msg = "%s function '%s' conflicts with intrinsic operator"_err_en_US; } if (msg) { diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp index c5ed879..333fad0 100644 --- a/flang/lib/Semantics/check-omp-atomic.cpp +++ b/flang/lib/Semantics/check-omp-atomic.cpp @@ -197,7 +197,8 @@ static std::pair<parser::CharBlock, parser::CharBlock> SplitAssignmentSource( } static bool IsCheckForAssociated(const SomeExpr &cond) { - return GetTopLevelOperation(cond).first == operation::Operator::Associated; + return GetTopLevelOperationIgnoreResizing(cond).first == + operation::Operator::Associated; } static bool IsMaybeAtomicWrite(const evaluate::Assignment &assign) { @@ -399,8 +400,8 @@ OmpStructureChecker::CheckUpdateCapture( // subexpression of the right-hand side. // 2. An assignment could be a capture (cbc) if the right-hand side is // a variable (or a function ref), with potential type conversions. - bool cbu1{IsSubexpressionOf(as1.lhs, as1.rhs)}; // Can as1 be an update? - bool cbu2{IsSubexpressionOf(as2.lhs, as2.rhs)}; // Can as2 be an update? + bool cbu1{IsVarSubexpressionOf(as1.lhs, as1.rhs)}; // Can as1 be an update? + bool cbu2{IsVarSubexpressionOf(as2.lhs, as2.rhs)}; // Can as2 be an update? bool cbc1{IsVarOrFunctionRef(GetConvertInput(as1.rhs))}; // Can 1 be capture? bool cbc2{IsVarOrFunctionRef(GetConvertInput(as2.rhs))}; // Can 2 be capture? @@ -607,7 +608,7 @@ void OmpStructureChecker::CheckAtomicUpdateAssignment( std::pair<operation::Operator, std::vector<SomeExpr>> top{ operation::Operator::Unknown, {}}; if (auto &&maybeInput{GetConvertInput(update.rhs)}) { - top = GetTopLevelOperation(*maybeInput); + top = GetTopLevelOperationIgnoreResizing(*maybeInput); } switch (top.first) { case operation::Operator::Add: @@ -657,7 +658,7 @@ void OmpStructureChecker::CheckAtomicUpdateAssignment( if (IsSameOrConvertOf(arg, atom)) { ++count; } else { - if (!subExpr && IsSubexpressionOf(atom, arg)) { + if (!subExpr && evaluate::IsVarSubexpressionOf(atom, arg)) { subExpr = arg; } nonAtom.push_back(arg); @@ -715,7 +716,7 @@ void OmpStructureChecker::CheckAtomicConditionalUpdateAssignment( CheckAtomicVariable(atom, alsrc); - auto top{GetTopLevelOperation(cond)}; + auto top{GetTopLevelOperationIgnoreResizing(cond)}; // Missing arguments to operations would have been diagnosed by now. switch (top.first) { diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp index 1447372..92dbe0e 100644 --- a/flang/lib/Semantics/expression.cpp +++ b/flang/lib/Semantics/expression.cpp @@ -165,10 +165,17 @@ public: bool CheckForNullPointer(const char *where = "as an operand here"); bool CheckForAssumedRank(const char *where = "as an operand here"); + bool AnyCUDADeviceData() const; + // Returns true if an interface has been defined for an intrinsic operator + // with one or more device operands. + bool HasDeviceDefinedIntrinsicOpOverride(const char *) const; + template <typename E> bool HasDeviceDefinedIntrinsicOpOverride(E opr) const { + return HasDeviceDefinedIntrinsicOpOverride( + context_.context().languageFeatures().GetNames(opr)); + } + // Find and return a user-defined operator or report an error. // The provided message is used if there is no such operator. - // If a definedOpSymbolPtr is provided, the caller must check - // for its accessibility. MaybeExpr TryDefinedOp( const char *, parser::MessageFixedText, bool isUserOp = false); template <typename E> @@ -183,6 +190,8 @@ public: void Dump(llvm::raw_ostream &); private: + bool HasDeviceDefinedIntrinsicOpOverride( + const std::vector<const char *> &) const; MaybeExpr TryDefinedOp( const std::vector<const char *> &, parser::MessageFixedText); MaybeExpr TryBoundOp(const Symbol &, int passIndex); @@ -202,7 +211,7 @@ private: void SayNoMatch( const std::string &, bool isAssignment = false, bool isAmbiguous = false); std::string TypeAsFortran(std::size_t); - bool AnyUntypedOrMissingOperand(); + bool AnyUntypedOrMissingOperand() const; ExpressionAnalyzer &context_; ActualArguments actuals_; @@ -4497,13 +4506,20 @@ void ArgumentAnalyzer::Analyze( bool ArgumentAnalyzer::IsIntrinsicRelational(RelationalOperator opr, const DynamicType &leftType, const DynamicType &rightType) const { CHECK(actuals_.size() == 2); - return semantics::IsIntrinsicRelational( - opr, leftType, GetRank(0), rightType, GetRank(1)); + return !(context_.context().languageFeatures().IsEnabled( + common::LanguageFeature::CUDA) && + HasDeviceDefinedIntrinsicOpOverride(opr)) && + semantics::IsIntrinsicRelational( + opr, leftType, GetRank(0), rightType, GetRank(1)); } bool ArgumentAnalyzer::IsIntrinsicNumeric(NumericOperator opr) const { std::optional<DynamicType> leftType{GetType(0)}; - if (actuals_.size() == 1) { + if (context_.context().languageFeatures().IsEnabled( + common::LanguageFeature::CUDA) && + HasDeviceDefinedIntrinsicOpOverride(AsFortran(opr))) { + return false; + } else if (actuals_.size() == 1) { if (IsBOZLiteral(0)) { return opr == NumericOperator::Add; // unary '+' } else { @@ -4617,6 +4633,53 @@ bool ArgumentAnalyzer::CheckForAssumedRank(const char *where) { return true; } +bool ArgumentAnalyzer::AnyCUDADeviceData() const { + for (const std::optional<ActualArgument> &arg : actuals_) { + if (arg) { + if (const Expr<SomeType> *expr{arg->UnwrapExpr()}) { + if (HasCUDADeviceAttrs(*expr)) { + return true; + } + } + } + } + return false; +} + +// Some operations can be defined with explicit non-type-bound interfaces +// that would erroneously conflict with intrinsic operations in their +// types and ranks but have one or more dummy arguments with the DEVICE +// attribute. +bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride( + const char *opr) const { + if (AnyCUDADeviceData() && !AnyUntypedOrMissingOperand()) { + std::string oprNameString{"operator("s + opr + ')'}; + parser::CharBlock oprName{oprNameString}; + parser::Messages buffer; + auto restorer{context_.GetContextualMessages().SetMessages(buffer)}; + const auto &scope{context_.context().FindScope(source_)}; + if (Symbol * generic{scope.FindSymbol(oprName)}) { + parser::Name name{generic->name(), generic}; + const Symbol *resultSymbol{nullptr}; + if (context_.AnalyzeDefinedOp( + name, ActualArguments{actuals_}, resultSymbol)) { + return true; + } + } + } + return false; +} + +bool ArgumentAnalyzer::HasDeviceDefinedIntrinsicOpOverride( + const std::vector<const char *> &oprNames) const { + for (const char *opr : oprNames) { + if (HasDeviceDefinedIntrinsicOpOverride(opr)) { + return true; + } + } + return false; +} + MaybeExpr ArgumentAnalyzer::TryDefinedOp( const char *opr, parser::MessageFixedText error, bool isUserOp) { if (AnyUntypedOrMissingOperand()) { @@ -5135,7 +5198,7 @@ std::string ArgumentAnalyzer::TypeAsFortran(std::size_t i) { } } -bool ArgumentAnalyzer::AnyUntypedOrMissingOperand() { +bool ArgumentAnalyzer::AnyUntypedOrMissingOperand() const { for (const auto &actual : actuals_) { if (!actual || (!actual->GetType() && !IsBareNullPointer(actual->UnwrapExpr()))) { diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp index da14507..7a492a4 100644 --- a/flang/lib/Semantics/openmp-utils.cpp +++ b/flang/lib/Semantics/openmp-utils.cpp @@ -270,28 +270,6 @@ struct DesignatorCollector : public evaluate::Traverse<DesignatorCollector, } }; -struct VariableFinder : public evaluate::AnyTraverse<VariableFinder> { - using Base = evaluate::AnyTraverse<VariableFinder>; - VariableFinder(const SomeExpr &v) : Base(*this), var(v) {} - - using Base::operator(); - - template <typename T> - bool operator()(const evaluate::Designator<T> &x) const { - auto copy{x}; - return evaluate::AsGenericExpr(std::move(copy)) == var; - } - - template <typename T> - bool operator()(const evaluate::FunctionRef<T> &x) const { - auto copy{x}; - return evaluate::AsGenericExpr(std::move(copy)) == var; - } - -private: - const SomeExpr &var; -}; - std::vector<SomeExpr> GetAllDesignators(const SomeExpr &expr) { return DesignatorCollector{}(expr); } @@ -380,10 +358,6 @@ const SomeExpr *HasStorageOverlap( return nullptr; } -bool IsSubexpressionOf(const SomeExpr &sub, const SomeExpr &super) { - return VariableFinder{sub}(super); -} - // Check if the ActionStmt is actually a [Pointer]AssignmentStmt. This is // to separate cases where the source has something that looks like an // assignment, but is semantically wrong (diagnosed by general semantic diff --git a/flang/lib/Semantics/openmp-utils.h b/flang/lib/Semantics/openmp-utils.h index 001fbeb..b8ad9ed 100644 --- a/flang/lib/Semantics/openmp-utils.h +++ b/flang/lib/Semantics/openmp-utils.h @@ -72,7 +72,6 @@ std::optional<bool> IsContiguous( std::vector<SomeExpr> GetAllDesignators(const SomeExpr &expr); const SomeExpr *HasStorageOverlap( const SomeExpr &base, llvm::ArrayRef<SomeExpr> exprs); -bool IsSubexpressionOf(const SomeExpr &sub, const SomeExpr &super); bool IsAssignment(const parser::ActionStmt *x); bool IsPointerAssignment(const evaluate::Assignment &x); const parser::Block &GetInnermostExecPart(const parser::Block &block); diff --git a/flang/lib/Semantics/pointer-assignment.cpp b/flang/lib/Semantics/pointer-assignment.cpp index 0908769..e767bf8 100644 --- a/flang/lib/Semantics/pointer-assignment.cpp +++ b/flang/lib/Semantics/pointer-assignment.cpp @@ -270,18 +270,18 @@ bool PointerAssignmentChecker::Check(const evaluate::FunctionRef<T> &f) { std::optional<MessageFixedText> msg; const auto &funcResult{proc->functionResult}; // C1025 if (!funcResult) { - msg = "%s is associated with the non-existent result of reference to" - " procedure"_err_en_US; + msg = + "%s is associated with the non-existent result of reference to procedure"_err_en_US; } else if (CharacterizeProcedure()) { // Shouldn't be here in this function unless lhs is an object pointer. - msg = "Procedure %s is associated with the result of a reference to" - " function '%s' that does not return a procedure pointer"_err_en_US; + msg = + "Procedure %s is associated with the result of a reference to function '%s' that does not return a procedure pointer"_err_en_US; } else if (funcResult->IsProcedurePointer()) { - msg = "Object %s is associated with the result of a reference to" - " function '%s' that is a procedure pointer"_err_en_US; + msg = + "Object %s is associated with the result of a reference to function '%s' that is a procedure pointer"_err_en_US; } else if (!funcResult->attrs.test(FunctionResult::Attr::Pointer)) { - msg = "%s is associated with the result of a reference to function '%s'" - " that is a not a pointer"_err_en_US; + msg = + "%s is associated with the result of a reference to function '%s' that is not a pointer"_err_en_US; } else if (isContiguous_ && !funcResult->attrs.test(FunctionResult::Attr::Contiguous)) { auto restorer{common::ScopedSet(lhs_, symbol)}; diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 4c3e509..aa006b1 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -1545,6 +1545,7 @@ void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) { void AccAttributeVisitor::Post(const parser::Name &name) { auto *symbol{name.symbol}; if (symbol && !dirContext_.empty() && GetContext().withinConstruct) { + symbol = &symbol->GetUltimate(); if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() && !symbol->has<SubprogramDetails>() && !IsObjectWithDSA(*symbol)) { if (Symbol * found{currScope().FindSymbol(name.source)}) { @@ -1553,8 +1554,7 @@ void AccAttributeVisitor::Post(const parser::Name &name) { } else if (GetContext().defaultDSA == Symbol::Flag::AccNone) { // 2.5.14. context_.Say(name.source, - "The DEFAULT(NONE) clause requires that '%s' must be listed in " - "a data-mapping clause"_err_en_US, + "The DEFAULT(NONE) clause requires that '%s' must be listed in a data-mapping clause"_err_en_US, symbol->name()); } } |