Forráskód Böngészése

Formalize Cpp as a PackageNameId (#6306)

This turns `Cpp` into a keyword, and makes it map to `NameId::Cpp` and
`PackageNameId::Cpp`.

Per discussion with zygoloid, the keyword versus identifier question is
deliberately kept open by #4846. This PR switches to a keyword because
mapping to a specific `PackageNameId` works best with a special `NameId`
not backed by an `IdentifierId`. We could in theory make it work using
`IdentifierId` or a runtime-tracked `PackageNameId` for `Cpp` (e.g.
stored on `SemIR::File`), but this approach is consistent with `Core`
and so seemed like a good starting point.

---------

Co-authored-by: Dana Jansens <danakj@orodu.net>
Jon Ross-Perkins 5 hónapja
szülő
commit
8166f9a7cf

+ 15 - 2
toolchain/base/value_ids.h

@@ -83,7 +83,7 @@ struct PackageNameId : public IdBase<PackageNameId> {
   static constexpr llvm::StringLiteral Label = "package";
   static const PackageNameId None;
   static const PackageNameId Core;
-  static constexpr llvm::StringLiteral CppName = "Cpp";
+  static const PackageNameId Cpp;
 
   // Returns the PackageNameId corresponding to a particular IdentifierId.
   static auto ForIdentifier(IdentifierId id) -> PackageNameId {
@@ -101,17 +101,30 @@ struct PackageNameId : public IdBase<PackageNameId> {
   // Returns the special package name corresponding to this PackageNameId.
   // Requires that this name is not an identifier name.
   auto AsSpecialName() const -> llvm::StringLiteral {
+    CARBON_CHECK(index <= NoneIndex);
     if (*this == None) {
       return "Main";
     }
     if (*this == Core) {
       return "Core";
     }
-    CARBON_FATAL("Unknown special package name kind {0}", *this);
+    if (*this == Cpp) {
+      return "Cpp";
+    }
+    CARBON_FATAL("Unknown special package name kind {0}", index);
+  }
+
+  auto Print(llvm::raw_ostream& out) const -> void {
+    if (index <= NoneIndex) {
+      out << Label << AsSpecialName();
+    } else {
+      IdBase::Print(out);
+    }
   }
 };
 constexpr PackageNameId PackageNameId::None(PackageNameId::NoneIndex);
 constexpr PackageNameId PackageNameId::Core(PackageNameId::NoneIndex - 1);
+constexpr PackageNameId PackageNameId::Cpp(PackageNameId::NoneIndex - 2);
 
 // Corresponds to StringRefs for string literals.
 struct StringLiteralValueId : public IdBase<StringLiteralValueId> {

+ 8 - 10
toolchain/check/check.cpp

@@ -73,14 +73,7 @@ static auto TrackImport(Map<ImportKey, UnitAndImports*>& api_map,
                         UnitAndImports& unit_info,
                         Parse::Tree::PackagingNames import, bool fuzzing)
     -> void {
-  const auto& packaging = unit_info.parse_tree().packaging_decl();
-
-  PackageNameId file_package_id =
-      packaging ? packaging->names.package_id : PackageNameId::None;
-  const auto import_key = GetImportKey(unit_info, file_package_id, import);
-  const auto& [import_package_name, import_library_name] = import_key;
-
-  if (import_package_name == PackageNameId::CppName) {
+  if (import.package_id == PackageNameId::Cpp) {
     if (!explicit_import_map) {
       // Don't diagnose the implicit import in `impl package Cpp`, because we'll
       // have diagnosed the use of `Cpp` in the declaration.
@@ -108,9 +101,14 @@ static auto TrackImport(Map<ImportKey, UnitAndImports*>& api_map,
     return;
   }
 
+  const auto& packaging = unit_info.parse_tree().packaging_decl();
+  PackageNameId file_package_id =
+      packaging ? packaging->names.package_id : PackageNameId::None;
+  const auto import_key = GetImportKey(unit_info, file_package_id, import);
+
   // True if the import has `Main` as the package name, even if it comes from
   // the file's packaging (diagnostics may differentiate).
-  bool is_explicit_main = import_package_name == MainPackageName;
+  bool is_explicit_main = import_key.first == MainPackageName;
 
   // Explicit imports need more validation than implicit ones. We try to do
   // these in an order of imports that should be removed, followed by imports
@@ -265,7 +263,7 @@ static auto BuildApiMapAndDiagnosePackaging(
                                                        : ExplicitMainLibrary);
       continue;
     }
-    if (import_key.first == PackageNameId::CppName) {
+    if (packaging && packaging->names.package_id == PackageNameId::Cpp) {
       CARBON_DIAGNOSTIC(CppPackageDeclaration, Error,
                         "`Cpp` cannot be used by a `package` declaration");
       unit_info.emitter.Emit(packaging->names.node_id, CppPackageDeclaration);

+ 5 - 0
toolchain/check/handle_import_and_package.cpp

@@ -73,6 +73,11 @@ auto HandleParseNode(Context& /*context*/, Parse::CorePackageNameId /*node_id*/)
   return true;
 }
 
+auto HandleParseNode(Context& /*context*/, Parse::CppPackageNameId /*node_id*/)
+    -> bool {
+  return true;
+}
+
 auto HandleParseNode(Context& context, Parse::LibraryNameId node_id) -> bool {
   // This is discarded in this file's uses, but is used by modifiers for `extern
   // library`.

+ 8 - 0
toolchain/check/handle_name.cpp

@@ -240,4 +240,12 @@ auto HandleParseNode(Context& context, Parse::CoreNameExprId node_id) -> bool {
   return true;
 }
 
+auto HandleParseNode(Context& context, Parse::CppNameExprId node_id) -> bool {
+  // TODO: Unqualified lookup will never find anything; perform lookup directly
+  // into file scope.
+  context.node_stack().Push(
+      node_id, HandleNameAsExpr(context, node_id, SemIR::NameId::Cpp));
+  return true;
+}
+
 }  // namespace Carbon::Check

+ 1 - 0
toolchain/check/node_stack.h

@@ -491,6 +491,7 @@ class NodeStack {
       case Parse::NodeKind::CompileTimeBindingPatternStart:
       case Parse::NodeKind::ContinueStatementStart:
       case Parse::NodeKind::CorePackageName:
+      case Parse::NodeKind::CppPackageName:
       case Parse::NodeKind::ExportIntroducer:
       case Parse::NodeKind::FileEnd:
       case Parse::NodeKind::FileStart:

+ 29 - 29
toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon

@@ -52,32 +52,32 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     clang_decl_id60000006: {key: {decl: "extern void f__carbon_thunk(X * _Nonnull x)", num_params: 1}, inst_id: inst60000042}
 // CHECK:STDOUT:     clang_decl_id60000007: {key: "X * _Nonnull global", inst_id: inst6000004B}
 // CHECK:STDOUT:   name_scopes:
-// CHECK:STDOUT:     name_scope00000000: {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name00000000: inst60000010, name00000001: inst6000001C}}
-// CHECK:STDOUT:     name_scope60000001: {inst: inst60000010, parent_scope: name_scope00000000, has_error: false, extended_scopes: [], names: {name00000003: inst60000013, name00000004: inst60000029, name00000005: inst6000004B}}
+// CHECK:STDOUT:     name_scope00000000: {inst: inst0000000E, parent_scope: name_scope<none>, has_error: false, extended_scopes: [], names: {name(Cpp): inst60000010, name00000000: inst6000001C}}
+// CHECK:STDOUT:     name_scope60000001: {inst: inst60000010, parent_scope: name_scope00000000, has_error: false, extended_scopes: [], names: {name00000002: inst60000013, name00000003: inst60000029, name00000004: inst6000004B}}
 // CHECK:STDOUT:     name_scope60000002: {inst: inst60000013, parent_scope: name_scope60000001, has_error: false, extended_scopes: [], names: {}}
 // CHECK:STDOUT:   entity_names:
-// CHECK:STDOUT:     entity_name60000000: {name: name00000002, parent_scope: name_scope<none>, index: -1, is_template: 0}
-// CHECK:STDOUT:     entity_name60000001: {name: name00000002, parent_scope: name_scope<none>, index: -1, is_template: 0}
-// CHECK:STDOUT:     entity_name60000002: {name: name00000002, parent_scope: name_scope<none>, index: -1, is_template: 0}
-// CHECK:STDOUT:     entity_name60000003: {name: name00000005, parent_scope: name_scope60000001, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name60000000: {name: name00000001, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name60000001: {name: name00000001, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name60000002: {name: name00000001, parent_scope: name_scope<none>, index: -1, is_template: 0}
+// CHECK:STDOUT:     entity_name60000003: {name: name00000004, parent_scope: name_scope60000001, index: -1, is_template: 0}
 // CHECK:STDOUT:   cpp_global_vars:
 // CHECK:STDOUT:     cpp_global_var60000000: {key: {entity_name_id: entity_name60000003}, clang_decl_id: clang_decl_id60000007}
 // CHECK:STDOUT:   functions:
-// CHECK:STDOUT:     function60000000: {name: name00000001, parent_scope: name_scope00000000, call_params_id: inst_block60000006, body: [inst_block60000009]}
-// CHECK:STDOUT:     function60000001: {name: name00000004, parent_scope: name_scope60000001, call_params_id: inst_block_empty}
-// CHECK:STDOUT:     function60000002: {name: name00000007, parent_scope: name_scope60000001, call_params_id: inst_block_empty}
-// CHECK:STDOUT:     function60000003: {name: name00000004, parent_scope: name_scope60000001, call_params_id: inst_block6000000D}
-// CHECK:STDOUT:     function60000004: {name: name00000007, parent_scope: name_scope60000001, call_params_id: inst_block60000012}
+// CHECK:STDOUT:     function60000000: {name: name00000000, parent_scope: name_scope00000000, call_params_id: inst_block60000006, body: [inst_block60000009]}
+// CHECK:STDOUT:     function60000001: {name: name00000003, parent_scope: name_scope60000001, call_params_id: inst_block_empty}
+// CHECK:STDOUT:     function60000002: {name: name00000006, parent_scope: name_scope60000001, call_params_id: inst_block_empty}
+// CHECK:STDOUT:     function60000003: {name: name00000003, parent_scope: name_scope60000001, call_params_id: inst_block6000000D}
+// CHECK:STDOUT:     function60000004: {name: name00000006, parent_scope: name_scope60000001, call_params_id: inst_block60000012}
 // CHECK:STDOUT:   classes:
-// CHECK:STDOUT:     class60000000:   {name: name00000003, parent_scope: name_scope60000001, self_type_id: type(inst60000014), inheritance_kind: Base, is_dynamic: 0, scope_id: name_scope60000002, body_block_id: inst_block6000000A, adapt_id: inst<none>, base_id: inst<none>, complete_type_witness_id: inst60000024, vtable_decl_id: inst<none>}}
+// CHECK:STDOUT:     class60000000:   {name: name00000002, parent_scope: name_scope60000001, self_type_id: type(inst60000014), inheritance_kind: Base, is_dynamic: 0, scope_id: name_scope60000002, body_block_id: inst_block6000000A, 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_fields00000000: {}
 // CHECK:STDOUT:     struct_type_fields60000001:
-// CHECK:STDOUT:       0:               {name_id: name00000006, type_inst_id: inst6000001F}
+// CHECK:STDOUT:       0:               {name_id: name00000005, type_inst_id: inst6000001F}
 // CHECK:STDOUT:     struct_type_fields60000002:
-// CHECK:STDOUT:       0:               {name_id: name00000006, type_inst_id: inst6000001F}
+// CHECK:STDOUT:       0:               {name_id: name00000005, type_inst_id: inst6000001F}
 // CHECK:STDOUT:   types:
 // CHECK:STDOUT:     'type(TypeType)':
 // CHECK:STDOUT:       value_repr:      {kind: copy, type: type(TypeType)}
@@ -129,33 +129,33 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst0000000E:    {kind: Namespace, arg0: name_scope00000000, arg1: inst<none>, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst6000000F:    {kind: ImportCppDecl}
 // CHECK:STDOUT:     inst60000010:    {kind: Namespace, arg0: name_scope60000001, arg1: inst6000000F, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst60000011:    {kind: NameRef, arg0: name00000000, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000011:    {kind: NameRef, arg0: name(Cpp), arg1: inst60000010, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst60000012:    {kind: TupleType, arg0: inst_block_empty, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000013:    {kind: ClassDecl, arg0: class60000000, arg1: inst_block<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000014:    {kind: ClassType, arg0: class60000000, arg1: specific<none>, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000015:    {kind: NameRef, arg0: name00000003, arg1: inst60000013, type: type(TypeType)}
+// CHECK:STDOUT:     inst60000015:    {kind: NameRef, arg0: name00000002, arg1: inst60000013, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000016:    {kind: ValueBinding, arg0: entity_name60000000, arg1: inst6000001A, type: type(inst60000014)}
 // CHECK:STDOUT:     inst60000017:    {kind: PatternType, arg0: inst60000014, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000018:    {kind: ValueBindingPattern, arg0: entity_name60000000, type: type(inst60000017)}
 // CHECK:STDOUT:     inst60000019:    {kind: ValueParamPattern, arg0: inst60000018, arg1: call_param0, type: type(inst60000017)}
-// CHECK:STDOUT:     inst6000001A:    {kind: ValueParam, arg0: call_param0, arg1: name00000002, type: type(inst60000014)}
+// CHECK:STDOUT:     inst6000001A:    {kind: ValueParam, arg0: call_param0, arg1: name00000001, type: type(inst60000014)}
 // CHECK:STDOUT:     inst6000001B:    {kind: SpliceBlock, arg0: inst_block60000004, arg1: inst60000015, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001C:    {kind: FunctionDecl, arg0: function60000000, arg1: inst_block60000008, type: type(inst6000001D)}
 // CHECK:STDOUT:     inst6000001D:    {kind: FunctionType, arg0: function60000000, arg1: specific<none>, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000001E:    {kind: StructValue, arg0: inst_block_empty, type: type(inst6000001D)}
 // CHECK:STDOUT:     inst6000001F:    {kind: PointerType, arg0: inst60000014, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000020:    {kind: UnboundElementType, arg0: inst60000014, arg1: inst6000001F, type: type(TypeType)}
-// CHECK:STDOUT:     inst60000021:    {kind: FieldDecl, arg0: name00000006, arg1: element0, type: type(inst60000020)}
+// CHECK:STDOUT:     inst60000021:    {kind: FieldDecl, arg0: name00000005, arg1: element0, type: type(inst60000020)}
 // CHECK:STDOUT:     inst60000022:    {kind: CustomLayoutType, arg0: struct_type_fields60000001, arg1: custom_layout60000001, type: type(TypeType)}
 // CHECK:STDOUT:     inst60000023:    {kind: CustomLayoutType, arg0: struct_type_fields60000002, arg1: custom_layout60000001, 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: name00000000, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000027:    {kind: NameRef, arg0: name(Cpp), 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: name00000004, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000002B:    {kind: NameRef, arg0: name00000003, 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)}
@@ -163,13 +163,13 @@ fn G(x: Cpp.X) {
 // 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(inst60000012)}
-// CHECK:STDOUT:     inst60000033:    {kind: NameRef, arg0: name00000000, arg1: inst60000010, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst60000034:    {kind: NameRef, arg0: name00000004, arg1: inst60000029, type: type(inst60000028)}
-// CHECK:STDOUT:     inst60000035:    {kind: NameRef, arg0: name00000002, arg1: inst60000016, type: type(inst60000014)}
+// CHECK:STDOUT:     inst60000033:    {kind: NameRef, arg0: name(Cpp), arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000034:    {kind: NameRef, arg0: name00000003, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst60000035:    {kind: NameRef, arg0: name00000001, arg1: inst60000016, type: type(inst60000014)}
 // CHECK:STDOUT:     inst60000036:    {kind: ValueBinding, arg0: entity_name60000001, arg1: inst60000039, type: type(inst60000014)}
 // CHECK:STDOUT:     inst60000037:    {kind: ValueBindingPattern, arg0: entity_name60000001, type: type(inst60000017)}
 // CHECK:STDOUT:     inst60000038:    {kind: ValueParamPattern, arg0: inst60000037, arg1: call_param0, type: type(inst60000017)}
-// CHECK:STDOUT:     inst60000039:    {kind: ValueParam, arg0: call_param0, arg1: name00000002, type: type(inst60000014)}
+// CHECK:STDOUT:     inst60000039:    {kind: ValueParam, arg0: call_param0, arg1: name00000001, type: type(inst60000014)}
 // CHECK:STDOUT:     inst6000003A:    {kind: FunctionDecl, arg0: function60000003, arg1: inst_block6000000F, 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)}
@@ -177,21 +177,21 @@ fn G(x: Cpp.X) {
 // CHECK:STDOUT:     inst6000003E:    {kind: PatternType, arg0: inst6000001F, type: type(TypeType)}
 // CHECK:STDOUT:     inst6000003F:    {kind: ValueBindingPattern, arg0: entity_name60000002, 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: name00000002, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst60000041:    {kind: ValueParam, arg0: call_param0, arg1: name00000001, type: type(inst6000001F)}
 // CHECK:STDOUT:     inst60000042:    {kind: FunctionDecl, arg0: function60000004, arg1: inst_block60000014, 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(inst60000014)}
 // CHECK:STDOUT:     inst60000046:    {kind: AddrOf, arg0: inst60000045, type: type(inst6000001F)}
 // CHECK:STDOUT:     inst60000047:    {kind: Call, arg0: inst60000042, arg1: inst_block60000016, type: type(inst60000012)}
-// CHECK:STDOUT:     inst60000048:    {kind: NameRef, arg0: name00000000, arg1: inst60000010, type: type(inst(NamespaceType))}
-// CHECK:STDOUT:     inst60000049:    {kind: NameRef, arg0: name00000004, arg1: inst60000029, type: type(inst60000028)}
-// CHECK:STDOUT:     inst6000004A:    {kind: NameRef, arg0: name00000000, arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000048:    {kind: NameRef, arg0: name(Cpp), arg1: inst60000010, type: type(inst(NamespaceType))}
+// CHECK:STDOUT:     inst60000049:    {kind: NameRef, arg0: name00000003, arg1: inst60000029, type: type(inst60000028)}
+// CHECK:STDOUT:     inst6000004A:    {kind: NameRef, arg0: name(Cpp), arg1: inst60000010, type: type(inst(NamespaceType))}
 // CHECK:STDOUT:     inst6000004B:    {kind: VarStorage, arg0: inst6000004D, type: type(inst6000001F)}
 // CHECK:STDOUT:     inst6000004C:    {kind: RefBindingPattern, arg0: entity_name60000003, type: type(inst6000003E)}
 // CHECK:STDOUT:     inst6000004D:    {kind: VarPattern, arg0: inst6000004C, type: type(inst6000003E)}
 // CHECK:STDOUT:     inst6000004E:    {kind: NameBindingDecl, arg0: inst_block60000017}
-// CHECK:STDOUT:     inst6000004F:    {kind: NameRef, arg0: name00000005, arg1: inst6000004B, type: type(inst6000001F)}
+// CHECK:STDOUT:     inst6000004F:    {kind: NameRef, arg0: name00000004, arg1: inst6000004B, type: type(inst6000001F)}
 // CHECK:STDOUT:     inst60000050:    {kind: AcquireValue, arg0: inst6000004F, type: type(inst6000001F)}
 // CHECK:STDOUT:     inst60000051:    {kind: Deref, arg0: inst60000050, type: type(inst60000014)}
 // CHECK:STDOUT:     inst60000052:    {kind: AcquireValue, arg0: inst60000051, type: type(inst60000014)}

+ 0 - 10
toolchain/check/testdata/interop/cpp/class/access.carbon

@@ -1687,7 +1687,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .F = %Derived.F.decl
 // CHECK:STDOUT:   .instance_data = <poisoned>
@@ -1819,7 +1818,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .F = %Derived.F.decl
 // CHECK:STDOUT:   .instance_fn = <poisoned>
@@ -1862,7 +1860,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .F = %Derived.F.decl
 // CHECK:STDOUT:   .static_fn = <poisoned>
@@ -2088,7 +2085,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%D
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .D = <poisoned>
 // CHECK:STDOUT:   .MakePublic = %D.MakePublic.decl
@@ -2346,7 +2342,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .F = %Derived.F.decl
 // CHECK:STDOUT:   .Overload = <poisoned>
@@ -2468,7 +2463,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .F = %Derived.F.decl
 // CHECK:STDOUT:   .Overload = <poisoned>
@@ -2581,7 +2575,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .CallStatic = %Derived.CallStatic.decl
 // CHECK:STDOUT:   .CallInstance = %Derived.CallInstance.decl
@@ -2678,7 +2671,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .CallStatic = %Derived.CallStatic.decl
 // CHECK:STDOUT:   .CallInstance = %Derived.CallInstance.decl
@@ -2759,7 +2751,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .CallStatic = %Derived.CallStatic.decl
 // CHECK:STDOUT:   .CallInstance = %Derived.CallInstance.decl
@@ -2876,7 +2867,6 @@ fn Call(var instance: Cpp.PublicPrivate) {
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc7
 // CHECK:STDOUT:   .CallStatic = %Derived.CallStatic.decl
 // CHECK:STDOUT:   .CallInstance = %Derived.CallInstance.decl

+ 0 - 1
toolchain/check/testdata/interop/cpp/class/class.carbon

@@ -553,7 +553,6 @@ fn MyF(bar: Cpp.Bar*);
 // CHECK:STDOUT:
 // CHECK:STDOUT: !members:
 // CHECK:STDOUT:   .Self = constants.%Derived
-// CHECK:STDOUT:   .Cpp = <poisoned>
 // CHECK:STDOUT:   .base = %.loc8
 // CHECK:STDOUT:   .foo = <poisoned>
 // CHECK:STDOUT:   extend %Bar.ref

+ 19 - 23
toolchain/check/testdata/interop/cpp/cpp_namespace.carbon

@@ -18,25 +18,32 @@ library "[[@TEST_NAME]]";
 
 import Cpp library "header.h";
 
-// CHECK:STDERR: fail_duplicate_cpp_name.carbon:[[@LINE+7]]:11: error: duplicate name `Cpp` being declared in the same scope [NameDeclDuplicate]
+// CHECK:STDERR: fail_duplicate_cpp_name.carbon:[[@LINE+8]]:11: error: `namespace` introducer should be followed by a name [ExpectedDeclName]
+// CHECK:STDERR: namespace Cpp;
+// CHECK:STDERR:           ^~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_duplicate_cpp_name.carbon:[[@LINE+4]]:11: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
 // CHECK:STDERR: namespace Cpp;
 // CHECK:STDERR:           ^~~
-// CHECK:STDERR: fail_duplicate_cpp_name.carbon:[[@LINE-5]]:1: note: name is previously declared here [NameDeclPrevious]
-// CHECK:STDERR: import Cpp library "header.h";
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
 namespace Cpp;
 
-// --- cpp_in_inner_namespace.carbon
+// --- fail_cpp_in_inner_namespace.carbon
 
 library "[[@TEST_NAME]]";
 
 import Cpp library "header.h";
 
-//@dump-sem-ir-begin
 namespace N;
+// CHECK:STDERR: fail_cpp_in_inner_namespace.carbon:[[@LINE+8]]:13: error: `.` should be followed by a name [ExpectedDeclNameAfterPeriod]
+// CHECK:STDERR: namespace N.Cpp;
+// CHECK:STDERR:             ^~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_cpp_in_inner_namespace.carbon:[[@LINE+4]]:13: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
+// CHECK:STDERR: namespace N.Cpp;
+// CHECK:STDERR:             ^~~
+// CHECK:STDERR:
 namespace N.Cpp;
-//@dump-sem-ir-end
 
 // --- alias.carbon
 
@@ -54,12 +61,13 @@ library "[[@TEST_NAME]]";
 
 import Cpp library "header.h";
 
-// CHECK:STDERR: fail_add_name_to_cpp_namespace.carbon:[[@LINE+7]]:7: error: imported packages cannot be used for declarations [QualifiedDeclOutsidePackage]
+// CHECK:STDERR: fail_add_name_to_cpp_namespace.carbon:[[@LINE+8]]:7: error: `class` introducer should be followed by a name [ExpectedDeclName]
+// CHECK:STDERR: class Cpp.C {};
+// CHECK:STDERR:       ^~~
+// CHECK:STDERR:
+// CHECK:STDERR: fail_add_name_to_cpp_namespace.carbon:[[@LINE+4]]:7: error: semantics TODO: `handle invalid parse trees in `check`` [SemanticsTodo]
 // CHECK:STDERR: class Cpp.C {};
 // CHECK:STDERR:       ^~~
-// CHECK:STDERR: fail_add_name_to_cpp_namespace.carbon:[[@LINE-5]]:1: note: package imported here [QualifiedDeclOutsidePackageSource]
-// CHECK:STDERR: import Cpp library "header.h";
-// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // CHECK:STDERR:
 class Cpp.C {};
 
@@ -98,18 +106,6 @@ fn F() {
 //@dump-sem-ir-end
 }
 
-// CHECK:STDOUT: --- cpp_in_inner_namespace.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: file {
-// CHECK:STDOUT:   %N: <namespace> = namespace [concrete] {
-// CHECK:STDOUT:     .Cpp = %Cpp
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %Cpp: <namespace> = namespace [concrete] {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- alias.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {

+ 4 - 7
toolchain/check/testdata/packages/restricted_package_names.carbon

@@ -71,13 +71,8 @@ package Cpp;
 // CHECK:STDERR:
 impl package Cpp;
 
-// --- fail_raw_cpp.carbon
+// --- raw_cpp.carbon
 
-// `cpp` isn't a keyword, so this fails the same way.
-// CHECK:STDERR: fail_raw_cpp.carbon:[[@LINE+4]]:1: error: `Cpp` cannot be used by a `package` declaration [CppPackageDeclaration]
-// CHECK:STDERR: package r#Cpp;
-// CHECK:STDERR: ^~~~~~~~~~~~~~
-// CHECK:STDERR:
 package r#Cpp;
 
 // --- fail_cpp_lib.carbon
@@ -134,9 +129,11 @@ package Cpp library "[[@TEST_NAME]]";
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {}
+// CHECK:STDOUT:   %Cpp.import = import Cpp
+// CHECK:STDOUT:   %default.import = import <none>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- fail_raw_cpp.carbon
+// CHECK:STDOUT: --- raw_cpp.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: file {
 // CHECK:STDOUT:   package: <namespace> = namespace [concrete] {}

+ 1 - 0
toolchain/lex/token_kind.def

@@ -181,6 +181,7 @@ CARBON_KEYWORD_TOKEN(Char,                "char")
 CARBON_KEYWORD_TOKEN(Const,               "const")
 CARBON_KEYWORD_TOKEN(Continue,            "continue")
 CARBON_KEYWORD_TOKEN(Core,                "Core")
+CARBON_KEYWORD_TOKEN(Cpp,                 "Cpp")
 CARBON_KEYWORD_TOKEN(Default,             "default")
 CARBON_KEYWORD_TOKEN(Else,                "else")
 CARBON_KEYWORD_TOKEN(Extend,              "extend")

+ 1 - 1
toolchain/lex/token_kind_test.cpp

@@ -21,7 +21,7 @@ constexpr llvm::StringLiteral SymbolRegex =
 
 // We restrict keywords to be lowercase ASCII letters and underscores with a few
 // specific exceptions.
-constexpr llvm::StringLiteral KeywordRegex = "[a-z_]+|Core|Self|String";
+constexpr llvm::StringLiteral KeywordRegex = "[a-z_]+|Core|Cpp|Self";
 
 #define CARBON_TOKEN(TokenName)                           \
   TEST(TokenKindTest, TokenName) {                        \

+ 5 - 0
toolchain/parse/handle_expr.cpp

@@ -180,6 +180,11 @@ auto HandleExprInPostfix(Context& context) -> void {
       context.PushState(state);
       break;
     }
+    case Lex::TokenKind::Cpp: {
+      context.AddLeafNode(NodeKind::CppNameExpr, context.Consume());
+      context.PushState(state);
+      break;
+    }
     case Lex::TokenKind::SelfValueIdentifier: {
       context.AddLeafNode(NodeKind::SelfValueNameExpr, context.Consume());
       context.PushState(state);

+ 4 - 2
toolchain/parse/handle_import_and_package.cpp

@@ -48,7 +48,7 @@ static auto HandleDeclContent(Context& context, Context::State state,
     // This is either `library ...` or `import library ...`, so no package name
     // is expected.
   } else {
-    // We require a package name. This is either an identifier or the `Core`
+    // We require a package name. This is either an identifier or package name
     // keyword.
     auto package_name_position = *context.position();
     if (auto ident = context.ConsumeIf(Lex::TokenKind::Identifier)) {
@@ -56,9 +56,11 @@ static auto HandleDeclContent(Context& context, Context::State state,
           PackageNameId::ForIdentifier(context.tokens().GetIdentifier(*ident));
       context.AddLeafNode(NodeKind::IdentifierPackageName, *ident);
     } else if (auto core = context.ConsumeIf(Lex::TokenKind::Core)) {
-      // TODO: Model `Cpp` as a keyword too.
       names.package_id = PackageNameId::Core;
       context.AddLeafNode(NodeKind::CorePackageName, *core);
+    } else if (auto cpp = context.ConsumeIf(Lex::TokenKind::Cpp)) {
+      names.package_id = PackageNameId::Cpp;
+      context.AddLeafNode(NodeKind::CppPackageName, *cpp);
     } else {
       CARBON_DIAGNOSTIC(ExpectedIdentifierAfterPackage, Error,
                         "expected identifier after `package`");

+ 2 - 0
toolchain/parse/node_kind.def

@@ -109,8 +109,10 @@ CARBON_PARSE_NODE_KIND(UnderscoreName)
 CARBON_PARSE_NODE_KIND(BaseName)
 CARBON_PARSE_NODE_KIND(PackageExpr)
 CARBON_PARSE_NODE_KIND(CoreNameExpr)
+CARBON_PARSE_NODE_KIND(CppNameExpr)
 CARBON_PARSE_NODE_KIND(IdentifierPackageName)
 CARBON_PARSE_NODE_KIND(CorePackageName)
+CARBON_PARSE_NODE_KIND(CppPackageName)
 CARBON_PARSE_NODE_KIND(LibraryName)
 
 CARBON_PARSE_NODE_KIND(PackageIntroducer)

+ 6 - 6
toolchain/parse/testdata/packages/import/cpp_inline.carbon

@@ -76,17 +76,17 @@ int n;
 // CHECK:STDOUT:   parse_tree: [
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'InlineImportBody', text: ';', has_error: yes},
 // CHECK:STDOUT:       {kind: 'InlineImportSpecifier', text: 'inline', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'ImportDecl', text: ';', has_error: yes, subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'InlineImportBody', text: 'library', has_error: yes},
 // CHECK:STDOUT:       {kind: 'InlineImportSpecifier', text: 'inline', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'ImportDecl', text: ';', has_error: yes, subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'LibraryName', text: '"foo.h"'},
 // CHECK:STDOUT:       {kind: 'LibrarySpecifier', text: 'library', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'ImportDecl', text: ';', has_error: yes, subtree_size: 5},
@@ -100,7 +100,7 @@ int n;
 // CHECK:STDOUT:   parse_tree: [
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'InlineImportBody', text: '', has_error: yes},
 // CHECK:STDOUT:       {kind: 'InlineImportSpecifier', text: 'inline', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'ImportDecl', text: 'inline', has_error: yes, subtree_size: 5},
@@ -136,12 +136,12 @@ int n;
 // CHECK:STDOUT:   parse_tree: [
 // CHECK:STDOUT:     {kind: 'FileStart', text: ''},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'InlineImportBody', text: '"int m;"'},
 // CHECK:STDOUT:       {kind: 'InlineImportSpecifier', text: 'inline', subtree_size: 2},
 // CHECK:STDOUT:     {kind: 'ImportDecl', text: ';', subtree_size: 5},
 // CHECK:STDOUT:       {kind: 'ImportIntroducer', text: 'import'},
-// CHECK:STDOUT:       {kind: 'IdentifierPackageName', text: 'Cpp'},
+// CHECK:STDOUT:       {kind: 'CppPackageName', text: 'Cpp'},
 // CHECK:STDOUT:         {kind: 'InlineImportBody', text: ''''
 // CHECK:STDOUT: // C++ comment.
 // CHECK:STDOUT: int n;

+ 40 - 0
toolchain/parse/testdata/packages/keyword_names.carbon

@@ -0,0 +1,40 @@
+// 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
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/packages/keyword_names.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/packages/keyword_names.carbon
+
+// --- core.carbon
+
+var x: Core;
+
+// --- cpp.carbon
+
+var x: Cpp;
+
+// CHECK:STDOUT: - filename: core.carbon
+// CHECK:STDOUT:   parse_tree: [
+// CHECK:STDOUT:     {kind: 'FileStart', text: ''},
+// CHECK:STDOUT:       {kind: 'VariableIntroducer', text: 'var'},
+// CHECK:STDOUT:           {kind: 'IdentifierNameNotBeforeParams', text: 'x'},
+// CHECK:STDOUT:           {kind: 'CoreNameExpr', text: 'Core'},
+// CHECK:STDOUT:         {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
+// CHECK:STDOUT:       {kind: 'VariablePattern', text: 'var', subtree_size: 4},
+// CHECK:STDOUT:     {kind: 'VariableDecl', text: ';', subtree_size: 6},
+// CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
+// CHECK:STDOUT:   ]
+// CHECK:STDOUT: - filename: cpp.carbon
+// CHECK:STDOUT:   parse_tree: [
+// CHECK:STDOUT:     {kind: 'FileStart', text: ''},
+// CHECK:STDOUT:       {kind: 'VariableIntroducer', text: 'var'},
+// CHECK:STDOUT:           {kind: 'IdentifierNameNotBeforeParams', text: 'x'},
+// CHECK:STDOUT:           {kind: 'CppNameExpr', text: 'Cpp'},
+// CHECK:STDOUT:         {kind: 'VarBindingPattern', text: ':', subtree_size: 3},
+// CHECK:STDOUT:       {kind: 'VariablePattern', text: 'var', subtree_size: 4},
+// CHECK:STDOUT:     {kind: 'VariableDecl', text: ';', subtree_size: 6},
+// CHECK:STDOUT:     {kind: 'FileEnd', text: ''},
+// CHECK:STDOUT:   ]

+ 7 - 5
toolchain/parse/typed_nodes.h

@@ -203,13 +203,13 @@ struct DeclName {
 // Library, package, import, export
 // --------------------------------
 
-// The `package` keyword in an expression.
-using PackageExpr =
-    LeafNode<NodeKind::PackageExpr, Lex::PackageTokenIndex, NodeCategory::Expr>;
-
-// The `Core` keyword in an expression.
+// Various keywords in an expression.
 using CoreNameExpr =
     LeafNode<NodeKind::CoreNameExpr, Lex::CoreTokenIndex, NodeCategory::Expr>;
+using CppNameExpr =
+    LeafNode<NodeKind::CppNameExpr, Lex::CppTokenIndex, NodeCategory::Expr>;
+using PackageExpr =
+    LeafNode<NodeKind::PackageExpr, Lex::PackageTokenIndex, NodeCategory::Expr>;
 
 // The name of a package or library for `package`, `import`, and `library`.
 using IdentifierPackageName =
@@ -217,6 +217,8 @@ using IdentifierPackageName =
              NodeCategory::PackageName>;
 using CorePackageName = LeafNode<NodeKind::CorePackageName, Lex::CoreTokenIndex,
                                  NodeCategory::PackageName>;
+using CppPackageName = LeafNode<NodeKind::CppPackageName, Lex::CppTokenIndex,
+                                NodeCategory::PackageName>;
 using LibraryName =
     LeafNode<NodeKind::LibraryName, Lex::StringLiteralTokenIndex>;
 using DefaultLibrary =

+ 1 - 4
toolchain/sem_ir/formatter.cpp

@@ -1255,10 +1255,7 @@ auto Formatter::FormatImportCppDeclRhs() -> void {
   OpenBrace();
   for (const Parse::Tree::PackagingNames& import :
        sem_ir_->parse_tree().imports()) {
-    if (auto package_ident_id = import.package_id.AsIdentifierId();
-        !package_ident_id.has_value() ||
-        sem_ir_->identifiers().Get(package_ident_id) !=
-            PackageNameId::CppName) {
+    if (import.package_id != PackageNameId::Cpp) {
       continue;
     }
 

+ 2 - 0
toolchain/sem_ir/ids.cpp

@@ -162,6 +162,8 @@ auto NameId::ForPackageName(PackageNameId id) -> NameId {
     return ForIdentifier(identifier_id);
   } else if (id == PackageNameId::Core) {
     return NameId::Core;
+  } else if (id == PackageNameId::Cpp) {
+    return NameId::Cpp;
   } else if (!id.has_value()) {
     return NameId::None;
   } else {

+ 2 - 0
toolchain/sem_ir/ids.h

@@ -582,6 +582,8 @@ constexpr FloatKind FloatKind::PPCFloat128 = FloatKind(6);
   X(ChoiceDiscriminant)                                          \
   /* The name of the package `Core`. */                          \
   X(Core)                                                        \
+  /* The name of the package `Cpp`. */                           \
+  X(Cpp)                                                         \
   /* The name of `package`. */                                   \
   X(PackageNamespace)                                            \
   /* The name of `.Self`. */                                     \

+ 2 - 0
toolchain/sem_ir/name.cpp

@@ -23,6 +23,8 @@ static auto GetSpecialName(NameId name_id, bool for_ir) -> llvm::StringRef {
       return "discriminant";
     case NameId::SpecialNameId::Core:
       return "Core";
+    case NameId::SpecialNameId::Cpp:
+      return "Cpp";
     case NameId::SpecialNameId::PackageNamespace:
       return "package";
     case NameId::SpecialNameId::PeriodSelf: