From 2947877518c35c743a4f1cb0dd08894b681bace4 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 8 Aug 2023 14:55:32 -0700 Subject: [PATCH] Add support for dereference operator. (#3066) Also fix a couple of error-recovery issues exposed by the tests for this change. --- toolchain/diagnostics/diagnostic_kind.def | 2 + toolchain/lowering/lowering_handle.cpp | 6 ++ .../lowering/testdata/pointer/basic.carbon | 20 +++-- toolchain/semantics/semantics_context.cpp | 8 +- .../semantics/semantics_handle_operator.cpp | 32 +++++++- toolchain/semantics/semantics_ir.cpp | 3 + toolchain/semantics/semantics_node.h | 3 + toolchain/semantics/semantics_node_kind.def | 1 + .../operators/fail_type_mismatch.carbon | 2 +- .../operators/fail_type_mismatch_once.carbon | 4 +- .../testdata/pointer/address_of_deref.carbon | 62 +++++++++++++++ .../semantics/testdata/pointer/basic.carbon | 8 +- .../fail_dereference_not_pointer.carbon | 79 +++++++++++++++++++ .../pointer/fail_dereference_type.carbon | 45 +++++++++++ .../testdata/pointer/nested_const.carbon | 72 +++++++++++++++++ 15 files changed, 326 insertions(+), 21 deletions(-) create mode 100644 toolchain/semantics/testdata/pointer/address_of_deref.carbon create mode 100644 toolchain/semantics/testdata/pointer/fail_dereference_not_pointer.carbon create mode 100644 toolchain/semantics/testdata/pointer/fail_dereference_type.carbon create mode 100644 toolchain/semantics/testdata/pointer/nested_const.carbon diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index a39ce494c7b8..ede81a3e2334 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -98,6 +98,8 @@ CARBON_DIAGNOSTIC_KIND(SemanticsTodo) CARBON_DIAGNOSTIC_KIND(AddressOfEphemeralReference) CARBON_DIAGNOSTIC_KIND(AddressOfNonReference) +CARBON_DIAGNOSTIC_KIND(DereferenceOfNonPointer) +CARBON_DIAGNOSTIC_KIND(DereferenceOfType) CARBON_DIAGNOSTIC_KIND(NameNotFound) CARBON_DIAGNOSTIC_KIND(NameDeclarationDuplicate) CARBON_DIAGNOSTIC_KIND(NameDeclarationPrevious) diff --git a/toolchain/lowering/lowering_handle.cpp b/toolchain/lowering/lowering_handle.cpp index ebea588284d7..1e68bd89745c 100644 --- a/toolchain/lowering/lowering_handle.cpp +++ b/toolchain/lowering/lowering_handle.cpp @@ -142,6 +142,12 @@ auto LoweringHandleCall(LoweringFunctionContext& context, } } +auto LoweringHandleDereference(LoweringFunctionContext& context, + SemanticsNodeId node_id, SemanticsNode node) + -> void { + context.SetLocal(node_id, context.GetLocal(node.GetAsDereference())); +} + auto LoweringHandleFunctionDeclaration(LoweringFunctionContext& /*context*/, SemanticsNodeId /*node_id*/, SemanticsNode node) -> void { diff --git a/toolchain/lowering/testdata/pointer/basic.carbon b/toolchain/lowering/testdata/pointer/basic.carbon index e5565ff378f0..d3c94a24572d 100644 --- a/toolchain/lowering/testdata/pointer/basic.carbon +++ b/toolchain/lowering/testdata/pointer/basic.carbon @@ -4,23 +4,27 @@ // // AUTOUPDATE -fn G(p: i32*); +fn G(p: i32*) -> i32 { + // TODO: The LLVM IR generated here is wrong, missing a load. + return *p; +} -fn F() { +fn F() -> i32 { var n: i32 = 0; - G(&n); + return G(&n); } // CHECK:STDOUT: ; ModuleID = 'basic.carbon' // CHECK:STDOUT: source_filename = "basic.carbon" // CHECK:STDOUT: -// CHECK:STDOUT: declare void @G(ptr) +// CHECK:STDOUT: define i32 @G(ptr %p) { +// CHECK:STDOUT: ret ptr %p +// CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: define void @F() { +// CHECK:STDOUT: define i32 @F() { // CHECK:STDOUT: %var = alloca i32, align 4 // CHECK:STDOUT: store i32 0, ptr %var, align 4 // CHECK:STDOUT: %1 = load ptr, ptr %var, align 8 -// CHECK:STDOUT: call void @G(ptr %1) -// CHECK:STDOUT: %TupleLiteralValue = alloca {}, align 8 -// CHECK:STDOUT: ret void +// CHECK:STDOUT: %G = call i32 @G(ptr %1) +// CHECK:STDOUT: ret i32 %G // CHECK:STDOUT: } diff --git a/toolchain/semantics/semantics_context.cpp b/toolchain/semantics/semantics_context.cpp index 9dc191e9748c..1779d0696c47 100644 --- a/toolchain/semantics/semantics_context.cpp +++ b/toolchain/semantics/semantics_context.cpp @@ -360,7 +360,11 @@ auto SemanticsContext::ImplicitAsImpl(SemanticsNodeId value_id, auto value = semantics_ir_->GetNode(value_id); auto value_type_id = value.type_id(); if (value_type_id == SemanticsTypeId::Error) { - return ImplicitAsKind::Identical; + // Although the source type is invalid, this still changes the value. + if (output_value_id != nullptr) { + *output_value_id = SemanticsNodeId::BuiltinError; + } + return ImplicitAsKind::Compatible; } if (as_type_id == SemanticsTypeId::Error) { @@ -603,7 +607,7 @@ auto SemanticsContext::GetPointerType(ParseTree::Node parse_node, auto SemanticsContext::GetUnqualifiedType(SemanticsTypeId type_id) -> SemanticsTypeId { SemanticsNode type_node = - semantics_ir_->GetNode(semantics_ir_->GetType(type_id)); + semantics_ir_->GetNode(semantics_ir_->GetTypeAllowBuiltinTypes(type_id)); if (type_node.kind() == SemanticsNodeKind::ConstType) return type_node.GetAsConstType(); return type_id; diff --git a/toolchain/semantics/semantics_handle_operator.cpp b/toolchain/semantics/semantics_handle_operator.cpp index bb7cfa385e17..31626334f615 100644 --- a/toolchain/semantics/semantics_handle_operator.cpp +++ b/toolchain/semantics/semantics_handle_operator.cpp @@ -150,8 +150,36 @@ auto SemanticsHandlePrefixOperator(SemanticsContext& context, value_id)); return true; - case TokenKind::Star: - return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind)); + case TokenKind::Star: { + auto type_id = context.GetUnqualifiedType( + context.semantics_ir().GetNode(value_id).type_id()); + auto type_node = context.semantics_ir().GetNode( + context.semantics_ir().GetTypeAllowBuiltinTypes(type_id)); + auto result_type_id = SemanticsTypeId::Error; + if (type_node.kind() == SemanticsNodeKind::PointerType) { + result_type_id = type_node.GetAsPointerType(); + } else { + CARBON_DIAGNOSTIC( + DereferenceOfNonPointer, Error, + "Cannot dereference operand of non-pointer type `{0}`.", + std::string); + auto builder = context.emitter().Build( + parse_node, DereferenceOfNonPointer, + context.semantics_ir().StringifyType(type_id)); + // TODO: Check for any facet here, rather than only a type. + if (type_id == SemanticsTypeId::TypeType) { + CARBON_DIAGNOSTIC( + DereferenceOfType, Note, + "To form a pointer type, write the `*` after the pointee type."); + builder.Note(parse_node, DereferenceOfType); + } + builder.Emit(); + } + context.AddNodeAndPush(parse_node, + SemanticsNode::Dereference::Make( + parse_node, result_type_id, value_id)); + return true; + } default: return context.TODO(parse_node, llvm::formatv("Handle {0}", token_kind)); diff --git a/toolchain/semantics/semantics_ir.cpp b/toolchain/semantics/semantics_ir.cpp index cfe333f97c1e..2301160002e2 100644 --- a/toolchain/semantics/semantics_ir.cpp +++ b/toolchain/semantics/semantics_ir.cpp @@ -227,6 +227,7 @@ static auto GetTypePrecedence(SemanticsNodeKind kind) -> int { case SemanticsNodeKind::BranchIf: case SemanticsNodeKind::BranchWithArg: case SemanticsNodeKind::Call: + case SemanticsNodeKind::Dereference: case SemanticsNodeKind::FunctionDeclaration: case SemanticsNodeKind::Index: case SemanticsNodeKind::IntegerLiteral: @@ -368,6 +369,7 @@ auto SemanticsIR::StringifyType(SemanticsTypeId type_id) -> std::string { case SemanticsNodeKind::BranchWithArg: case SemanticsNodeKind::Builtin: case SemanticsNodeKind::Call: + case SemanticsNodeKind::Dereference: case SemanticsNodeKind::CrossReference: case SemanticsNodeKind::FunctionDeclaration: case SemanticsNodeKind::Index: @@ -481,6 +483,7 @@ auto GetSemanticsExpressionCategory(const SemanticsIR& semantics_ir, // struct/tuple value construction. return SemanticsExpressionCategory::Value; + case SemanticsNodeKind::Dereference: case SemanticsNodeKind::VarStorage: return SemanticsExpressionCategory::DurableReference; } diff --git a/toolchain/semantics/semantics_node.h b/toolchain/semantics/semantics_node.h index 98d6bcf33108..a21305920a26 100644 --- a/toolchain/semantics/semantics_node.h +++ b/toolchain/semantics/semantics_node.h @@ -379,6 +379,9 @@ class SemanticsNode { using FactoryBase::Get; }; + using Dereference = + Factory; + using FunctionDeclaration = FactoryNoType; diff --git a/toolchain/semantics/semantics_node_kind.def b/toolchain/semantics/semantics_node_kind.def index 5f1387bd5251..c1a33457b6f4 100644 --- a/toolchain/semantics/semantics_node_kind.def +++ b/toolchain/semantics/semantics_node_kind.def @@ -39,6 +39,7 @@ CARBON_SEMANTICS_NODE_KIND_WITH_TERMINATOR_KIND(BranchWithArg, Terminator) CARBON_SEMANTICS_NODE_KIND(Builtin) CARBON_SEMANTICS_NODE_KIND(Call) CARBON_SEMANTICS_NODE_KIND(ConstType) +CARBON_SEMANTICS_NODE_KIND(Dereference) CARBON_SEMANTICS_NODE_KIND(FunctionDeclaration) CARBON_SEMANTICS_NODE_KIND(Index) CARBON_SEMANTICS_NODE_KIND(IntegerLiteral) diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon index eefcb156d66d..0986566d4337 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch.carbon @@ -35,7 +35,7 @@ fn Main() -> i32 { // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0}, // CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type1}, // CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: nodeError, arg1: node+2, type: typeError}, -// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+3}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: nodeError}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ diff --git a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon index 74a4c1027512..8f67cb86d4ac 100644 --- a/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon +++ b/toolchain/semantics/testdata/operators/fail_type_mismatch_once.carbon @@ -39,8 +39,8 @@ fn Main() -> i32 { // CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type1}, // CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: nodeError, arg1: node+2, type: typeError}, // CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0}, -// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: node+3, arg1: node+4, type: typeError}, -// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+5}, +// CHECK:STDOUT: {kind: BinaryOperatorAdd, arg0: nodeError, arg1: node+4, type: typeError}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: nodeError}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ // CHECK:STDOUT: [ diff --git a/toolchain/semantics/testdata/pointer/address_of_deref.carbon b/toolchain/semantics/testdata/pointer/address_of_deref.carbon new file mode 100644 index 000000000000..1e6a0f30cdb5 --- /dev/null +++ b/toolchain/semantics/testdata/pointer/address_of_deref.carbon @@ -0,0 +1,62 @@ +// 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 + +fn F() -> i32 { + var n: i32 = 0; + return *&*&n; +} + +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: [ +// CHECK:STDOUT: {name: str0, param_refs: block0, return_type: type0, body: {block2}}}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 0, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: F, +// CHECK:STDOUT: n, +// CHECK:STDOUT: ] +// CHECK:STDOUT: types: [ +// CHECK:STDOUT: nodeIntegerType, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: ] +// CHECK:STDOUT: type_blocks: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0}, +// CHECK:STDOUT: {kind: VarStorage, type: type0}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+1, type: type0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0}, +// CHECK:STDOUT: {kind: Assign, arg0: node+1, arg1: node+3}, +// CHECK:STDOUT: {kind: PointerType, arg0: type0, type: typeTypeType}, +// CHECK:STDOUT: {kind: AddressOf, arg0: node+1, type: type1}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+6, type: type0}, +// CHECK:STDOUT: {kind: AddressOf, arg0: node+7, type: type1}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+8, type: type0}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+9}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/pointer/basic.carbon b/toolchain/semantics/testdata/pointer/basic.carbon index 837c18503103..e2f48282866b 100644 --- a/toolchain/semantics/testdata/pointer/basic.carbon +++ b/toolchain/semantics/testdata/pointer/basic.carbon @@ -8,10 +8,7 @@ fn F() -> i32 { var n: i32 = 0; var p: i32* = &n; - // TODO: Dereference. - // return *p; - - return 0; + return *p; } // CHECK:STDOUT: cross_reference_irs_size: 1 @@ -20,7 +17,6 @@ fn F() -> i32 { // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 0, -// CHECK:STDOUT: 0, // CHECK:STDOUT: ] // CHECK:STDOUT: real_literals: [ // CHECK:STDOUT: ] @@ -46,7 +42,7 @@ fn F() -> i32 { // CHECK:STDOUT: {kind: BindName, arg0: str2, arg1: node+6, type: type1}, // CHECK:STDOUT: {kind: AddressOf, arg0: node+1, type: type1}, // CHECK:STDOUT: {kind: Assign, arg0: node+6, arg1: node+8}, -// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+6, type: type0}, // CHECK:STDOUT: {kind: ReturnExpression, arg0: node+10}, // CHECK:STDOUT: ] // CHECK:STDOUT: node_blocks: [ diff --git a/toolchain/semantics/testdata/pointer/fail_dereference_not_pointer.carbon b/toolchain/semantics/testdata/pointer/fail_dereference_not_pointer.carbon new file mode 100644 index 000000000000..fdb25ec39acf --- /dev/null +++ b/toolchain/semantics/testdata/pointer/fail_dereference_not_pointer.carbon @@ -0,0 +1,79 @@ +// 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 + +fn Deref(n: i32) { + // CHECK:STDERR: fail_dereference_not_pointer.carbon:[[@LINE+3]]:3: Cannot dereference operand of non-pointer type `i32`. + // CHECK:STDERR: *n; + // CHECK:STDERR: ^ + *n; + // CHECK:STDERR: fail_dereference_not_pointer.carbon:[[@LINE+3]]:3: Cannot dereference operand of non-pointer type `() as type`. + // CHECK:STDERR: *(); + // CHECK:STDERR: ^ + *(); + // CHECK:STDERR: fail_dereference_not_pointer.carbon:[[@LINE+3]]:3: Cannot dereference operand of non-pointer type `{} as type`. + // CHECK:STDERR: *{}; + // CHECK:STDERR: ^ + *{}; +} + +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: [ +// CHECK:STDOUT: {name: str0, param_refs: block2, body: {block4}}}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: Deref, +// CHECK:STDOUT: n, +// CHECK:STDOUT: ] +// CHECK:STDOUT: types: [ +// CHECK:STDOUT: nodeIntegerType, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: ] +// CHECK:STDOUT: type_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: VarStorage, type: type0}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+0, type: type0}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+0, type: typeError}, +// CHECK:STDOUT: {kind: TupleType, arg0: typeBlock0, type: typeTypeType}, +// CHECK:STDOUT: {kind: TupleValue, arg0: block0, type: type1}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+5, type: typeError}, +// CHECK:STDOUT: {kind: StructType, arg0: block0, type: typeTypeType}, +// CHECK:STDOUT: {kind: StructValue, arg0: block0, type: type2}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+8, type: typeError}, +// CHECK:STDOUT: {kind: Return}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/pointer/fail_dereference_type.carbon b/toolchain/semantics/testdata/pointer/fail_dereference_type.carbon new file mode 100644 index 000000000000..e0ea3aa9783c --- /dev/null +++ b/toolchain/semantics/testdata/pointer/fail_dereference_type.carbon @@ -0,0 +1,45 @@ +// 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 + +// CHECK:STDERR: fail_dereference_type.carbon:[[@LINE+9]]:8: Parentheses are required around this unary `*` operator. +// CHECK:STDERR: var p: *i32; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_dereference_type.carbon:[[@LINE+6]]:8: Cannot dereference operand of non-pointer type `type`. +// CHECK:STDERR: var p: *i32; +// CHECK:STDERR: ^ +// CHECK:STDERR: fail_dereference_type.carbon:[[@LINE+3]]:8: To form a pointer type, write the `*` after the pointee type. +// CHECK:STDERR: var p: *i32; +// CHECK:STDERR: ^ +var p: *i32; + +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: p, +// CHECK:STDOUT: ] +// CHECK:STDOUT: types: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: type_blocks: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: Dereference, arg0: nodeIntegerType, type: typeError}, +// CHECK:STDOUT: {kind: VarStorage, type: typeError}, +// CHECK:STDOUT: {kind: BindName, arg0: str0, arg1: node+1, type: typeError}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] diff --git a/toolchain/semantics/testdata/pointer/nested_const.carbon b/toolchain/semantics/testdata/pointer/nested_const.carbon new file mode 100644 index 000000000000..46738c346b5c --- /dev/null +++ b/toolchain/semantics/testdata/pointer/nested_const.carbon @@ -0,0 +1,72 @@ +// 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 + +// TODO: The `const` in the return type should not be necessary. +fn F(p: const (const (const i32*)*)) -> const i32 { + return **p; +} + +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: [ +// CHECK:STDOUT: {name: str0, param_refs: block2, return_type: type1, body: {block4}}}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: F, +// CHECK:STDOUT: p, +// CHECK:STDOUT: ] +// CHECK:STDOUT: types: [ +// CHECK:STDOUT: nodeIntegerType, +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: ] +// CHECK:STDOUT: type_blocks: [ +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: ConstType, arg0: type0, type: typeTypeType}, +// CHECK:STDOUT: {kind: PointerType, arg0: type1, type: typeTypeType}, +// CHECK:STDOUT: {kind: ConstType, arg0: type2, type: typeTypeType}, +// CHECK:STDOUT: {kind: PointerType, arg0: type3, type: typeTypeType}, +// CHECK:STDOUT: {kind: ConstType, arg0: type4, type: typeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, type: type5}, +// CHECK:STDOUT: {kind: BindName, arg0: str1, arg1: node+5, type: type5}, +// CHECK:STDOUT: {kind: ConstType, arg0: type0, type: typeTypeType}, +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+5, type: type3}, +// CHECK:STDOUT: {kind: Dereference, arg0: node+9, type: type1}, +// CHECK:STDOUT: {kind: ReturnExpression, arg0: node+10}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ]