Repository: llvm/llvm-project
File: flang/lib/Semantics/resolve-names.cpp (C++)

Code before:
bool OmpVisitor::Pre(const parser::OmpClause::To &x) {
  auto &mods{OmpGetModifiers(x.v)};
  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
    ResolveMapperModifier(*mapper);
  }
  return true;
}

bool OmpVisitor::Pre(const parser::OmpClause::From &x) {
  auto &mods{OmpGetModifiers(x.v)};
  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
    ResolveMapperModifier(*mapper);
  }
  return true;
}

void OmpVisitor::ResolveMapperModifier(const parser::OmpMapper &mapper) {
  if (auto *symbol{FindSymbol(currScope(), mapper.v)}) {
    auto &ultimate{symbol->GetUltimate()};
    auto *misc{ultimate.detailsIf<MiscDetails>()};
    auto *md{ultimate.detailsIf<MapperDetails>()};
    if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName))
      context().Say(mapper.v.source,
          "Name '%s' should be a mapper name"_err_en_US, mapper.v.source);
    else
      const_cast<parser::OmpMapper &>(mapper).v.symbol = symbol;
  } else {
    // Allow the special 'default' mapper identifier without prior
    // declaration so lowering can recognize and handle it. Emit an
    // error for any other missing mapper identifier.
    if (mapper.v.source.ToString() == "default") {
      const_cast<parser::OmpMapper &>(mapper).v.symbol =
          &MakeSymbol(mapper.v, MiscDetails{MiscDetails::Kind::ConstructName});
    } else {
      context().Say(
          mapper.v.source, "'%s' not declared"_err_en_US, mapper.v.source);
    }
  }
}

void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
    const parser::OmpClauseList &clauses) {
  // This "manually" walks the tree of the construct, because we need
  // to resolve the type before the map clauses are processed - when
  // just following the natural flow, the map clauses gets processed before
  // the type has been fully processed.
  BeginDeclTypeSpec();
  auto &mapperName{std::get<std::string>(spec.t)};
  // Create or update the mapper symbol with MapperDetails and
  // keep track of the declarative construct for module emission.
  SourceName mapperSource{context().SaveTempName(std::string{mapperName})};

Review comment (bug):
The cast isn't necessary.  The `symbol` member is mutable:
```
struct Name {
  std::string ToString() const { return source.ToString(); }
  CharBlock source;
  mutable semantics::Symbol *symbol{nullptr}; // filled in during semantics
};
```

Code after:
  return true;
}

bool OmpVisitor::Pre(const parser::OmpClause::To &x) {
  auto &mods{OmpGetModifiers(x.v)};
  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
    ResolveMapperModifier(*mapper);
  }
  return true;
}

bool OmpVisitor::Pre(const parser::OmpClause::From &x) {
  auto &mods{OmpGetModifiers(x.v)};
  if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
    ResolveMapperModifier(*mapper);
  }
  return true;
}

void OmpVisitor::ResolveMapperModifier(const parser::OmpMapper &mapper) {
  if (auto *symbol{FindSymbol(currScope(), mapper.v)}) {
    auto &ultimate{symbol->GetUltimate()};
    auto *misc{ultimate.detailsIf<MiscDetails>()};
    auto *md{ultimate.detailsIf<MapperDetails>()};
    if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName))
      context().Say(mapper.v.source,
          "Name '%s' should be a mapper name"_err_en_US, mapper.v.source);
    else
      mapper.v.symbol = symbol;
  } else {
    // Allow the special 'default' mapper identifier without prior
    // declaration so lowering can recognize and handle it. Emit an
    // error for any other missing mapper identifier.
    if (mapper.v.source.ToString() == "default") {
      mapper.v.symbol =
          &MakeSymbol(mapper.v, MiscDetails{MiscDetails::Kind::ConstructName});
    } else {
      context().Say(
          mapper.v.source, "'%s' not declared"_err_en_US, mapper.v.source);
    }
  }
}

void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
    const parser::OmpClauseList &clauses) {
  // This "manually" walks the tree of the construct, because we need
  // to resolve the type before the map clauses are processed - when
  // just following the natural flow, the map clauses gets processed before
  // the type has been fully processed.
  BeginDeclTypeSpec();
  auto &mapperName{std::get<std::string>(spec.t)};