Просмотр исходного кода

Move the mapping from entity name to an imported C++ global variable declaration outside of `EntityName` (#6211)

This would save space for every `EntityName` that is not an imported C++
global variable.
C++ global variables include static data members.
Created `CppGlobalVarId`, `CppGlobalVarKey` and `CppGlobalVar` to allow
having `CanonicalValueStore` that maps `EntityNameId` (which is in
`CppGlobalVarKey` and `CppGlobalVar`) to `ClangDeclId` (which is also in
`CppGlobalVar`).
This is similar to `ClangDeclId`, `ClangDeclKey` and `ClangDecl` .
Boaz Brickner 6 месяцев назад
Родитель
Сommit
ffefa7711c

+ 3 - 0
toolchain/check/context.h

@@ -255,6 +255,9 @@ class Context {
   auto entity_names() -> SemIR::EntityNameStore& {
     return sem_ir().entity_names();
   }
+  auto cpp_global_names() -> SemIR::CppGlobalVarStore& {
+    return sem_ir().cpp_global_vars();
+  }
   auto cpp_overload_sets() -> SemIR::CppOverloadSetStore& {
     return sem_ir().cpp_overload_sets();
   }

+ 3 - 1
toolchain/check/cpp/import.cpp

@@ -1853,7 +1853,9 @@ static auto ImportVarDecl(Context& context, SemIR::LocId loc_id,
   SemIR::EntityNameId entity_name_id =
       context.entity_names().AddSymbolicBindingName(
           var_name_id, GetParentNameScopeId(context, var_decl),
-          SemIR::CompileTimeBindIndex::None, false, clang_decl_id);
+          SemIR::CompileTimeBindIndex::None, false);
+  context.cpp_global_names().Add({.key = {.entity_name_id = entity_name_id},
+                                  .clang_decl_id = clang_decl_id});
 
   // Create `BindingPattern` and `VarPattern` in a `NameBindingDecl`.
   context.pattern_block_stack().Push();

+ 1 - 0
toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon

@@ -22,6 +22,7 @@
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:   entity_names:    {}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:       {}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}

+ 170 - 113
toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon

@@ -14,12 +14,14 @@
 // --- header.h
 
 struct X {
-  X *p;
+  X* _Nonnull p;
 };
 
 void f(X x = {}) {
 }
 
+X* _Nonnull global;
+
 // --- import.carbon
 
 import Cpp library "header.h";
@@ -27,6 +29,7 @@ import Cpp library "header.h";
 fn G(x: Cpp.X) {
   Cpp.f();
   Cpp.f(x);
+  Cpp.f(*Cpp.global);
 }
 
 // CHECK:STDOUT: ---
@@ -42,30 +45,39 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:   clang_decls:
 // CHECK:STDOUT:     clang_decl_id0:  {key: "<translation unit>", inst_id: inst60000010}
 // CHECK:STDOUT:     clang_decl_id1:  {key: "struct X {}", inst_id: inst60000012}
-// CHECK:STDOUT:     clang_decl_id2:  {key: {decl: "void f(X x = {})", num_params: 0}, inst_id: inst60000029}
-// CHECK:STDOUT:     clang_decl_id3:  {key: {decl: "extern void f__carbon_thunk()", num_params: 0}, inst_id: inst6000002C}
-// CHECK:STDOUT:     clang_decl_id4:  {key: {decl: "void f(X x = {})", num_params: 1}, inst_id: inst60000037}
-// CHECK:STDOUT:     clang_decl_id5:  {key: {decl: "extern void f__carbon_thunk(X * _Nonnull x)", num_params: 1}, inst_id: inst60000040}
+// CHECK:STDOUT:     clang_decl_id2:  {key: "X * _Nonnull p", inst_id: inst60000021}
+// CHECK:STDOUT:     clang_decl_id3:  {key: {decl: "void f(X x = {})", num_params: 0}, inst_id: inst6000002C}
+// CHECK:STDOUT:     clang_decl_id4:  {key: {decl: "extern void f__carbon_thunk()", num_params: 0}, inst_id: inst6000002F}
+// CHECK:STDOUT:     clang_decl_id5:  {key: {decl: "void f(X x = {})", num_params: 1}, inst_id: inst6000003A}
+// CHECK:STDOUT:     clang_decl_id6:  {key: {decl: "extern void f__carbon_thunk(X * _Nonnull x)", num_params: 1}, inst_id: inst60000042}
+// CHECK:STDOUT:     clang_decl_id7:  {key: "X * _Nonnull global", inst_id: inst6000004B}
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst60000010, name1: inst6000001B}}
-// CHECK:STDOUT:     name_scope1:     {inst: inst60000010, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name3: inst60000012, name4: inst60000026}}
+// CHECK:STDOUT:     name_scope1:     {inst: inst60000010, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name3: inst60000012, name4: inst60000029, name5: inst6000004B}}
 // CHECK:STDOUT:     name_scope2:     {inst: inst60000012, parent_scope: name_scope1, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name0:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name1:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name2:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
+// CHECK:STDOUT:     entity_name0:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name1:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name2:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name3:    {name: name5, parent_scope: name_scope1, index: -1, is_template: 0}
+// CHECK:STDOUT:   cpp_global_vars:
+// CHECK:STDOUT:     cpp_global_var0: {key: {entity_name_id: entity_name3}, clang_decl_id: clang_decl_id7}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function60000000: {name: name1, parent_scope: name_scope0, call_params_id: inst_block6, body: [inst_block9]}
 // CHECK:STDOUT:     function60000001: {name: name4, parent_scope: name_scope1, call_params_id: inst_block_empty}
-// CHECK:STDOUT:     function60000002: {name: name6, parent_scope: name_scope1, call_params_id: inst_block_empty}
+// CHECK:STDOUT:     function60000002: {name: name7, parent_scope: name_scope1, call_params_id: inst_block_empty}
 // CHECK:STDOUT:     function60000003: {name: name4, parent_scope: name_scope1, call_params_id: inst_block13}
-// CHECK:STDOUT:     function60000004: {name: name6, parent_scope: name_scope1, call_params_id: inst_block18}
+// CHECK:STDOUT:     function60000004: {name: name7, parent_scope: name_scope1, call_params_id: inst_block18}
 // CHECK:STDOUT:   classes:
-// CHECK:STDOUT:     class60000000:   {name: name3, parent_scope: name_scope1, self_type_id: type(inst60000013), inheritance_kind: Base, is_dynamic: 0, scope_id: name_scope2, body_block_id: inst_block10, adapt_id: inst<none>, base_id: inst<none>, complete_type_witness_id: inst60000021, vtable_decl_id: inst<none>}}
+// CHECK:STDOUT:     class60000000:   {name: name3, parent_scope: name_scope1, self_type_id: type(inst60000013), inheritance_kind: Base, is_dynamic: 0, scope_id: name_scope2, body_block_id: inst_block10, adapt_id: inst<none>, base_id: inst<none>, complete_type_witness_id: inst60000024, vtable_decl_id: inst<none>}}
 // CHECK:STDOUT:   generics:        {}
 // CHECK:STDOUT:   specifics:       {}
 // CHECK:STDOUT:   struct_type_fields:
 // CHECK:STDOUT:     struct_type_fields0: {}
+// CHECK:STDOUT:     struct_type_fields1:
+// CHECK:STDOUT:       0:               {name_id: name6, type_inst_id: inst6000001F}
+// CHECK:STDOUT:     struct_type_fields2:
+// CHECK:STDOUT:       0:               {name_id: name6, type_inst_id: inst6000001F}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     'type(TypeType)':
 // CHECK:STDOUT:       value_repr:      {kind: copy, type: type(TypeType)}
@@ -79,24 +91,24 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
 // CHECK:STDOUT:     'type(inst(WitnessType))':
 // CHECK:STDOUT:       value_repr:      {kind: copy, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     'type(inst60000020)':
-// CHECK:STDOUT:       value_repr:      {kind: pointer, type: type(inst60000023)}
+// CHECK:STDOUT:     'type(inst6000001F)':
+// CHECK:STDOUT:       value_repr:      {kind: copy, type: type(inst6000001F)}
 // CHECK:STDOUT:     'type(inst60000023)':
-// CHECK:STDOUT:       value_repr:      {kind: copy, type: type(inst60000023)}
+// CHECK:STDOUT:       value_repr:      {kind: pointer, type: type(inst60000026)}
+// CHECK:STDOUT:     'type(inst60000026)':
+// CHECK:STDOUT:       value_repr:      {kind: copy, type: type(inst60000026)}
 // CHECK:STDOUT:     'type(inst60000013)':
-// CHECK:STDOUT:       value_repr:      {kind: pointer, type: type(inst60000023)}
-// CHECK:STDOUT:     'type(inst60000025)':
-// CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
-// CHECK:STDOUT:     'type(inst6000002A)':
+// CHECK:STDOUT:       value_repr:      {kind: pointer, type: type(inst60000026)}
+// CHECK:STDOUT:     'type(inst60000028)':
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
 // CHECK:STDOUT:     'type(inst6000002D)':
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
-// CHECK:STDOUT:     'type(inst60000038)':
+// CHECK:STDOUT:     'type(inst60000030)':
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
-// CHECK:STDOUT:     'type(inst60000041)':
+// CHECK:STDOUT:     'type(inst6000003B)':
+// CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
+// CHECK:STDOUT:     'type(inst60000043)':
 // CHECK:STDOUT:       value_repr:      {kind: none, type: type(inst6000001D)}
-// CHECK:STDOUT:     'type(inst6000003A)':
-// CHECK:STDOUT:       value_repr:      {kind: copy, type: type(inst6000003A)}
 // CHECK:STDOUT:   insts:
 // CHECK:STDOUT:     'inst(TypeType)':  {kind: TypeType, type: type(TypeType)}
 // CHECK:STDOUT:     'inst(AutoType)':  {kind: AutoType, type: type(TypeType)}
@@ -129,46 +141,62 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst6000001C:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001D:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001E:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000001C)}
-// CHECK:STDOUT:     inst6000001F:    {kind: CustomLayoutType, arg0: struct_type_fields0, arg1: custom_layout1, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000020:    {kind: CustomLayoutType, arg0: struct_type_fields0, arg1: custom_layout1, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000021:    {kind: CompleteTypeWitness, arg0: inst6000001F, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst60000022:    {kind: CompleteTypeWitness, arg0: inst60000020, type: type(inst(WitnessType))}
-// CHECK:STDOUT:     inst60000023:    {kind: PointerType, arg0: inst60000020, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000024:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst60000025:    {kind: CppOverloadSetType, arg0: cpp_overload_set60000000, arg1: specific<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000026:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000025)}
-// CHECK:STDOUT:     inst60000027:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000025)}
-// CHECK:STDOUT:     inst60000028:    {kind: NameRef, arg0: name4, arg1: inst60000026, type: type(inst60000025)}
-// CHECK:STDOUT:     inst60000029:    {kind: FunctionDecl, arg0: function60000001, arg1: inst_block_empty, type: type(inst6000002A)}
-// CHECK:STDOUT:     inst6000002A:    {kind: FunctionType, arg0: function60000001, arg1: specific<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst6000002B:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000002A)}
-// CHECK:STDOUT:     inst6000002C:    {kind: FunctionDecl, arg0: function60000002, arg1: inst_block_empty, type: type(inst6000002D)}
-// CHECK:STDOUT:     inst6000002D:    {kind: FunctionType, arg0: function60000002, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000001F:    {kind: PointerType, arg0: inst60000013, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000020:    {kind: UnboundElementType, arg0: inst60000013, arg1: inst6000001F, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000021:    {kind: FieldDecl, arg0: name6, arg1: element0, type: type(inst60000020)}
+// CHECK:STDOUT:     inst60000022:    {kind: CustomLayoutType, arg0: struct_type_fields1, arg1: custom_layout1, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000023:    {kind: CustomLayoutType, arg0: struct_type_fields2, arg1: custom_layout1, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000024:    {kind: CompleteTypeWitness, arg0: inst60000022, type: type(inst(WitnessType))}
+// CHECK:STDOUT:     inst60000025:    {kind: CompleteTypeWitness, arg0: inst60000023, type: type(inst(WitnessType))}
+// CHECK:STDOUT:     inst60000026:    {kind: PointerType, arg0: inst60000023, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000027:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000028:    {kind: CppOverloadSetType, arg0: cpp_overload_set60000000, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000029:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000002A:    {kind: CppOverloadSetValue, arg0: cpp_overload_set60000000, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000002B:    {kind: NameRef, arg0: name4, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000002C:    {kind: FunctionDecl, arg0: function60000001, arg1: inst_block_empty, type: type(inst6000002D)}
+// CHECK:STDOUT:     inst6000002D:    {kind: FunctionType, arg0: function60000001, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000002E:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000002D)}
-// CHECK:STDOUT:     inst6000002F:    {kind: Call, arg0: inst6000002C, arg1: inst_block_empty, type: type(inst6000001D)}
-// CHECK:STDOUT:     inst60000030:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst60000031:    {kind: NameRef, arg0: name4, arg1: inst60000026, type: type(inst60000025)}
-// CHECK:STDOUT:     inst60000032:    {kind: NameRef, arg0: name2, arg1: inst60000015, type: type(inst60000013)}
-// CHECK:STDOUT:     inst60000033:    {kind: BindName, arg0: entity_name1, arg1: inst60000036, type: type(inst60000013)}
-// CHECK:STDOUT:     inst60000034:    {kind: BindingPattern, arg0: entity_name1, type: type(inst60000016)}
-// CHECK:STDOUT:     inst60000035:    {kind: ValueParamPattern, arg0: inst60000034, arg1: call_param0, type: type(inst60000016)}
-// CHECK:STDOUT:     inst60000036:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst60000013)}
-// CHECK:STDOUT:     inst60000037:    {kind: FunctionDecl, arg0: function60000003, arg1: inst_block15, type: type(inst60000038)}
-// CHECK:STDOUT:     inst60000038:    {kind: FunctionType, arg0: function60000003, arg1: specific<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000039:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000038)}
-// CHECK:STDOUT:     inst6000003A:    {kind: PointerType, arg0: inst60000013, type: type(TypeType)}
-// CHECK:STDOUT:     inst6000003B:    {kind: BindName, arg0: entity_name2, arg1: inst6000003F, type: type(inst6000003A)}
-// CHECK:STDOUT:     inst6000003C:    {kind: PatternType, arg0: inst6000003A, type: type(TypeType)}
-// CHECK:STDOUT:     inst6000003D:    {kind: BindingPattern, arg0: entity_name2, type: type(inst6000003C)}
-// CHECK:STDOUT:     inst6000003E:    {kind: ValueParamPattern, arg0: inst6000003D, arg1: call_param0, type: type(inst6000003C)}
-// CHECK:STDOUT:     inst6000003F:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst6000003A)}
-// CHECK:STDOUT:     inst60000040:    {kind: FunctionDecl, arg0: function60000004, arg1: inst_block20, type: type(inst60000041)}
-// CHECK:STDOUT:     inst60000041:    {kind: FunctionType, arg0: function60000004, arg1: specific<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000042:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000041)}
-// CHECK:STDOUT:     inst60000043:    {kind: ValueAsRef, arg0: inst60000032, type: type(inst60000013)}
-// CHECK:STDOUT:     inst60000044:    {kind: AddrOf, arg0: inst60000043, type: type(inst6000003A)}
-// CHECK:STDOUT:     inst60000045:    {kind: Call, arg0: inst60000040, arg1: inst_block22, type: type(inst6000001D)}
-// CHECK:STDOUT:     inst60000046:    {kind: Return}
+// CHECK:STDOUT:     inst6000002F:    {kind: FunctionDecl, arg0: function60000002, arg1: inst_block_empty, type: type(inst60000030)}
+// CHECK:STDOUT:     inst60000030:    {kind: FunctionType, arg0: function60000002, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000031:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000030)}
+// CHECK:STDOUT:     inst60000032:    {kind: Call, arg0: inst6000002F, arg1: inst_block_empty, type: type(inst6000001D)}
+// CHECK:STDOUT:     inst60000033:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000034:    {kind: NameRef, arg0: name4, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst60000035:    {kind: NameRef, arg0: name2, arg1: inst60000015, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000036:    {kind: BindName, arg0: entity_name1, arg1: inst60000039, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000037:    {kind: BindingPattern, arg0: entity_name1, type: type(inst60000016)}
+// CHECK:STDOUT:     inst60000038:    {kind: ValueParamPattern, arg0: inst60000037, arg1: call_param0, type: type(inst60000016)}
+// CHECK:STDOUT:     inst60000039:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst60000013)}
+// CHECK:STDOUT:     inst6000003A:    {kind: FunctionDecl, arg0: function60000003, arg1: inst_block15, type: type(inst6000003B)}
+// CHECK:STDOUT:     inst6000003B:    {kind: FunctionType, arg0: function60000003, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000003C:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000003B)}
+// CHECK:STDOUT:     inst6000003D:    {kind: BindName, arg0: entity_name2, arg1: inst60000041, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst6000003E:    {kind: PatternType, arg0: inst6000001F, type: type(TypeType)}
+// CHECK:STDOUT:     inst6000003F:    {kind: BindingPattern, arg0: entity_name2, type: type(inst6000003E)}
+// CHECK:STDOUT:     inst60000040:    {kind: ValueParamPattern, arg0: inst6000003F, arg1: call_param0, type: type(inst6000003E)}
+// CHECK:STDOUT:     inst60000041:    {kind: ValueParam, arg0: call_param0, arg1: name2, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000042:    {kind: FunctionDecl, arg0: function60000004, arg1: inst_block20, type: type(inst60000043)}
+// CHECK:STDOUT:     inst60000043:    {kind: FunctionType, arg0: function60000004, arg1: specific<none>, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000044:    {kind: StructValue, arg0: inst_block_empty, type: type(inst60000043)}
+// CHECK:STDOUT:     inst60000045:    {kind: ValueAsRef, arg0: inst60000035, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000046:    {kind: AddrOf, arg0: inst60000045, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000047:    {kind: Call, arg0: inst60000042, arg1: inst_block22, type: type(inst6000001D)}
+// CHECK:STDOUT:     inst60000048:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000049:    {kind: NameRef, arg0: name4, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000004A:    {kind: NameRef, arg0: name0, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst6000004B:    {kind: VarStorage, arg0: inst6000004D, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst6000004C:    {kind: BindingPattern, arg0: entity_name3, type: type(inst6000003E)}
+// CHECK:STDOUT:     inst6000004D:    {kind: VarPattern, arg0: inst6000004C, type: type(inst6000003E)}
+// CHECK:STDOUT:     inst6000004E:    {kind: NameBindingDecl, arg0: inst_block23}
+// CHECK:STDOUT:     inst6000004F:    {kind: NameRef, arg0: name5, arg1: inst6000004B, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000050:    {kind: BindValue, arg0: inst6000004F, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000051:    {kind: Deref, arg0: inst60000050, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000052:    {kind: BindValue, arg0: inst60000051, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000053:    {kind: ValueAsRef, arg0: inst60000052, type: type(inst60000013)}
+// CHECK:STDOUT:     inst60000054:    {kind: AddrOf, arg0: inst60000053, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000055:    {kind: Call, arg0: inst60000042, arg1: inst_block25, type: type(inst6000001D)}
+// CHECK:STDOUT:     inst60000056:    {kind: Return}
 // CHECK:STDOUT:   constant_values:
 // CHECK:STDOUT:     values:
 // CHECK:STDOUT:       'inst(TypeType)':  concrete_constant(inst(TypeType))
