Repository: carbon-language/carbon-lang
File: toolchain/check/cpp/import.cpp (C++)

Code before:
  SemIR::InstId builtin_inst_id =
      LookupBuiltinName(context, loc_id, scope_id, name_id);
  if (builtin_inst_id.has_value()) {
    AddNameToScope(context, scope_id, name_id, SemIR::AccessKind::Public,
                   builtin_inst_id);
    return SemIR::ScopeLookupResult::MakeWrappedLookupResult(
        builtin_inst_id, SemIR::AccessKind::Public);
  }
  return SemIR::ScopeLookupResult::MakeNotFound();
}

// Checks if the name scope is a class that is not complete.
static auto IsIncompleteClass(Context& context, SemIR::NameScopeId scope_id)
    -> bool {
  auto class_decl = context.insts().TryGetAs<SemIR::ClassDecl>(
      context.name_scopes().Get(scope_id).inst_id());
  return class_decl.has_value() &&
         !context.types().IsComplete(
             context.classes().Get(class_decl->class_id).self_type_id);
}

// TODO: dedup with code in `MapConstant` and `TryEvaluateMacroToConstant`.
auto MapAPValueToConstant(Context& context, SemIR::LocId loc_id,
                          const clang::APValue& ap_value, clang::QualType type)
    -> SemIR::ConstantId {
  SemIR::TypeId type_id = MapType(context, loc_id, type).type_id;
  if (!type_id.has_value()) {
    return SemIR::ConstantId::NotConstant;
  }

  if (ap_value.isInt()) {
    int64_t value = ap_value.getInt().getExtValue();

    if (type->isBooleanType()) {
      return TryEvalInst(
          context, SemIR::BoolLiteral{.type_id = type_id,
                                      .value = SemIR::BoolValue::From(value)});

    } else {
      IntId int_id = context.ints().Add(value);
      return TryEvalInst(context,
                         SemIR::IntValue{.type_id = type_id, .int_id = int_id});
    }
  } else {
    // TODO: support other types.
    return SemIR::ConstantId::NotConstant;
  }
}

// Maps a Clang literal expression to a Carbon constant.
// TODO: Add support for all constant types for which a C++ to Carbon type

Review comment (suggestion):
Use `ImportCppType` here instead. `MapType` assumes that all the dependencies of the type have already been imported (eg, if the type is `class N::C*`, it assumes that `class N::C` and its enclosing `namespace N` have already been imported), whereas `ImportCppType` imports the dependencies first.

Code after:
  SemIR::InstId builtin_inst_id =
      LookupBuiltinName(context, loc_id, scope_id, name_id);
  if (builtin_inst_id.has_value()) {
    AddNameToScope(context, scope_id, name_id, SemIR::AccessKind::Public,
                   builtin_inst_id);
    return SemIR::ScopeLookupResult::MakeWrappedLookupResult(
        builtin_inst_id, SemIR::AccessKind::Public);
  }
  return SemIR::ScopeLookupResult::MakeNotFound();
}

// Checks if the name scope is a class that is not complete.
static auto IsIncompleteClass(Context& context, SemIR::NameScopeId scope_id)
    -> bool {
  auto class_decl = context.insts().TryGetAs<SemIR::ClassDecl>(
      context.name_scopes().Get(scope_id).inst_id());
  return class_decl.has_value() &&
         !context.types().IsComplete(
             context.classes().Get(class_decl->class_id).self_type_id);
}

// Maps a Clang literal expression to a Carbon constant.
// TODO: Add support for all constant types for which a C++ to Carbon type
// mapping exists.
static auto MapConstant(Context& context, SemIR::LocId loc_id,
                        clang::Expr* expr) -> SemIR::InstId {
  CARBON_CHECK(expr, "empty expression");

  if (auto* string_literal = dyn_cast<clang::StringLiteral>(expr)) {
    if (!string_literal->isOrdinary() && !string_literal->isUTF8()) {
      context.TODO(loc_id,
                   llvm::formatv("Unsupported: string literal type: {0}",
                                 expr->getType()));
      return SemIR::ErrorInst::InstId;
    }
    StringLiteralValueId string_id =
        context.string_literal_values().Add(string_literal->getString());
    auto inst_id =
        MakeStringLiteral(context, Parse::StringLiteralId::None, string_id);
    return inst_id;
  } else if (isa<clang::CXXNullPtrLiteralExpr>(expr)) {
    auto type_id = MapNullptrType(context, loc_id).type_id;
    return GetOrAddInst<SemIR::UninitializedValue>(context, SemIR::LocId::None,
                                                   {.type_id = type_id});
  }

  SemIR::TypeId type_id = MapType(context, loc_id, expr->getType()).type_id;
  if (!type_id.has_value()) {
    context.TODO(loc_id, llvm::formatv("Unsupported: C++ literal's type `{0}` "
                                       "could not be mapped to a Carbon type",
                                       expr->getType().getAsString()));