mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Add a `Core.CppCompat.NullptrT` type that C++'s `nullptr_t` maps into. Map `nullptr` to an uninitialized constant of that type -- `nullptr` doesn't actually have any defined bits within it, despite having the same representation as `void*`.
304 lines
8.7 KiB
C++
304 lines
8.7 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/sem_ir/expr_info.h"
|
|
|
|
#include "common/check.h"
|
|
#include "toolchain/base/kind_switch.h"
|
|
#include "toolchain/sem_ir/typed_insts.h"
|
|
|
|
namespace Carbon::SemIR {
|
|
|
|
auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory {
|
|
const File* ir = &file;
|
|
|
|
// The overall expression category if the current instruction is a value
|
|
// expression.
|
|
ExprCategory value_category = ExprCategory::Value;
|
|
|
|
while (true) {
|
|
auto untyped_inst = ir->insts().Get(inst_id);
|
|
CARBON_KIND_SWITCH(untyped_inst) {
|
|
case AdaptDecl::Kind:
|
|
case AddrPattern::Kind:
|
|
case Assign::Kind:
|
|
case BaseDecl::Kind:
|
|
case Branch::Kind:
|
|
case BranchIf::Kind:
|
|
case BranchWithArg::Kind:
|
|
case FieldDecl::Kind:
|
|
case FunctionDecl::Kind:
|
|
case ImplDecl::Kind:
|
|
case NameBindingDecl::Kind:
|
|
case Namespace::Kind:
|
|
case OutParamPattern::Kind:
|
|
case RefBindingPattern::Kind:
|
|
case RefParamPattern::Kind:
|
|
case RequireImplsDecl::Kind:
|
|
case RequirementBaseFacetType::Kind:
|
|
case RequirementEquivalent::Kind:
|
|
case RequirementImpls::Kind:
|
|
case RequirementRewrite::Kind:
|
|
case Return::Kind:
|
|
case ReturnSlotPattern::Kind:
|
|
case ReturnExpr::Kind:
|
|
case SymbolicBindingPattern::Kind:
|
|
case TuplePattern::Kind:
|
|
case ValueBindingPattern::Kind:
|
|
case ValueParamPattern::Kind:
|
|
case VarParamPattern::Kind:
|
|
case VarPattern::Kind:
|
|
return ExprCategory::NotExpr;
|
|
|
|
case ImportRefUnloaded::Kind:
|
|
case ImportRefLoaded::Kind: {
|
|
auto import_ir_inst = ir->import_ir_insts().Get(
|
|
untyped_inst.As<AnyImportRef>().import_ir_inst_id);
|
|
ir = ir->import_irs().Get(import_ir_inst.ir_id()).sem_ir;
|
|
inst_id = import_ir_inst.inst_id();
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(AsCompatible inst): {
|
|
inst_id = inst.source_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(AliasBinding inst): {
|
|
inst_id = inst.value_id;
|
|
continue;
|
|
}
|
|
case CARBON_KIND(ExportDecl inst): {
|
|
inst_id = inst.value_id;
|
|
continue;
|
|
}
|
|
case CARBON_KIND(NameRef inst): {
|
|
inst_id = inst.value_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(Converted inst): {
|
|
inst_id = inst.result_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(ImplWitnessAssociatedConstant inst): {
|
|
inst_id = inst.inst_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(SpecificConstant inst): {
|
|
inst_id = inst.inst_id;
|
|
continue;
|
|
}
|
|
|
|
case AccessMemberAction::Kind:
|
|
case AccessOptionalMemberAction::Kind:
|
|
case AddrOf::Kind:
|
|
case ArrayType::Kind:
|
|
case AssociatedConstantDecl::Kind:
|
|
case AssociatedEntity::Kind:
|
|
case AssociatedEntityType::Kind:
|
|
case AutoType::Kind:
|
|
case SymbolicBinding::Kind:
|
|
case AcquireValue::Kind:
|
|
case ValueBinding::Kind:
|
|
case BlockArg::Kind:
|
|
case BoolLiteral::Kind:
|
|
case BoolType::Kind:
|
|
case BoundMethod::Kind:
|
|
case BoundMethodType::Kind:
|
|
case CharLiteralType::Kind:
|
|
case CharLiteralValue::Kind:
|
|
case ClassDecl::Kind:
|
|
case ClassType::Kind:
|
|
case CompleteTypeWitness::Kind:
|
|
case ConstType::Kind:
|
|
case ConvertToValueAction::Kind:
|
|
case CppOverloadSetType::Kind:
|
|
case CppOverloadSetValue::Kind:
|
|
case CppVoidType::Kind:
|
|
case CustomLayoutType::Kind:
|
|
case FacetAccessType::Kind:
|
|
case FacetType::Kind:
|
|
case FacetValue::Kind:
|
|
case FloatLiteralType::Kind:
|
|
case FloatLiteralValue::Kind:
|
|
case FloatType::Kind:
|
|
case FloatValue::Kind:
|
|
case FunctionType::Kind:
|
|
case FunctionTypeWithSelfType::Kind:
|
|
case GenericClassType::Kind:
|
|
case GenericInterfaceType::Kind:
|
|
case GenericNamedConstraintType::Kind:
|
|
case LookupImplWitness::Kind:
|
|
case ImplWitness::Kind:
|
|
case ImplWitnessAccess::Kind:
|
|
case ImplWitnessAccessSubstituted::Kind:
|
|
case ImplWitnessTable::Kind:
|
|
case ImportCppDecl::Kind:
|
|
case ImportDecl::Kind:
|
|
case InstType::Kind:
|
|
case InstValue::Kind:
|
|
case IntLiteralType::Kind:
|
|
case IntType::Kind:
|
|
case IntValue::Kind:
|
|
case InterfaceDecl::Kind:
|
|
case MaybeUnformedType::Kind:
|
|
case NamedConstraintDecl::Kind:
|
|
case NamespaceType::Kind:
|
|
case PartialType::Kind:
|
|
case PatternType::Kind:
|
|
case PointerType::Kind:
|
|
case RefineTypeAction::Kind:
|
|
case RequireCompleteType::Kind:
|
|
case SpecificFunction::Kind:
|
|
case SpecificFunctionType::Kind:
|
|
case SpecificImplFunction::Kind:
|
|
case StringLiteral::Kind:
|
|
case StructType::Kind:
|
|
case StructValue::Kind:
|
|
case SymbolicBindingType::Kind:
|
|
case TupleType::Kind:
|
|
case TupleValue::Kind:
|
|
case TypeOfInst::Kind:
|
|
case TypeType::Kind:
|
|
case UnaryOperatorNot::Kind:
|
|
case UnboundElementType::Kind:
|
|
case UninitializedValue::Kind:
|
|
case ValueOfInitializer::Kind:
|
|
case ValueParam::Kind:
|
|
case VtableType::Kind:
|
|
case WhereExpr::Kind:
|
|
case WitnessType::Kind:
|
|
return value_category;
|
|
|
|
case ErrorInst::Kind:
|
|
return ExprCategory::Error;
|
|
|
|
case CARBON_KIND(ArrayIndex inst): {
|
|
inst_id = inst.array_id;
|
|
continue;
|
|
}
|
|
|
|
case VtablePtr::Kind:
|
|
case VtableDecl::Kind:
|
|
return ExprCategory::EphemeralRef;
|
|
|
|
case CARBON_KIND(ClassElementAccess inst): {
|
|
inst_id = inst.base_id;
|
|
// A value of class type is a pointer to an object representation.
|
|
// Therefore, if the base is a value, the result is an ephemeral
|
|
// reference.
|
|
value_category = ExprCategory::EphemeralRef;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(StructAccess inst): {
|
|
inst_id = inst.struct_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(TupleAccess inst): {
|
|
inst_id = inst.tuple_id;
|
|
continue;
|
|
}
|
|
|
|
case CARBON_KIND(SpliceBlock inst): {
|
|
inst_id = inst.result_id;
|
|
continue;
|
|
}
|
|
|
|
case SpliceInst::Kind:
|
|
// TODO: Add ExprCategory::Dependent.
|
|
return value_category;
|
|
|
|
case StructLiteral::Kind:
|
|
case TupleLiteral::Kind:
|
|
return ExprCategory::Mixed;
|
|
|
|
case ArrayInit::Kind:
|
|
case Call::Kind:
|
|
case InitializeFrom::Kind:
|
|
case InPlaceInit::Kind:
|
|
case ClassInit::Kind:
|
|
case StructInit::Kind:
|
|
case TupleInit::Kind:
|
|
return ExprCategory::Initializing;
|
|
|
|
case RefBinding::Kind:
|
|
case Deref::Kind:
|
|
case VarStorage::Kind:
|
|
case ReturnSlot::Kind:
|
|
return ExprCategory::DurableRef;
|
|
|
|
case Temporary::Kind:
|
|
case TemporaryStorage::Kind:
|
|
case ValueAsRef::Kind:
|
|
return ExprCategory::EphemeralRef;
|
|
|
|
case OutParam::Kind:
|
|
case RefParam::Kind:
|
|
// TODO: Consider introducing a separate category for OutParam:
|
|
// unlike other DurableRefs, it permits initialization.
|
|
return ExprCategory::DurableRef;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto FindReturnSlotArgForInitializer(const File& sem_ir, InstId init_id)
|
|
-> InstId {
|
|
while (true) {
|
|
Inst init_untyped = sem_ir.insts().Get(init_id);
|
|
CARBON_KIND_SWITCH(init_untyped) {
|
|
case CARBON_KIND(AsCompatible init): {
|
|
init_id = init.source_id;
|
|
continue;
|
|
}
|
|
case CARBON_KIND(Converted init): {
|
|
init_id = init.result_id;
|
|
continue;
|
|
}
|
|
case CARBON_KIND(ArrayInit init): {
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(ClassInit init): {
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(StructInit init): {
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(TupleInit init): {
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(InitializeFrom init): {
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(InPlaceInit init): {
|
|
if (!ReturnTypeInfo::ForType(sem_ir, init.type_id).has_return_slot()) {
|
|
return InstId::None;
|
|
}
|
|
return init.dest_id;
|
|
}
|
|
case CARBON_KIND(Call call): {
|
|
if (!ReturnTypeInfo::ForType(sem_ir, call.type_id).has_return_slot()) {
|
|
return InstId::None;
|
|
}
|
|
if (!call.args_id.has_value()) {
|
|
// Argument initialization failed, so we have no return slot.
|
|
return InstId::None;
|
|
}
|
|
return sem_ir.inst_blocks().Get(call.args_id).back();
|
|
}
|
|
case CARBON_KIND(ErrorInst _): {
|
|
return InstId::None;
|
|
}
|
|
default:
|
|
CARBON_FATAL("Initialization from unexpected inst {0}", init_untyped);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Carbon::SemIR
|