@@ -199,36 +227,45 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:       inst6000001C:    concrete_constant(inst6000001C)
 // CHECK:STDOUT:       inst6000001D:    concrete_constant(inst6000001D)
 // CHECK:STDOUT:       inst6000001E:    concrete_constant(inst6000001E)
-// CHECK:STDOUT:       inst6000001F:    concrete_constant(inst60000020)
+// CHECK:STDOUT:       inst6000001F:    concrete_constant(inst6000001F)
 // CHECK:STDOUT:       inst60000020:    concrete_constant(inst60000020)
-// CHECK:STDOUT:       inst60000021:    concrete_constant(inst60000022)
-// CHECK:STDOUT:       inst60000022:    concrete_constant(inst60000022)
+// CHECK:STDOUT:       inst60000021:    concrete_constant(inst60000021)
+// CHECK:STDOUT:       inst60000022:    concrete_constant(inst60000023)
 // CHECK:STDOUT:       inst60000023:    concrete_constant(inst60000023)
-// CHECK:STDOUT:       inst60000024:    concrete_constant(inst60000010)
+// CHECK:STDOUT:       inst60000024:    concrete_constant(inst60000025)
 // CHECK:STDOUT:       inst60000025:    concrete_constant(inst60000025)
-// CHECK:STDOUT:       inst60000026:    concrete_constant(inst60000027)
-// CHECK:STDOUT:       inst60000027:    concrete_constant(inst60000027)
-// CHECK:STDOUT:       inst60000028:    concrete_constant(inst60000027)
-// CHECK:STDOUT:       inst60000029:    concrete_constant(inst6000002B)
+// CHECK:STDOUT:       inst60000026:    concrete_constant(inst60000026)
+// CHECK:STDOUT:       inst60000027:    concrete_constant(inst60000010)
+// CHECK:STDOUT:       inst60000028:    concrete_constant(inst60000028)
+// CHECK:STDOUT:       inst60000029:    concrete_constant(inst6000002A)
 // CHECK:STDOUT:       inst6000002A:    concrete_constant(inst6000002A)
-// CHECK:STDOUT:       inst6000002B:    concrete_constant(inst6000002B)
+// CHECK:STDOUT:       inst6000002B:    concrete_constant(inst6000002A)
 // CHECK:STDOUT:       inst6000002C:    concrete_constant(inst6000002E)
 // CHECK:STDOUT:       inst6000002D:    concrete_constant(inst6000002D)
 // CHECK:STDOUT:       inst6000002E:    concrete_constant(inst6000002E)
-// CHECK:STDOUT:       inst60000030:    concrete_constant(inst60000010)
-// CHECK:STDOUT:       inst60000031:    concrete_constant(inst60000027)
-// CHECK:STDOUT:       inst60000034:    concrete_constant(inst60000034)
-// CHECK:STDOUT:       inst60000035:    concrete_constant(inst60000035)
-// CHECK:STDOUT:       inst60000037:    concrete_constant(inst60000039)
+// CHECK:STDOUT:       inst6000002F:    concrete_constant(inst60000031)
+// CHECK:STDOUT:       inst60000030:    concrete_constant(inst60000030)
+// CHECK:STDOUT:       inst60000031:    concrete_constant(inst60000031)
+// CHECK:STDOUT:       inst60000033:    concrete_constant(inst60000010)
+// CHECK:STDOUT:       inst60000034:    concrete_constant(inst6000002A)
+// CHECK:STDOUT:       inst60000037:    concrete_constant(inst60000037)
 // CHECK:STDOUT:       inst60000038:    concrete_constant(inst60000038)
-// CHECK:STDOUT:       inst60000039:    concrete_constant(inst60000039)
-// CHECK:STDOUT:       inst6000003A:    concrete_constant(inst6000003A)
+// CHECK:STDOUT:       inst6000003A:    concrete_constant(inst6000003C)
+// CHECK:STDOUT:       inst6000003B:    concrete_constant(inst6000003B)
 // CHECK:STDOUT:       inst6000003C:    concrete_constant(inst6000003C)
