Skip to content

Commit

Permalink
[Flang][OpenMP][Sema] More gracefully handle undefined symbol in a no…
Browse files Browse the repository at this point in the history
… implicit module for declare target

Prior to this change, if you define a module as such with a declare target in it:

module test_0
    implicit none
!$omp declare target(no_implicit_materialization_1)
end module test_0

The compiler will crash rather than give some form of reasonable
diagnostic. This patch attempts to fix that.

Reviewers: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D149913
  • Loading branch information
agozillon committed May 5, 2023
1 parent 11d1be4 commit 39b747d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 3 deletions.
46 changes: 43 additions & 3 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,13 @@ void OmpStructureChecker::CheckThreadprivateOrDeclareTargetVar(
common::visitors{
[&](const parser::Designator &) {
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
// The symbol is null, return early, CheckSymbolNames
// should have already reported the missing symbol as a
// diagnostic error
if (!name->symbol) {
return;
}

if (name->symbol->GetUltimate().IsSubprogram()) {
if (GetContext().directive ==
llvm::omp::Directive::OMPD_threadprivate)
Expand Down Expand Up @@ -1061,6 +1068,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPThreadprivate &c) {
void OmpStructureChecker::Leave(const parser::OpenMPThreadprivate &c) {
const auto &dir{std::get<parser::Verbatim>(c.t)};
const auto &objectList{std::get<parser::OmpObjectList>(c.t)};
CheckSymbolNames(dir.source, objectList);
CheckIsVarPartOfAnotherVar(dir.source, objectList);
CheckThreadprivateOrDeclareTargetVar(objectList);
dirContext_.pop_back();
Expand Down Expand Up @@ -1117,20 +1125,49 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
}
}

void OmpStructureChecker::CheckSymbolNames(
const parser::CharBlock &source, const parser::OmpObjectList &objList) {
for (const auto &ompObject : objList.v) {
common::visit(
common::visitors{
[&](const parser::Designator &designator) {
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
if (!name->symbol) {
context_.Say(source,
"The given %s directive clause has an invalid argument"_err_en_US,
ContextDirectiveAsFortran());
}
}
},
[&](const parser::Name &name) {
if (!name.symbol) {
context_.Say(source,
"The given %s directive clause has an invalid argument"_err_en_US,
ContextDirectiveAsFortran());
}
},
},
ompObject.u);
}
}

void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
const auto &spec{std::get<parser::OmpDeclareTargetSpecifier>(x.t)};
if (const auto *objectList{parser::Unwrap<parser::OmpObjectList>(spec.u)}) {
CheckSymbolNames(dir.source, *objectList);
CheckIsVarPartOfAnotherVar(dir.source, *objectList);
CheckThreadprivateOrDeclareTargetVar(*objectList);
} else if (const auto *clauseList{
parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
for (const auto &clause : clauseList->v) {
if (const auto *toClause{std::get_if<parser::OmpClause::To>(&clause.u)}) {
CheckSymbolNames(dir.source, toClause->v);
CheckIsVarPartOfAnotherVar(dir.source, toClause->v);
CheckThreadprivateOrDeclareTargetVar(toClause->v);
} else if (const auto *linkClause{
std::get_if<parser::OmpClause::Link>(&clause.u)}) {
CheckSymbolNames(dir.source, linkClause->v);
CheckIsVarPartOfAnotherVar(dir.source, linkClause->v);
CheckThreadprivateOrDeclareTargetVar(linkClause->v);
}
Expand Down Expand Up @@ -1797,9 +1834,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
common::visitors{
[&](const parser::Designator &) {
if (const auto *name{
parser::Unwrap<parser::Name>(ompObject)})
testThreadprivateVarErr(
name->symbol->GetUltimate(), *name, type);
parser::Unwrap<parser::Name>(ompObject)}) {
if (name->symbol) {
testThreadprivateVarErr(
name->symbol->GetUltimate(), *name, type);
}
}
},
[&](const parser::Name &name) {
if (name.symbol) {
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Semantics/check-omp-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ class OmpStructureChecker
const parser::CharBlock &source, const parser::OmpObjectList &objList);
void CheckThreadprivateOrDeclareTargetVar(
const parser::OmpObjectList &objList);
void CheckSymbolNames(
const parser::CharBlock &source, const parser::OmpObjectList &objList);
void CheckIntentInPointer(
const parser::OmpObjectList &, const llvm::omp::Clause);
void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &);
Expand Down
23 changes: 23 additions & 0 deletions flang/test/Semantics/OpenMP/declare-target06.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
! OpenMP Version 5.1
! Check OpenMP construct validity for the following directives:
! 2.14.7 Declare Target Directive
! When used in an implicit none context.

module test_0
implicit none
!ERROR: The given DECLARE TARGET directive clause has an invalid argument
!ERROR: No explicit type declared for 'no_implicit_materialization_1'
!$omp declare target(no_implicit_materialization_1)

!ERROR: The given DECLARE TARGET directive clause has an invalid argument
!ERROR: No explicit type declared for 'no_implicit_materialization_2'
!$omp declare target link(no_implicit_materialization_2)

!ERROR: The given DECLARE TARGET directive clause has an invalid argument
!ERROR: No explicit type declared for 'no_implicit_materialization_3'
!$omp declare target to(no_implicit_materialization_3)

INTEGER :: data_int = 10
!$omp declare target(data_int)
end module test_0

0 comments on commit 39b747d

Please sign in to comment.