@@ -61,7 +61,7 @@ enum ConstCastResultId {
61
61
ConstCastResultIdType,
62
62
ConstCastResultIdUnresolvedInferredErrSet,
63
63
ConstCastResultIdAsyncAllocatorType,
64
- ConstCastResultIdNullWrapPtr
64
+ ConstCastResultIdBadAllowsZero,
65
65
};
66
66
67
67
struct ConstCastOnly;
@@ -83,6 +83,7 @@ struct ConstCastErrUnionErrSetMismatch;
83
83
struct ConstCastErrUnionPayloadMismatch;
84
84
struct ConstCastErrSetMismatch;
85
85
struct ConstCastTypeMismatch;
86
+ struct ConstCastBadAllowsZero;
86
87
87
88
struct ConstCastOnly {
88
89
ConstCastResultId id;
@@ -99,6 +100,7 @@ struct ConstCastOnly {
99
100
ConstCastOnly *null_wrap_ptr_child;
100
101
ConstCastArg fn_arg;
101
102
ConstCastArgNoAlias arg_no_alias;
103
+ ConstCastBadAllowsZero *bad_allows_zero;
102
104
} data;
103
105
};
104
106
@@ -141,6 +143,12 @@ struct ConstCastErrSetMismatch {
141
143
ZigList<ErrorTableEntry *> missing_errors;
142
144
};
143
145
146
+ struct ConstCastBadAllowsZero {
147
+ ZigType *wanted_type;
148
+ ZigType *actual_type;
149
+ };
150
+
151
+
144
152
enum UndefAllowed {
145
153
UndefOk,
146
154
UndefBad,
@@ -8636,6 +8644,14 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
8636
8644
return err_set_type;
8637
8645
}
8638
8646
8647
+ static bool ptr_allows_addr_zero(ZigType *ptr_type) {
8648
+ if (ptr_type->id == ZigTypeIdPointer) {
8649
+ return ptr_type->data.pointer.allow_zero;
8650
+ } else if (ptr_type->id == ZigTypeIdOptional) {
8651
+ return true;
8652
+ }
8653
+ return false;
8654
+ }
8639
8655
8640
8656
static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type,
8641
8657
ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable)
@@ -8649,34 +8665,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
8649
8665
if (wanted_type == actual_type)
8650
8666
return result;
8651
8667
8652
- // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively
8653
- // but not if we want a mutable pointer
8654
- // and not if the actual pointer has zero bits
8655
- if (!wanted_is_mutable && wanted_type->id == ZigTypeIdOptional &&
8656
- wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&
8657
- actual_type->id == ZigTypeIdPointer && type_has_bits(actual_type))
8658
- {
8659
- ConstCastOnly child = types_match_const_cast_only(ira,
8660
- wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
8661
- if (child.id == ConstCastResultIdInvalid)
8662
- return child;
8663
- if (child.id != ConstCastResultIdOk) {
8664
- result.id = ConstCastResultIdNullWrapPtr;
8665
- result.data.null_wrap_ptr_child = allocate_nonzero<ConstCastOnly>(1);
8666
- *result.data.null_wrap_ptr_child = child;
8667
- }
8668
- return result;
8669
- }
8670
-
8671
- // pointer const
8668
+ // If pointers have the same representation in memory, they can be "const-casted".
8669
+ // `const` attribute can be gained
8670
+ // `volatile` attribute can be gained
8671
+ // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer)
8672
+ // but only if !wanted_is_mutable
8673
+ // alignment can be decreased
8674
+ // bit offset attributes must match exactly
8675
+ // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one
8672
8676
ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type);
8673
8677
ZigType *actual_ptr_type = get_src_ptr_type(actual_type);
8678
+ bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type);
8679
+ bool actual_allows_zero = ptr_allows_addr_zero(actual_type);
8674
8680
bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC;
8675
8681
bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC;
8676
- if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) ||
8677
- (wanted_ptr_type != nullptr && actual_is_c_ptr) ||
8678
- (actual_ptr_type != nullptr && wanted_is_c_ptr))
8679
- {
8682
+ bool wanted_opt_or_ptr = wanted_ptr_type != nullptr &&
8683
+ (wanted_type->id == ZigTypeIdPointer || wanted_type->id == ZigTypeIdOptional);
8684
+ bool actual_opt_or_ptr = actual_ptr_type != nullptr &&
8685
+ (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional);
8686
+ if (wanted_opt_or_ptr && actual_opt_or_ptr) {
8687
+ bool ok_allows_zero = (wanted_allows_zero &&
8688
+ (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) ||
8689
+ (!wanted_allows_zero && !actual_allows_zero);
8690
+ if (!ok_allows_zero) {
8691
+ result.id = ConstCastResultIdBadAllowsZero;
8692
+ result.data.bad_allows_zero = allocate_nonzero<ConstCastBadAllowsZero>(1);
8693
+ result.data.bad_allows_zero->wanted_type = wanted_type;
8694
+ result.data.bad_allows_zero->actual_type = actual_type;
8695
+ return result;
8696
+ }
8680
8697
ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
8681
8698
actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
8682
8699
if (child.id == ConstCastResultIdInvalid)
@@ -8699,6 +8716,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
8699
8716
}
8700
8717
bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len;
8701
8718
if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) &&
8719
+ type_has_bits(wanted_type) == type_has_bits(actual_type) &&
8702
8720
(!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
8703
8721
(!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
8704
8722
actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host &&
@@ -9922,7 +9940,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
9922
9940
if (undef_allowed == UndefOk) {
9923
9941
return &value->value;
9924
9942
} else {
9925
- ir_add_error(ira, value, buf_sprintf("use of undefined value"));
9943
+ ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior "));
9926
9944
return nullptr;
9927
9945
}
9928
9946
}
@@ -10828,6 +10846,26 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
10828
10846
report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg);
10829
10847
break;
10830
10848
}
10849
+ case ConstCastResultIdBadAllowsZero: {
10850
+ bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type);
10851
+ bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type);
10852
+ ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type);
10853
+ ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type);
10854
+ ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type;
10855
+ ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type;
10856
+ if (actual_allows_zero && !wanted_allows_zero) {
10857
+ add_error_note(ira->codegen, parent_msg, source_node,
10858
+ buf_sprintf("'%s' could have null values which are illegal in type '%s'",
10859
+ buf_ptr(&actual_elem_type->name),
10860
+ buf_ptr(&wanted_elem_type->name)));
10861
+ } else {
10862
+ add_error_note(ira->codegen, parent_msg, source_node,
10863
+ buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'",
10864
+ buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name),
10865
+ buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name)));
10866
+ }
10867
+ break;
10868
+ }
10831
10869
case ConstCastResultIdFnAlign: // TODO
10832
10870
case ConstCastResultIdFnCC: // TODO
10833
10871
case ConstCastResultIdFnVarArgs: // TODO
@@ -10838,7 +10876,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
10838
10876
case ConstCastResultIdFnArgNoAlias: // TODO
10839
10877
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
10840
10878
case ConstCastResultIdAsyncAllocatorType: // TODO
10841
- case ConstCastResultIdNullWrapPtr: // TODO
10842
10879
break;
10843
10880
}
10844
10881
}
@@ -20589,12 +20626,14 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
20589
20626
// We have a check for zero bits later so we use get_src_ptr_type to
20590
20627
// validate src_type and dest_type.
20591
20628
20592
- if (get_src_ptr_type(src_type) == nullptr) {
20629
+ ZigType *src_ptr_type = get_src_ptr_type(src_type);
20630
+ if (src_ptr_type == nullptr) {
20593
20631
ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
20594
20632
return ira->codegen->invalid_instruction;
20595
20633
}
20596
20634
20597
- if (get_src_ptr_type(dest_type) == nullptr) {
20635
+ ZigType *dest_ptr_type = get_src_ptr_type(dest_type);
20636
+ if (dest_ptr_type == nullptr) {
20598
20637
ir_add_error(ira, dest_type_src,
20599
20638
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
20600
20639
return ira->codegen->invalid_instruction;
@@ -20606,6 +20645,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
20606
20645
}
20607
20646
20608
20647
if (instr_is_comptime(ptr)) {
20648
+ // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern
20649
+ // of the pointer as the new pointer type.
20609
20650
ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
20610
20651
if (!val)
20611
20652
return ira->codegen->invalid_instruction;
0 commit comments