-// CHECK:STDOUT:       inst6000003D:    concrete_constant(inst6000003D)
 // CHECK:STDOUT:       inst6000003E:    concrete_constant(inst6000003E)
-// CHECK:STDOUT:       inst60000040:    concrete_constant(inst60000042)
-// CHECK:STDOUT:       inst60000041:    concrete_constant(inst60000041)
-// CHECK:STDOUT:       inst60000042:    concrete_constant(inst60000042)
+// CHECK:STDOUT:       inst6000003F:    concrete_constant(inst6000003F)
+// CHECK:STDOUT:       inst60000040:    concrete_constant(inst60000040)
+// CHECK:STDOUT:       inst60000042:    concrete_constant(inst60000044)
+// CHECK:STDOUT:       inst60000043:    concrete_constant(inst60000043)
+// CHECK:STDOUT:       inst60000044:    concrete_constant(inst60000044)
+// CHECK:STDOUT:       inst60000048:    concrete_constant(inst60000010)
+// CHECK:STDOUT:       inst60000049:    concrete_constant(inst6000002A)
+// CHECK:STDOUT:       inst6000004A:    concrete_constant(inst60000010)
+// CHECK:STDOUT:       inst6000004B:    concrete_constant(inst6000004B)
+// CHECK:STDOUT:       inst6000004C:    concrete_constant(inst6000004C)
+// CHECK:STDOUT:       inst6000004D:    concrete_constant(inst6000004D)
+// CHECK:STDOUT:       inst6000004F:    concrete_constant(inst6000004B)
 // CHECK:STDOUT:     symbolic_constants: {}
 // CHECK:STDOUT:   inst_blocks:
 // CHECK:STDOUT:     inst_block_empty: {}
@@ -237,11 +274,13 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     imports:
 // CHECK:STDOUT:       0:               inst60000010
 // CHECK:STDOUT:       1:               inst60000012
-// CHECK:STDOUT:       2:               inst60000026
-// CHECK:STDOUT:       3:               inst60000029
-// CHECK:STDOUT:       4:               inst6000002C
-// CHECK:STDOUT:       5:               inst60000037
-// CHECK:STDOUT:       6:               inst60000040
+// CHECK:STDOUT:       2:               inst60000029
+// CHECK:STDOUT:       3:               inst6000002C
+// CHECK:STDOUT:       4:               inst6000002F
+// CHECK:STDOUT:       5:               inst6000003A
+// CHECK:STDOUT:       6:               inst60000042
+// CHECK:STDOUT:       7:               inst6000004E
+// CHECK:STDOUT:       8:               inst6000004B
 // CHECK:STDOUT:     global_init:     {}
 // CHECK:STDOUT:     inst_block4:
 // CHECK:STDOUT:       0:               inst60000011
@@ -258,46 +297,64 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:       1:               inst6000001A
 // CHECK:STDOUT:       2:               inst60000015
 // CHECK:STDOUT:     inst_block9:
-// CHECK:STDOUT:       0:               inst60000024
-// CHECK:STDOUT:       1:               inst60000028
-// CHECK:STDOUT:       2:               inst6000002F
-// CHECK:STDOUT:       3:               inst60000030
-// CHECK:STDOUT:       4:               inst60000031
-// CHECK:STDOUT:       5:               inst60000032
-// CHECK:STDOUT:       6:               inst60000043
-// CHECK:STDOUT:       7:               inst60000044
-// CHECK:STDOUT:       8:               inst60000045
-// CHECK:STDOUT:       9:               inst60000046
+// CHECK:STDOUT:       0:               inst60000027
+// CHECK:STDOUT:       1:               inst6000002B
+// CHECK:STDOUT:       2:               inst60000032
+// CHECK:STDOUT:       3:               inst60000033
+// CHECK:STDOUT:       4:               inst60000034
+// CHECK:STDOUT:       5:               inst60000035
+// CHECK:STDOUT:       6:               inst60000045
+// CHECK:STDOUT:       7:               inst60000046
+// CHECK:STDOUT:       8:               inst60000047
+// CHECK:STDOUT:       9:               inst60000048
+// CHECK:STDOUT:       10:              inst60000049
+// CHECK:STDOUT:       11:              inst6000004A
+// CHECK:STDOUT:       12:              inst6000004F
+// CHECK:STDOUT:       13:              inst60000050
+// CHECK:STDOUT:       14:              inst60000051
+// CHECK:STDOUT:       15:              inst60000052
+// CHECK:STDOUT:       16:              inst60000053
+// CHECK:STDOUT:       17:              inst60000054
+// CHECK:STDOUT:       18:              inst60000055
+// CHECK:STDOUT:       19:              inst60000056
 // CHECK:STDOUT:     inst_block10:
-// CHECK:STDOUT:       0:               inst6000001F
-// CHECK:STDOUT:       1:               inst60000021
+// CHECK:STDOUT:       0:               inst60000021
+// CHECK:STDOUT:       1:               inst60000022
+// CHECK:STDOUT:       2:               inst60000024
 // CHECK:STDOUT:     inst_block11:    {}
 // CHECK:STDOUT:     inst_block12:
-// CHECK:STDOUT:       0:               inst60000035
+// CHECK:STDOUT:       0:               inst60000038
 // CHECK:STDOUT:     inst_block13:
-// CHECK:STDOUT:       0:               inst60000036
+// CHECK:STDOUT:       0:               inst60000039
 // CHECK:STDOUT:     inst_block14:
-// CHECK:STDOUT:       0:               inst60000034
-// CHECK:STDOUT:       1:               inst60000035
+// CHECK:STDOUT:       0:               inst60000037
+// CHECK:STDOUT:       1:               inst60000038
 // CHECK:STDOUT:     inst_block15:
-// CHECK:STDOUT:       0:               inst60000036
-// CHECK:STDOUT:       1:               inst60000033
+// CHECK:STDOUT:       0:               inst60000039
+// CHECK:STDOUT:       1:               inst60000036
 // CHECK:STDOUT:     inst_block16:    {}
 // CHECK:STDOUT:     inst_block17:
-// CHECK:STDOUT:       0:               inst6000003E
+// CHECK:STDOUT:       0:               inst60000040
 // CHECK:STDOUT:     inst_block18:
-// CHECK:STDOUT:       0:               inst6000003F
+// CHECK:STDOUT:       0:               inst60000041
 // CHECK:STDOUT:     inst_block19:
-// CHECK:STDOUT:       0:               inst6000003D
-// CHECK:STDOUT:       1:               inst6000003E
-// CHECK:STDOUT:     inst_block20:
 // CHECK:STDOUT:       0:               inst6000003F
-// CHECK:STDOUT:       1:               inst6000003B
+// CHECK:STDOUT:       1:               inst60000040
+// CHECK:STDOUT:     inst_block20:
+// CHECK:STDOUT:       0:               inst60000041
+// CHECK:STDOUT:       1:               inst6000003D
 // CHECK:STDOUT:     inst_block21:
-// CHECK:STDOUT:       0:               inst60000032
+// CHECK:STDOUT:       0:               inst60000035
 // CHECK:STDOUT:     inst_block22:
-// CHECK:STDOUT:       0:               inst60000044
+// CHECK:STDOUT:       0:               inst60000046
 // CHECK:STDOUT:     inst_block23:
+// CHECK:STDOUT:       0:               inst6000004C
+// CHECK:STDOUT:       1:               inst6000004D
+// CHECK:STDOUT:     inst_block24:
+// CHECK:STDOUT:       0:               inst60000052
+// CHECK:STDOUT:     inst_block25:
+// CHECK:STDOUT:       0:               inst60000054
+// CHECK:STDOUT:     inst_block26:
 // CHECK:STDOUT:       0:               inst0000000E
 // CHECK:STDOUT:       1:               inst6000000F
 // CHECK:STDOUT:       2:               inst6000001B

+ 3 - 1
toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon

@@ -38,6 +38,7 @@ fn B() {
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst6000000F}}
 // CHECK:STDOUT:   entity_names:    {}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:   classes:         {}
@@ -99,7 +100,8 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name1: inst50000010, name0: inst50000011}}
 // CHECK:STDOUT:     name_scope1:     {inst: inst50000010, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name1: inst50000016}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
+// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function50000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:     function50000001: {name: name1, parent_scope: name_scope1}

+ 3 - 1
toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon

@@ -38,6 +38,7 @@ fn B() {
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst6000000F}}
 // CHECK:STDOUT:   entity_names:    {}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:   classes:         {}
@@ -118,7 +119,8 @@ fn B() {
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name1: inst50000010, name0: inst50000011}}
 // CHECK:STDOUT:     name_scope1:     {inst: inst50000010, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name1: inst50000016}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
+// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope1, index: -1, is_template: 0}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function50000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block_empty, body: [inst_block5]}
 // CHECK:STDOUT:     function50000001: {name: name1, parent_scope: name_scope1}

+ 63 - 62
toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon

@@ -232,68 +232,69 @@ fn Foo[T:! type](p: T*) -> (T*, ()) {
 // CHECK:STDOUT:     name_scope11:    {inst: inst600000BD, parent_scope: name_scope1, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:     name_scope12:    {inst: inst600000F5, parent_scope: name_scope1, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name0:    {name: name(PeriodSelf), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name1:    {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name2:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name3:    {name: name3, parent_scope: name_scope1, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name4:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name5:    {name: name4, parent_scope: name_scope2, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name6:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name7:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name8:    {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name9:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name10:   {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name11:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name12:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name13:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name14:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name15:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name16:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name17:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name18:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name19:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name20:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name21:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name22:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name23:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name24:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name25:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name26:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name27:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name28:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name29:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name30:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name31:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name32:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name33:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name34:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name35:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name36:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name37:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name38:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name39:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name40:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name41:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name42:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name43:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name44:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name45:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name46:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name47:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name48:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name49:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name50:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name51:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name52:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name53:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name54:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name55:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name56:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name57:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name58:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name59:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name60:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
-// CHECK:STDOUT:     entity_name61:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0, clang_decl_id: clang_decl_id<none>}
+// CHECK:STDOUT:     entity_name0:    {name: name(PeriodSelf), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name1:    {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name2:    {name: name2, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name3:    {name: name3, parent_scope: name_scope1, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name4:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name5:    {name: name4, parent_scope: name_scope2, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name6:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name7:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name8:    {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name9:    {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name10:   {name: name(SelfType), parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name11:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name12:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name13:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name14:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name15:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name16:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name17:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name18:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name19:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name20:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name21:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name22:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name23:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name24:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name25:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name26:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name27:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name28:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name29:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name30:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name31:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name32:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name33:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name34:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name35:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name36:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name37:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name38:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name39:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name40:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name41:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name42:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name43:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name44:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name45:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name46:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name47:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name48:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name49:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name50:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name51:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name52:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name53:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name54:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name55:   {name: name(SelfValue), parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name56:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name57:   {name: name1, parent_scope: name_scope<none>, index: 0, is_template: 0}
+// CHECK:STDOUT:     entity_name58:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name59:   {name: name5, parent_scope: name_scope<none>, index: 1, is_template: 0}
+// CHECK:STDOUT:     entity_name60:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:     entity_name61:   {name: name6, parent_scope: name_scope<none>, index: 2, is_template: 0}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block13, return_slot_pattern: inst60000030, body: [inst_block20]}
 // CHECK:STDOUT:     function60000001: {name: name4, parent_scope: name_scope2, return_slot_pattern: inst60000055}

+ 2 - 1
toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon

@@ -28,7 +28,8 @@ fn Foo(n: ()) -> ((), ()) {
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name0: inst60000025}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope<none>, index: -1, is_template: 0, clang_decl_id: clang_decl_id<none>}
+// CHECK:STDOUT:     entity_name0:    {name: name1, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:
 // CHECK:STDOUT:     function60000000: {name: name0, parent_scope: name_scope0, call_params_id: inst_block9, return_slot_pattern: inst60000020, body: [inst_block12]}
 // CHECK:STDOUT:   classes:         {}

