Commit 6769183a9d

Andrew Kelley <andrew@ziglang.org>
2019-02-14 21:48:28
fix implicit cast error unions with non-optional to optional pointer
and update self hosted compiler for C pointers See #1059
1 parent 52c03de
doc/docgen.zig
@@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
             std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
             std.zig.Token.Id.Tilde,
             std.zig.Token.Id.BracketStarBracket,
+            std.zig.Token.Id.BracketStarCBracket,
             => try writeEscaped(out, src[token.start..token.end]),
 
             std.zig.Token.Id.Invalid => return parseError(
src/ir.cpp
@@ -8696,7 +8696,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
             return result;
         }
         bool ok_allows_zero = (wanted_allows_zero &&
-                (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) ||
+                (actual_allows_zero || !wanted_is_mutable)) ||
             (!wanted_allows_zero && !actual_allows_zero);
         if (!ok_allows_zero) {
             result.id = ConstCastResultIdBadAllowsZero;
src-self-hosted/codegen.zig
@@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
 
 pub const ObjectFile = struct {
     comp: *Compilation,
-    module: llvm.ModuleRef,
-    builder: llvm.BuilderRef,
+    module: *llvm.Module,
+    builder: *llvm.Builder,
     dibuilder: *llvm.DIBuilder,
-    context: llvm.ContextRef,
+    context: *llvm.Context,
     lock: event.Lock,
     arena: *std.mem.Allocator,
 
@@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
 
 fn addLLVMAttr(
     ofile: *ObjectFile,
-    val: llvm.ValueRef,
+    val: *llvm.Value,
     attr_index: llvm.AttributeIndex,
     attr_name: []const u8,
 ) !void {
@@ -335,7 +335,7 @@ fn addLLVMAttr(
 
 fn addLLVMAttrStr(
     ofile: *ObjectFile,
-    val: llvm.ValueRef,
+    val: *llvm.Value,
     attr_index: llvm.AttributeIndex,
     attr_name: []const u8,
     attr_val: []const u8,
@@ -351,7 +351,7 @@ fn addLLVMAttrStr(
 }
 
 fn addLLVMAttrInt(
-    val: llvm.ValueRef,
+    val: *llvm.Value,
     attr_index: llvm.AttributeIndex,
     attr_name: []const u8,
     attr_val: u64,
@@ -362,25 +362,25 @@ fn addLLVMAttrInt(
     llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
 }
 
-fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
+fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void {
     return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name);
 }
 
-fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
+fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void {
     return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
 }
 
-fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
+fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void {
     return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
 }
 
 fn renderLoadUntyped(
     ofile: *ObjectFile,
-    ptr: llvm.ValueRef,
+    ptr: *llvm.Value,
     alignment: Type.Pointer.Align,
     vol: Type.Pointer.Vol,
     name: [*]const u8,
-) !llvm.ValueRef {
+) !*llvm.Value {
     const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
     switch (vol) {
         Type.Pointer.Vol.Non => {},
@@ -390,11 +390,11 @@ fn renderLoadUntyped(
     return result;
 }
 
-fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
+fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {
     return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
 }
 
-pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
+pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value {
     const child_type = ptr_type.key.child_type;
     if (!child_type.hasBits()) {
         return null;
@@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
 
 pub fn renderStoreUntyped(
     ofile: *ObjectFile,
-    value: llvm.ValueRef,
-    ptr: llvm.ValueRef,
+    value: *llvm.Value,
+    ptr: *llvm.Value,
     alignment: Type.Pointer.Align,
     vol: Type.Pointer.Vol,
-) !llvm.ValueRef {
+) !*llvm.Value {
     const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
     switch (vol) {
         Type.Pointer.Vol.Non => {},
@@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
 
 pub fn renderStore(
     ofile: *ObjectFile,
-    value: llvm.ValueRef,
-    ptr: llvm.ValueRef,
+    value: *llvm.Value,
+    ptr: *llvm.Value,
     ptr_type: *Type.Pointer,
-) !llvm.ValueRef {
+) !*llvm.Value {
     return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
 }
 
@@ -435,7 +435,7 @@ pub fn renderAlloca(
     var_type: *Type,
     name: []const u8,
     alignment: Type.Pointer.Align,
-) !llvm.ValueRef {
+) !*llvm.Value {
     const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
     const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
     const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
@@ -443,7 +443,7 @@ pub fn renderAlloca(
     return result;
 }
 
-pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
+pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 {
     return switch (alignment) {
         Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
         Type.Pointer.Align.Override => |a| a,
src-self-hosted/compilation.zig
@@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
 /// Data that is local to the event loop.
 pub const ZigCompiler = struct {
     loop: *event.Loop,
-    llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
+    llvm_handle_pool: std.atomic.Stack(*llvm.Context),
     lld_lock: event.Lock,
 
     /// TODO pool these so that it doesn't have to lock
@@ -60,7 +60,7 @@ pub const ZigCompiler = struct {
         return ZigCompiler{
             .loop = loop,
             .lld_lock = event.Lock.init(loop),
-            .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
+            .llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(),
             .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
             .native_libc = event.Future(LibCInstallation).init(loop),
         };
@@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
     fn deinit(self: *ZigCompiler) void {
         self.lld_lock.deinit();
         while (self.llvm_handle_pool.pop()) |node| {
-            c.LLVMContextDispose(node.data);
+            llvm.ContextDispose(node.data);
             self.loop.allocator.destroy(node);
         }
     }
@@ -80,11 +80,11 @@ pub const ZigCompiler = struct {
     pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
         if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
 
-        const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
-        errdefer c.LLVMContextDispose(context_ref);
+        const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
+        errdefer llvm.ContextDispose(context_ref);
 
-        const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node);
-        node.* = std.atomic.Stack(llvm.ContextRef).Node{
+        const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
+        node.* = std.atomic.Stack(*llvm.Context).Node{
             .next = undefined,
             .data = context_ref,
         };
@@ -114,7 +114,7 @@ pub const ZigCompiler = struct {
 };
 
 pub const LlvmHandle = struct {
-    node: *std.atomic.Stack(llvm.ContextRef).Node,
+    node: *std.atomic.Stack(*llvm.Context).Node,
 
     pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void {
         zig_compiler.llvm_handle_pool.push(self.node);
@@ -128,7 +128,7 @@ pub const Compilation = struct {
     llvm_triple: Buffer,
     root_src_path: ?[]const u8,
     target: Target,
-    llvm_target: llvm.TargetRef,
+    llvm_target: *llvm.Target,
     build_mode: builtin.Mode,
     zig_lib_dir: []const u8,
     zig_std_dir: []const u8,
@@ -212,8 +212,8 @@ pub const Compilation = struct {
     false_value: *Value.Bool,
     noreturn_value: *Value.NoReturn,
 
-    target_machine: llvm.TargetMachineRef,
-    target_data_ref: llvm.TargetDataRef,
+    target_machine: *llvm.TargetMachine,
+    target_data_ref: *llvm.TargetData,
     target_layout_str: [*]u8,
     target_ptr_bits: u32,
 
src-self-hosted/ir.zig
@@ -67,7 +67,7 @@ pub const Inst = struct {
     parent: ?*Inst,
 
     /// populated durign codegen
-    llvm_value: ?llvm.ValueRef,
+    llvm_value: ?*llvm.Value,
 
     pub fn cast(base: *Inst, comptime T: type) ?*T {
         if (base.id == comptime typeToId(T)) {
@@ -129,7 +129,7 @@ pub const Inst = struct {
         }
     }
 
-    pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
+    pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) {
         switch (base.id) {
             Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
             Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
@@ -313,10 +313,10 @@ pub const Inst = struct {
             return new_inst;
         }
 
-        pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
+        pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
             const fn_ref = self.params.fn_ref.llvm_value.?;
 
-            const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
+            const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len);
             for (self.params.args) |arg, i| {
                 args[i] = arg.llvm_value.?;
             }
@@ -360,7 +360,7 @@ pub const Inst = struct {
             return new_inst;
         }
 
-        pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
+        pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
             return self.base.val.KnownValue.getLlvmConst(ofile);
         }
     };
@@ -392,7 +392,7 @@ pub const Inst = struct {
             return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
         }
 
-        pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
+        pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
             const value = self.params.return_value.llvm_value;
             const return_type = self.params.return_value.getKnownType();
 
@@ -540,7 +540,7 @@ pub const Inst = struct {
             }
         }
 
-        pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
+        pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value {
             switch (self.params.var_scope.data) {
                 Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
                 Scope.Var.Data.Param => |param| return param.llvm_value,
@@ -596,7 +596,7 @@ pub const Inst = struct {
             return new_inst;
         }
 
-        pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
+        pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
             const child_type = self.base.getKnownType();
             if (!child_type.hasBits()) {
                 return null;
@@ -935,8 +935,8 @@ pub const BasicBlock = struct {
     ref_instruction: ?*Inst,
 
     /// for codegen
-    llvm_block: llvm.BasicBlockRef,
-    llvm_exit_block: llvm.BasicBlockRef,
+    llvm_block: *llvm.BasicBlock,
+    llvm_exit_block: *llvm.BasicBlock,
 
     /// the basic block that is derived from this one in analysis
     child: ?*BasicBlock,
src-self-hosted/llvm.zig
@@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
 pub const AttributeIndex = c_uint;
 pub const Bool = c_int;
 
-pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
-pub const ContextRef = removeNullability(c.LLVMContextRef);
-pub const ModuleRef = removeNullability(c.LLVMModuleRef);
-pub const ValueRef = removeNullability(c.LLVMValueRef);
-pub const TypeRef = removeNullability(c.LLVMTypeRef);
-pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
-pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
-pub const TargetRef = removeNullability(c.LLVMTargetRef);
-pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
-pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
+pub const Builder = c.LLVMBuilderRef.Child;
+pub const Context = c.LLVMContextRef.Child;
+pub const Module = c.LLVMModuleRef.Child;
+pub const Value = c.LLVMValueRef.Child;
+pub const Type = c.LLVMTypeRef.Child;
+pub const BasicBlock = c.LLVMBasicBlockRef.Child;
+pub const Attribute = c.LLVMAttributeRef.Child;
+pub const Target = c.LLVMTargetRef.Child;
+pub const TargetMachine = c.LLVMTargetMachineRef.Child;
+pub const TargetData = c.LLVMTargetDataRef.Child;
 pub const DIBuilder = c.ZigLLVMDIBuilder;
+pub const DIFile = c.ZigLLVMDIFile;
+pub const DICompileUnit = c.ZigLLVMDICompileUnit;
 
 pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
 pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
-pub const AddFunction = c.LLVMAddFunction;
-pub const AddGlobal = c.LLVMAddGlobal;
 pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
 pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
-pub const ArrayType = c.LLVMArrayType;
-pub const BuildLoad = c.LLVMBuildLoad;
 pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
 pub const ConstAllOnes = c.LLVMConstAllOnes;
 pub const ConstArray = c.LLVMConstArray;
 pub const ConstBitCast = c.LLVMConstBitCast;
-pub const ConstInt = c.LLVMConstInt;
 pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
 pub const ConstNeg = c.LLVMConstNeg;
-pub const ConstNull = c.LLVMConstNull;
-pub const ConstStringInContext = c.LLVMConstStringInContext;
 pub const ConstStructInContext = c.LLVMConstStructInContext;
-pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
-pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
-pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
-pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
-pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
-pub const CreateFile = c.ZigLLVMCreateFile;
-pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
-pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
-pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
 pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
 pub const DisposeBuilder = c.LLVMDisposeBuilder;
 pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
@@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
 pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
 pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
 pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
-pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
 pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
-pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
 pub const GetUndef = c.LLVMGetUndef;
 pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
 pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
@@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
 pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
 pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
 pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
-pub const IntTypeInContext = c.LLVMIntTypeInContext;
 pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
 pub const MDNodeInContext = c.LLVMMDNodeInContext;
 pub const MDStringInContext = c.LLVMMDStringInContext;
 pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
-pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
 pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
-pub const PointerType = c.LLVMPointerType;
 pub const SetAlignment = c.LLVMSetAlignment;
 pub const SetDataLayout = c.LLVMSetDataLayout;
 pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
@@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
 pub const SetVolatile = c.LLVMSetVolatile;
 pub const StructTypeInContext = c.LLVMStructTypeInContext;
 pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
-pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
 pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
 pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
 
+pub const AddGlobal = LLVMAddGlobal;
+extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
+
+pub const ConstStringInContext = LLVMConstStringInContext;
+extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
+
+pub const ConstInt = LLVMConstInt;
+extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
+
+pub const BuildLoad = LLVMBuildLoad;
+extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
+
+pub const ConstNull = LLVMConstNull;
+extern fn LLVMConstNull(Ty: *Type) ?*Value;
+
+pub const CreateStringAttribute = LLVMCreateStringAttribute;
+extern fn LLVMCreateStringAttribute(
+    C: *Context,
+    K: [*]const u8,
+    KLength: c_uint,
+    V: [*]const u8,
+    VLength: c_uint,
+) ?*Attribute;
+
+pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
+extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
+
+pub const AddFunction = LLVMAddFunction;
+extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
+
+pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
+extern fn ZigLLVMCreateCompileUnit(
+    dibuilder: *DIBuilder,
+    lang: c_uint,
+    difile: *DIFile,
+    producer: [*]const u8,
+    is_optimized: bool,
+    flags: [*]const u8,
+    runtime_version: c_uint,
+    split_name: [*]const u8,
+    dwo_id: u64,
+    emit_debug_info: bool,
+) ?*DICompileUnit;
+
+pub const CreateFile = ZigLLVMCreateFile;
+extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
+
+pub const ArrayType = LLVMArrayType;
+extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
+
+pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
+extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
+
+pub const PointerType = LLVMPointerType;
+extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
+
+pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
+extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
+
+pub const IntTypeInContext = LLVMIntTypeInContext;
+extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
+
+pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
+extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
+
+pub const VoidTypeInContext = LLVMVoidTypeInContext;
+extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
+
+pub const ContextCreate = LLVMContextCreate;
+extern fn LLVMContextCreate() ?*Context;
+
+pub const ContextDispose = LLVMContextDispose;
+extern fn LLVMContextDispose(C: *Context) void;
+
+pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
+extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
+
+pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
+extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
+
+pub const CreateTargetMachine = LLVMCreateTargetMachine;
+extern fn LLVMCreateTargetMachine(
+    T: *Target,
+    Triple: [*]const u8,
+    CPU: [*]const u8,
+    Features: [*]const u8,
+    Level: CodeGenOptLevel,
+    Reloc: RelocMode,
+    CodeModel: CodeModel,
+) ?*TargetMachine;
+
+pub const GetHostCPUName = LLVMGetHostCPUName;
+extern fn LLVMGetHostCPUName() ?[*]u8;
+
+pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
+extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
+
 pub const GetElementType = LLVMGetElementType;
-extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
+extern fn LLVMGetElementType(Ty: *Type) *Type;
 
 pub const TypeOf = LLVMTypeOf;
-extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
+extern fn LLVMTypeOf(Val: *Value) *Type;
 
 pub const BuildStore = LLVMBuildStore;
-extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
+extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
 
 pub const BuildAlloca = LLVMBuildAlloca;
-extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
+extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
 
 pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
-pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
+pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
 
 pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
-extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
+extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
 
 pub const VerifyModule = LLVMVerifyModule;
-extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
+extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
 
 pub const GetInsertBlock = LLVMGetInsertBlock;
-extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
+extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
 
 pub const FunctionType = LLVMFunctionType;
 extern fn LLVMFunctionType(
-    ReturnType: TypeRef,
-    ParamTypes: [*]TypeRef,
+    ReturnType: *Type,
+    ParamTypes: [*]*Type,
     ParamCount: c_uint,
     IsVarArg: Bool,
-) ?TypeRef;
+) ?*Type;
 
 pub const GetParam = LLVMGetParam;
-extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
+extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
 
 pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
-extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
+extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
 
 pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
-extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
+extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
 
 pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
 pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
@@ -190,17 +267,17 @@ pub const FnInline = extern enum {
 };
 
 fn removeNullability(comptime T: type) type {
-    comptime assert(@typeId(T) == builtin.TypeId.Optional);
-    return T.Child;
+    comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
+    return *T.Child;
 }
 
 pub const BuildRet = LLVMBuildRet;
-extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
+extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
 
 pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
 extern fn ZigLLVMTargetMachineEmitToFile(
-    targ_machine_ref: TargetMachineRef,
-    module_ref: ModuleRef,
+    targ_machine_ref: *TargetMachine,
+    module_ref: *Module,
     filename: [*]const u8,
     output_type: EmitOutputType,
     error_message: *[*]u8,
@@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
 ) bool;
 
 pub const BuildCall = ZigLLVMBuildCall;
-extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
+extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
 
 pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
src-self-hosted/scope.zig
@@ -362,7 +362,7 @@ pub const Scope = struct {
         pub const Param = struct {
             index: usize,
             typ: *Type,
-            llvm_value: llvm.ValueRef,
+            llvm_value: *llvm.Value,
         };
 
         pub fn createParam(
src-self-hosted/target.zig
@@ -457,8 +457,8 @@ pub const Target = union(enum) {
         }
     }
 
-    pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
-        var result: llvm.TargetRef = undefined;
+    pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
+        var result: *llvm.Target = undefined;
         var err_msg: [*]u8 = undefined;
         if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
             std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
src-self-hosted/type.zig
@@ -51,8 +51,8 @@ pub const Type = struct {
     pub fn getLlvmType(
         base: *Type,
         allocator: *Allocator,
-        llvm_context: llvm.ContextRef,
-    ) (error{OutOfMemory}!llvm.TypeRef) {
+        llvm_context: *llvm.Context,
+    ) (error{OutOfMemory}!*llvm.Type) {
         switch (base.id) {
             Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
             Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
@@ -196,7 +196,7 @@ pub const Type = struct {
     }
 
     /// If you have an llvm conext handy, you can use it here.
-    pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
+    pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
         if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
 
         base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
@@ -205,7 +205,7 @@ pub const Type = struct {
     }
 
     /// Lower level function that does the work. See getAbiAlignment.
-    async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
+    async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
         const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
         return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
     }
@@ -218,7 +218,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -496,13 +496,13 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
+        pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
             const normal = &self.key.data.Normal;
             const llvm_return_type = switch (normal.return_type.id) {
                 Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
                 else => try normal.return_type.getLlvmType(allocator, llvm_context),
             };
-            const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
+            const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
             defer allocator.free(llvm_param_types);
             for (llvm_param_types) |*llvm_param_type, i| {
                 llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
@@ -559,7 +559,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -658,7 +658,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
+        pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
             return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
         }
     };
@@ -670,7 +670,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -836,7 +836,7 @@ pub const Type = struct {
             return self;
         }
 
-        pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
+        pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
             const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
             return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
         }
@@ -904,7 +904,7 @@ pub const Type = struct {
             return self;
         }
 
-        pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
+        pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
             const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
             return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
         }
@@ -917,7 +917,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -967,7 +967,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -979,7 +979,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -991,7 +991,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -1003,7 +1003,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -1015,7 +1015,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -1035,7 +1035,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -1055,7 +1055,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
@@ -1067,7 +1067,7 @@ pub const Type = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
+        pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
             @panic("TODO");
         }
     };
src-self-hosted/value.zig
@@ -57,7 +57,7 @@ pub const Value = struct {
         std.debug.warn("{}", @tagName(base.id));
     }
 
-    pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
+    pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) {
         switch (base.id) {
             Id.Type => unreachable,
             Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
@@ -153,7 +153,7 @@ pub const Value = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
+        pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value {
             const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
             const llvm_fn = llvm.AddFunction(
                 ofile.module,
@@ -238,7 +238,7 @@ pub const Value = struct {
         /// We know that the function definition will end up in an .o file somewhere.
         /// Here, all we have to do is generate a global prototype.
         /// TODO cache the prototype per ObjectFile
-        pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
+        pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value {
             const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
             const llvm_fn = llvm.AddFunction(
                 ofile.module,
@@ -283,7 +283,7 @@ pub const Value = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
+        pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?*llvm.Value {
             const llvm_type = llvm.Int1TypeInContext(ofile.context);
             if (self.x) {
                 return llvm.ConstAllOnes(llvm_type);
@@ -381,7 +381,7 @@ pub const Value = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
+        pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value {
             const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
             // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
             switch (self.special) {
@@ -391,7 +391,7 @@ pub const Value = struct {
                     const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
                     const ptr_bit_count = ofile.comp.target_ptr_bits;
                     const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
-                    const indices = []llvm.ValueRef{
+                    const indices = []*llvm.Value{
                         llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
                         llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
                     };
@@ -459,7 +459,7 @@ pub const Value = struct {
             comp.gpa().destroy(self);
         }
 
-        pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
+        pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
             switch (self.special) {
                 Special.Undefined => {
                     const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
@@ -534,7 +534,7 @@ pub const Value = struct {
             return self;
         }
 
-        pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
+        pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value {
             switch (self.base.typ.id) {
                 Type.Id.Int => {
                     const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
std/hash_map.zig
@@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
         builtin.TypeId.Pointer => |info| switch (info.size) {
             builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
             builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
+            builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
             builtin.TypeInfo.Pointer.Size.Slice => {
                 const interval = std.math.max(1, key.len / 256);
                 var i: usize = 0;
@@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
         builtin.TypeId.Pointer => |info| switch (info.size) {
             builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
             builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
+            builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
             builtin.TypeInfo.Pointer.Size.Slice => {
                 if (a.len != b.len) return false;
                 for (a) |a_item, i| {
test/stage1/behavior/pointers.zig
@@ -1,5 +1,6 @@
 const std = @import("std");
 const expect = std.testing.expect;
+const expectError = std.testing.expectError;
 
 test "dereference pointer" {
     comptime testDerefPtr();
@@ -107,3 +108,19 @@ test "implicit casting between C pointer and optional non-C pointer" {
     ptr_opt_many_ptr = c_ptr;
     expect(ptr_opt_many_ptr.*.?[1] == 'o');
 }
+
+test "implicit cast error unions with non-optional to optional pointer" {
+    const S = struct {
+        fn doTheTest() void {
+            expectError(error.Fail, foo());
+        }
+        fn foo() anyerror!?*u8 {
+            return bar() orelse error.Fail;
+        }
+        fn bar() ?*u8 {
+            return null;
+        }
+    };
+    S.doTheTest();
+    comptime S.doTheTest();
+}
test/compile_errors.zig
@@ -92,15 +92,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    var slice: []u8 = &buf;
         \\    var opt_many_ptr: [*]u8 = slice.ptr;
         \\    var ptr_opt_many_ptr = &opt_many_ptr;
-        \\    var c_ptr: [*c]const [*c]u8 = ptr_opt_many_ptr;
+        \\    var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
         \\}
     ,
         ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
         ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
         ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
-        ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'",
-        ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'",
-        ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]u8'",
+        ".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
+        ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
+        ".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
     );
 
     cases.addTest(