+ 1 - 0
toolchain/driver/testdata/stdin.carbon

@@ -34,6 +34,7 @@
 // CHECK:STDOUT:   name_scopes:
 // CHECK:STDOUT:     name_scope0:     {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:   entity_names:    {}
+// CHECK:STDOUT:   cpp_global_vars: {}
 // CHECK:STDOUT:   functions:       {}
 // CHECK:STDOUT:   classes:         {}
 // CHECK:STDOUT:   generics:        {}

+ 1 - 0
toolchain/lower/BUILD

@@ -61,6 +61,7 @@ cc_library(
         "//toolchain/base:kind_switch",
         "//toolchain/parse:tree",
         "//toolchain/sem_ir:absolute_node_id",
+        "//toolchain/sem_ir:clang_decl",
         "//toolchain/sem_ir:diagnostic_loc_converter",
         "//toolchain/sem_ir:entry_point",
         "//toolchain/sem_ir:expr_info",

+ 10 - 3
toolchain/lower/mangler.cpp

@@ -9,6 +9,7 @@
 #include "common/raw_string_ostream.h"
 #include "toolchain/base/kind_switch.h"
 #include "toolchain/lower/clang_global_decl.h"
+#include "toolchain/sem_ir/clang_decl.h"
 #include "toolchain/sem_ir/entry_point.h"
 #include "toolchain/sem_ir/ids.h"
 #include "toolchain/sem_ir/pattern.h"
@@ -208,15 +209,21 @@ auto Mangler::MangleGlobalVariable(SemIR::InstId pattern_id) -> std::string {
     return std::string();
   }
 
-  auto var_name = sem_ir().entity_names().Get(var_name_id);
-  if (var_name.clang_decl_id.has_value()) {
+  SemIR::CppGlobalVarId cpp_global_var_id =
+      sem_ir().cpp_global_vars().Lookup({.entity_name_id = var_name_id});
+  if (cpp_global_var_id.has_value()) {
+    SemIR::ClangDeclId clang_decl_id =
+        sem_ir().cpp_global_vars().Get(cpp_global_var_id).clang_decl_id;
+    CARBON_CHECK(clang_decl_id.has_value(),
+                 "CppGlobalVar should have a clang_decl_id");
     return MangleCppClang(cast<clang::NamedDecl>(
-        sem_ir().clang_decls().Get(var_name.clang_decl_id).key.decl));
+        sem_ir().clang_decls().Get(clang_decl_id).key.decl));
   }
 
   RawStringOstream os;
   os << "_C";
 
+  auto var_name = sem_ir().entity_names().Get(var_name_id);
   MangleNameId(os, var_name.name_id);
   // TODO: If the variable is private, also include the library name as part of
   // the mangling.

+ 1 - 0
toolchain/sem_ir/BUILD

@@ -87,6 +87,7 @@ cc_library(
         "class.h",
         "constant.h",
         "copy_on_write_block.h",
+        "cpp_global_var.h",
         "cpp_overload_set.h",
         "entity_name.h",
         "entity_with_params_base.h",

+ 71 - 0
toolchain/sem_ir/cpp_global_var.h

@@ -0,0 +1,71 @@
+// 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
+
+#ifndef CARBON_TOOLCHAIN_SEM_IR_CPP_GLOBAL_VAR_H_
+#define CARBON_TOOLCHAIN_SEM_IR_CPP_GLOBAL_VAR_H_
+
+#include "common/hashing.h"
+#include "common/ostream.h"
+#include "toolchain/sem_ir/clang_decl.h"
+#include "toolchain/sem_ir/ids.h"
+
+namespace Carbon::SemIR {
+
+// A key describing a C++ global variable imported into Carbon, identified by
+// its entity name.
+struct CppGlobalVarKey : public Printable<CppGlobalVarKey> {
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "{entity_name_id: " << entity_name_id << "}";
+  }
+
+  // TODO: Use default when `Printable` supports it.
+  friend auto operator==(const CppGlobalVarKey& lhs, const CppGlobalVarKey& rhs)
+      -> bool {
+    return lhs.entity_name_id == rhs.entity_name_id;
+  }
+
+  // The name of the variable.
+  EntityNameId entity_name_id;
+};
+
+// A C++ global variable imported into Carbon. This is used to map the entity
+// name to the Clang declaration so we can use Clang mangling.
+struct CppGlobalVar : public Printable<CppGlobalVar> {
+  auto Print(llvm::raw_ostream& out) const -> void {
+    out << "{key: " << key << ", clang_decl_id: " << clang_decl_id << "}";
+  }
+
+  // Comparison against `CppGlobalVarKey`, required by `CanonicalValueStore`.
+  friend auto operator==(const CppGlobalVar& lhs, const CppGlobalVarKey& rhs)
+      -> bool {
+    return lhs.key == rhs;
+  }
+  friend auto operator==(const CppGlobalVar& lhs, const CppGlobalVar& rhs)
+      -> bool {
+    return lhs.key == rhs.key;
+  }
+
+  // Hashing for `CppGlobalVar`. See common/hashing.h.
+  friend auto CarbonHashValue(const CppGlobalVar& value, uint64_t seed)
+      -> HashCode {
+    return HashValue(value.key, seed);
+  }
+
+  // The key by which this variable can be looked up.
+  CppGlobalVarKey key;
+
+  // The Clang declaration for this variable, if any.
+  // This is ignored for equality and hashing, since it's always unique for a
+  // given key, in order to store it in `CanonicalValueStore` and allow lookup
+  // by `CppGlobalVarKey`.
+  ClangDeclId clang_decl_id;
+};
+
+// Use the name of a C++ global variable when doing `Lookup` to find an ID.
+using CppGlobalVarStore =
+    CanonicalValueStore<CppGlobalVarId, CppGlobalVarKey, CppGlobalVar>;
+
+}  // namespace Carbon::SemIR
+
+#endif  // CARBON_TOOLCHAIN_SEM_IR_CPP_GLOBAL_VAR_H_

+ 3 - 9
toolchain/sem_ir/entity_name.h

@@ -17,7 +17,7 @@ struct EntityName : public Printable<EntityName> {
   auto Print(llvm::raw_ostream& out) const -> void {
     out << "{name: " << name_id << ", parent_scope: " << parent_scope_id
         << ", index: " << bind_index_value << ", is_template: " << is_template
-        << ", clang_decl_id: " << clang_decl_id << "}";
+        << "}";
   }
 
   friend auto CarbonHashtableEq(const EntityName& lhs, const EntityName& rhs)
@@ -56,10 +56,6 @@ struct EntityName : public Printable<EntityName> {
   int32_t bind_index_value : 31 = CompileTimeBindIndex::None.index;
   // Whether this binding is a template parameter.
   bool is_template : 1 = false;
-  // For imported C++ global variable names, the Clang decl to use for mangling.
-  // TODO: Move the mapping between global variables and the clang decl to avoid
-  // paying extra memory when the names are not imported from C++.
-  ClangDeclId clang_decl_id = ClangDeclId::None;
 };
 
 // Value store for EntityName. In addition to the regular ValueStore
@@ -68,14 +64,12 @@ struct EntityNameStore : public ValueStore<EntityNameId, EntityName> {
  public:
   // Adds an entity name for a symbolic binding.
   auto AddSymbolicBindingName(NameId name_id, NameScopeId parent_scope_id,
-                              CompileTimeBindIndex bind_index, bool is_template,
-                              ClangDeclId clang_decl_id = ClangDeclId::None)
+                              CompileTimeBindIndex bind_index, bool is_template)
       -> EntityNameId {
     return Add({.name_id = name_id,
                 .parent_scope_id = parent_scope_id,
                 .bind_index_value = bind_index.index,
-                .is_template = is_template,
-                .clang_decl_id = clang_decl_id});
+                .is_template = is_template});
   }
 
   // Convert an `EntityName` to a canonical ID. All calls to this with

+ 3 - 0
toolchain/sem_ir/file.cpp

@@ -112,6 +112,7 @@ auto File::OutputYaml(bool include_singletons) const -> Yaml::OutputMapping {
               map.Add("clang_decls", clang_decls_.OutputYaml());
               map.Add("name_scopes", name_scopes_.OutputYaml());
               map.Add("entity_names", entity_names_.OutputYaml());
+              map.Add("cpp_global_vars", cpp_global_vars_.OutputYaml());
               map.Add("functions", functions_.OutputYaml());
               map.Add("classes", classes_.OutputYaml());
               map.Add("generics", generics_.OutputYaml());
@@ -139,6 +140,8 @@ auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
   mem_usage.Collect(MemUsage::ConcatLabel(label, "allocator_"), allocator_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "entity_names_"),
                     entity_names_);
+  mem_usage.Collect(MemUsage::ConcatLabel(label, "cpp_global_vars_"),
+                    cpp_global_vars_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "functions_"), functions_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "classes_"), classes_);
   mem_usage.Collect(MemUsage::ConcatLabel(label, "interfaces_"), interfaces_);

+ 8 - 0
toolchain/sem_ir/file.h

@@ -21,6 +21,7 @@
 #include "toolchain/sem_ir/associated_constant.h"
 #include "toolchain/sem_ir/class.h"
 #include "toolchain/sem_ir/constant.h"
+#include "toolchain/sem_ir/cpp_global_var.h"
 #include "toolchain/sem_ir/cpp_overload_set.h"
 #include "toolchain/sem_ir/entity_name.h"
 #include "toolchain/sem_ir/facet_type_info.h"
@@ -154,6 +155,10 @@ class File : public Printable<File> {
 
   auto entity_names() -> EntityNameStore& { return entity_names_; }
   auto entity_names() const -> const EntityNameStore& { return entity_names_; }
+  auto cpp_global_vars() -> CppGlobalVarStore& { return cpp_global_vars_; }
+  auto cpp_global_vars() const -> const CppGlobalVarStore& {
+    return cpp_global_vars_;
+  }
   auto functions() -> FunctionStore& { return functions_; }
   auto functions() const -> const FunctionStore& { return functions_; }
   auto cpp_overload_sets() -> CppOverloadSetStore& {
@@ -301,6 +306,9 @@ class File : public Printable<File> {
   // Storage for EntityNames.
   EntityNameStore entity_names_;
 
+  // For imported C++ global variables, the Clang decl to use for mangling.
+  CppGlobalVarStore cpp_global_vars_;
+
   // Storage for callable objects.
   FunctionStore functions_;
 

+ 7 - 0
toolchain/sem_ir/ids.h

@@ -251,6 +251,13 @@ struct EntityNameId : public IdBase<EntityNameId> {
   using IdBase::IdBase;
 };
 
+// The ID of a C++ global variable.
+struct CppGlobalVarId : public IdBase<CppGlobalVarId> {
+  static constexpr llvm::StringLiteral Label = "cpp_global_var";
+
+  using IdBase::IdBase;
+};
+
 // The index of a compile-time binding. This is the de Bruijn level for the
 // binding -- that is, this is the number of other compile time bindings whose
 // scope encloses this binding.

+ 1 - 0
toolchain/sem_ir/yaml_test.cpp

@@ -60,6 +60,7 @@ TEST(SemIRTest, Yaml) {
       Pair("clang_decls", Yaml::Mapping(SizeIs(0))),
       Pair("name_scopes", Yaml::Mapping(SizeIs(1))),
       Pair("entity_names", Yaml::Mapping(SizeIs(1))),
+      Pair("cpp_global_vars", Yaml::Mapping(SizeIs(0))),
       Pair("functions", Yaml::Mapping(SizeIs(1))),
       Pair("classes", Yaml::Mapping(SizeIs(0))),
       Pair("generics", Yaml::Mapping(SizeIs(0))),