Deprecated '&' macro arguments.

This commit is contained in:
Christoffer Lerno
2025-01-08 22:13:49 +01:00
parent 9412b58d80
commit 8e0d6d11b9
24 changed files with 288 additions and 304 deletions

View File

@@ -26,24 +26,25 @@ def VoidFn = fn void();
Stores a variable on the stack, then restores it at the end of the Stores a variable on the stack, then restores it at the end of the
macro scope. macro scope.
@param variable `the variable to store and restore` @param #variable `the variable to store and restore`
@require values::@is_lvalue(#variable)
*> *>
macro void @scope(&variable; @body) @builtin macro void @scope(#variable; @body) @builtin
{ {
var temp = *variable; var temp = #variable;
defer *variable = temp; defer #variable = temp;
@body(); @body();
} }
<* <*
Swap two variables Swap two variables
@require $assignable(*b, $typeof(*a)) && $assignable(*a, $typeof(*b)) @require $defined(#a = #b, #b = #a) `The values must be mutually assignable`
*> *>
macro void @swap(&a, &b) @builtin macro void @swap(#a, #b) @builtin
{ {
var temp = *a; var temp = #a;
*a = *b; #a = #b;
*b = temp; #b = temp;
} }
<* <*
@@ -366,9 +367,12 @@ macro bool @ok(#expr) @builtin
return true; return true;
} }
macro char[] @as_char_view(&value) @builtin <*
@require $defined(&#value, (char*)&#value) "This must be a value that can be viewed as a char array"
*>
macro char[] @as_char_view(#value) @builtin
{ {
return ((char*)value)[:$sizeof(*value)]; return ((char*)&#value)[:$sizeof(#value)];
} }
macro isz @str_find(String $string, String $needle) @builtin => $$str_find($string, $needle); macro isz @str_find(String $string, String $needle) @builtin => $$str_find($string, $needle);

View File

@@ -162,42 +162,55 @@ macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
} }
<* <*
@param [in] x "The variable or dereferenced pointer to load." @param #x "The variable or dereferenced pointer to load."
@param $alignment "The alignment to assume for the load" @param $alignment "The alignment to assume for the load"
@return "The value of x" @return "The value of the variable"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
*> *>
macro @unaligned_load(&x, usz $alignment) @builtin macro @unaligned_load(#x, usz $alignment) @builtin
{ {
return $$unaligned_load(x, $alignment); return $$unaligned_load(&#x, $alignment);
} }
<* <*
@param [out] x "The variable or dereferenced pointer to store to." @param #x "The variable or dereferenced pointer to store to."
@param value "The value to store." @param value "The value to store."
@param $alignment "The alignment to assume for the store" @param $alignment "The alignment to assume for the store"
@return "The value of x" @return "The value stored"
@require $assignable(value, $typeof(*x)) : "The value doesn't match the variable" @require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two" @require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*> *>
macro @unaligned_store(&x, value, usz $alignment) @builtin macro @unaligned_store(#x, value, usz $alignment) @builtin
{ {
return $$unaligned_store(x, ($typeof(*x))value, $alignment); return $$unaligned_store(&#x, ($typeof(#x))value, $alignment);
}
macro @volatile_load(&x) @builtin
{
return $$volatile_load(x);
} }
<* <*
@require $assignable(y, $typeof(*x)) : "The value doesn't match the variable" @param #x "The variable or dereferenced pointer to load."
@return "The value of the variable"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
*> *>
macro @volatile_store(&x, y) @builtin macro @volatile_load(#x) @builtin
{ {
return $$volatile_store(x, ($typeof(*x))y); return $$volatile_load(&#x);
}
<*
@param #x "The variable or dereferenced pointer to store to."
@param value "The value to store."
@return "The value stored"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
*>
macro @volatile_store(#x, value) @builtin
{
return $$volatile_store(&#x, ($typeof(#x))value);
} }
enum AtomicOrdering : int enum AtomicOrdering : int
@@ -212,34 +225,36 @@ enum AtomicOrdering : int
} }
<* <*
@param [in] x "the variable or dereferenced pointer to load." @param #x "the variable or dereferenced pointer to load."
@param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT" @param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@param $volatile "whether the load should be volatile, defaults to 'false'" @param $volatile "whether the load should be volatile, defaults to 'false'"
@return "returns the value of x" @return "returns the value of x"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $ordering != AtomicOrdering.RELEASE "Release ordering is not valid for load." @require $ordering != AtomicOrdering.RELEASE "Release ordering is not valid for load."
@require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for load." @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for load."
@require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." @require types::may_load_atomic($typeof(#x)) "Only integer, float and pointers may be used."
@require @typekind(x) == POINTER "You can only load from a pointer"
*> *>
macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin macro @atomic_load(#x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
{ {
return $$atomic_load(x, $volatile, $ordering.ordinal); return $$atomic_load(&#x, $volatile, $ordering.ordinal);
} }
<* <*
@param [out] x "the variable or dereferenced pointer to store to." @param #x "the variable or dereferenced pointer to store to."
@param value "the value to store." @param value "the value to store."
@param $ordering "the atomic ordering of the store, defaults to SEQ_CONSISTENT" @param $ordering "the atomic ordering of the store, defaults to SEQ_CONSISTENT"
@param $volatile "whether the store should be volatile, defaults to 'false'" @param $volatile "whether the store should be volatile, defaults to 'false'"
@require $ordering != AtomicOrdering.ACQUIRE "Acquire ordering is not valid for store." @require $ordering != AtomicOrdering.ACQUIRE "Acquire ordering is not valid for store."
@require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for store." @require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for store."
@require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used." @require types::may_load_atomic($typeof(#x)) "Only integer, float and pointers may be used."
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
*> *>
macro void @atomic_store(&x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin macro void @atomic_store(#x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
{ {
$$atomic_store(x, value, $volatile, $ordering.ordinal); $$atomic_store(&#x, value, $volatile, $ordering.ordinal);
} }
<* <*

View File

@@ -16,6 +16,7 @@ macro bool @is_promotable_to_float(#value) @const => types::is_promotable_to_flo
macro bool @is_vector(#value) @const => types::is_vector($typeof(#value)); macro bool @is_vector(#value) @const => types::is_vector($typeof(#value));
macro bool @is_same_vector_type(#value1, #value2) @const => types::is_same_vector_type($typeof(#value1), $typeof(#value2)); macro bool @is_same_vector_type(#value1, #value2) @const => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
macro bool @assign_to(#value1, #value2) @const => $assignable(#value1, $typeof(#value2)); macro bool @assign_to(#value1, #value2) @const => $assignable(#value1, $typeof(#value2));
macro bool @is_lvalue(#value) => $defined(#value = #value);
macro promote_int(x) macro promote_int(x)
{ {

View File

@@ -106,7 +106,7 @@ macro @h(x, y, z) => (x ^ y) ^ z;
macro @h2(x, y, z) => x ^ (y ^ z); macro @h2(x, y, z) => x ^ (y ^ z);
macro @i(x, y, z) => y ^ (x | ~z); macro @i(x, y, z) => y ^ (x | ~z);
macro @step(#f, &a, b, c, d, ptr, n, t, s) macro @step(#f, a, b, c, d, ptr, n, t, s)
{ {
*a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t; *a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t;
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s)); *a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
@@ -133,76 +133,76 @@ fn char* body(Md5* ctx, void* data, usz size)
saved_d = d; saved_d = d;
/* Round 1 */ /* Round 1 */
@step(@f, a, b, c, d, ptr, 0, 0xd76aa478, 7) ; @step(@f, &a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
@step(@f, d, a, b, c, ptr, 1, 0xe8c7b756, 12) ; @step(@f, &d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
@step(@f, c, d, a, b, ptr, 2, 0x242070db, 17) ; @step(@f, &c, d, a, b, ptr, 2, 0x242070db, 17) ;
@step(@f, b, c, d, a, ptr, 3, 0xc1bdceee, 22) ; @step(@f, &b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
@step(@f, a, b, c, d, ptr, 4, 0xf57c0faf, 7) ; @step(@f, &a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
@step(@f, d, a, b, c, ptr, 5, 0x4787c62a, 12) ; @step(@f, &d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
@step(@f, c, d, a, b, ptr, 6, 0xa8304613, 17) ; @step(@f, &c, d, a, b, ptr, 6, 0xa8304613, 17) ;
@step(@f, b, c, d, a, ptr, 7, 0xfd469501, 22) ; @step(@f, &b, c, d, a, ptr, 7, 0xfd469501, 22) ;
@step(@f, a, b, c, d, ptr, 8, 0x698098d8, 7) ; @step(@f, &a, b, c, d, ptr, 8, 0x698098d8, 7) ;
@step(@f, d, a, b, c, ptr, 9, 0x8b44f7af, 12) ; @step(@f, &d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
@step(@f, c, d, a, b, ptr, 10, 0xffff5bb1, 17); @step(@f, &c, d, a, b, ptr, 10, 0xffff5bb1, 17);
@step(@f, b, c, d, a, ptr, 11, 0x895cd7be, 22); @step(@f, &b, c, d, a, ptr, 11, 0x895cd7be, 22);
@step(@f, a, b, c, d, ptr, 12, 0x6b901122, 7) ; @step(@f, &a, b, c, d, ptr, 12, 0x6b901122, 7) ;
@step(@f, d, a, b, c, ptr, 13, 0xfd987193, 12); @step(@f, &d, a, b, c, ptr, 13, 0xfd987193, 12);
@step(@f, c, d, a, b, ptr, 14, 0xa679438e, 17); @step(@f, &c, d, a, b, ptr, 14, 0xa679438e, 17);
@step(@f, b, c, d, a, ptr, 15, 0x49b40821, 22); @step(@f, &b, c, d, a, ptr, 15, 0x49b40821, 22);
/* Round 2 */ /* Round 2 */
@step(@g, a, b, c, d, ptr, 1, 0xf61e2562, 5) ; @step(@g, &a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
@step(@g, d, a, b, c, ptr, 6, 0xc040b340, 9) ; @step(@g, &d, a, b, c, ptr, 6, 0xc040b340, 9) ;
@step(@g, c, d, a, b, ptr, 11, 0x265e5a51, 14); @step(@g, &c, d, a, b, ptr, 11, 0x265e5a51, 14);
@step(@g, b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ; @step(@g, &b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
@step(@g, a, b, c, d, ptr, 5, 0xd62f105d, 5) ; @step(@g, &a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
@step(@g, d, a, b, c, ptr, 10, 0x02441453, 9) ; @step(@g, &d, a, b, c, ptr, 10, 0x02441453, 9) ;
@step(@g, c, d, a, b, ptr, 15, 0xd8a1e681, 14); @step(@g, &c, d, a, b, ptr, 15, 0xd8a1e681, 14);
@step(@g, b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ; @step(@g, &b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
@step(@g, a, b, c, d, ptr, 9, 0x21e1cde6, 5) ; @step(@g, &a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
@step(@g, d, a, b, c, ptr, 14, 0xc33707d6, 9) ; @step(@g, &d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
@step(@g, c, d, a, b, ptr, 3, 0xf4d50d87, 14) ; @step(@g, &c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
@step(@g, b, c, d, a, ptr, 8, 0x455a14ed, 20) ; @step(@g, &b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
@step(@g, a, b, c, d, ptr, 13, 0xa9e3e905, 5) ; @step(@g, &a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
@step(@g, d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ; @step(@g, &d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
@step(@g, c, d, a, b, ptr, 7, 0x676f02d9, 14) ; @step(@g, &c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
@step(@g, b, c, d, a, ptr, 12, 0x8d2a4c8a, 20); @step(@g, &b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
/* Round 3 */ /* Round 3 */
@step(@h, a, b, c, d, ptr, 5, 0xfffa3942, 4); @step(@h, &a, b, c, d, ptr, 5, 0xfffa3942, 4);
@step(@h2, d, a, b, c, ptr, 8, 0x8771f681, 11); @step(@h2, &d, a, b, c, ptr, 8, 0x8771f681, 11);
@step(@h, c, d, a, b, ptr, 11, 0x6d9d6122, 16); @step(@h, &c, d, a, b, ptr, 11, 0x6d9d6122, 16);
@step(@h2, b, c, d, a, ptr, 14, 0xfde5380c, 23); @step(@h2, &b, c, d, a, ptr, 14, 0xfde5380c, 23);
@step(@h, a, b, c, d, ptr, 1, 0xa4beea44, 4); @step(@h, &a, b, c, d, ptr, 1, 0xa4beea44, 4);
@step(@h2, d, a, b, c, ptr, 4, 0x4bdecfa9, 11); @step(@h2, &d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
@step(@h, c, d, a, b, ptr, 7, 0xf6bb4b60, 16); @step(@h, &c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
@step(@h2, b, c, d, a, ptr, 10, 0xbebfbc70, 23); @step(@h2, &b, c, d, a, ptr, 10, 0xbebfbc70, 23);
@step(@h, a, b, c, d, ptr, 13, 0x289b7ec6, 4) ; @step(@h, &a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
@step(@h2, d, a, b, c, ptr, 0, 0xeaa127fa, 11) ; @step(@h2, &d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
@step(@h, c, d, a, b, ptr, 3, 0xd4ef3085, 16) ; @step(@h, &c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
@step(@h2, b, c, d, a, ptr, 6, 0x04881d05, 23) ; @step(@h2, &b, c, d, a, ptr, 6, 0x04881d05, 23) ;
@step(@h, a, b, c, d, ptr, 9, 0xd9d4d039, 4) ; @step(@h, &a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
@step(@h2, d, a, b, c, ptr, 12, 0xe6db99e5, 11) ; @step(@h2, &d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
@step(@h, c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ; @step(@h, &c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
@step(@h2, b, c, d, a, ptr, 2, 0xc4ac5665, 23) ; @step(@h2, &b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
/* Round 4 */ /* Round 4 */
@step(@i, a, b, c, d, ptr, 0, 0xf4292244, 6) ; @step(@i, &a, b, c, d, ptr, 0, 0xf4292244, 6) ;
@step(@i, d, a, b, c, ptr, 7, 0x432aff97, 10) ; @step(@i, &d, a, b, c, ptr, 7, 0x432aff97, 10) ;
@step(@i, c, d, a, b, ptr, 14, 0xab9423a7, 15) ; @step(@i, &c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
@step(@i, b, c, d, a, ptr, 5, 0xfc93a039, 21) ; @step(@i, &b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
@step(@i, a, b, c, d, ptr, 12, 0x655b59c3, 6) ; @step(@i, &a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
@step(@i, d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ; @step(@i, &d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
@step(@i, c, d, a, b, ptr, 10, 0xffeff47d, 15) ; @step(@i, &c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
@step(@i, b, c, d, a, ptr, 1, 0x85845dd1, 21) ; @step(@i, &b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
@step(@i, a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ; @step(@i, &a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
@step(@i, d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ; @step(@i, &d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
@step(@i, c, d, a, b, ptr, 6, 0xa3014314, 15) ; @step(@i, &c, d, a, b, ptr, 6, 0xa3014314, 15) ;
@step(@i, b, c, d, a, ptr, 13, 0x4e0811a1, 21) ; @step(@i, &b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
@step(@i, a, b, c, d, ptr, 4, 0xf7537e82, 6) ; @step(@i, &a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
@step(@i, d, a, b, c, ptr, 11, 0xbd3af235, 10) ; @step(@i, &d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
@step(@i, c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ; @step(@i, &c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
@step(@i, b, c, d, a, ptr, 9, 0xeb86d391, 21) ; @step(@i, &b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
a += saved_a; a += saved_a;
b += saved_b; b += saved_b;

View File

@@ -104,7 +104,7 @@ macro usz! write_all(stream, char[] buffer)
return n; return n;
} }
macro usz! @read_using_read_byte(&s, char[] buffer) macro usz! @read_using_read_byte(&s, char[] buffer) @deprecated
{ {
return read_using_read_byte(*s, buffer); return read_using_read_byte(*s, buffer);
} }
@@ -137,7 +137,7 @@ macro void! @write_byte_using_write(&s, char c) @deprecated
return write_byte_using_write(*s, c); return write_byte_using_write(*s, c);
} }
macro char! @read_byte_using_read(&s) macro char! @read_byte_using_read(&s) @deprecated
{ {
return read_byte_using_read(*s); return read_byte_using_read(*s);
} }

View File

@@ -132,7 +132,7 @@ $endif
return (usz)n; return (usz)n;
} }
fn char! Socket.read_byte(&self) @dynamic => io::@read_byte_using_read(self); fn char! Socket.read_byte(&self) @dynamic => io::read_byte_using_read(self);
fn usz! Socket.write(&self, char[] bytes) @dynamic fn usz! Socket.write(&self, char[] bytes) @dynamic
{ {

View File

@@ -21,6 +21,7 @@
- Include `@name` when searching for possible matches to `name` in the error message. #1779 - Include `@name` when searching for possible matches to `name` in the error message. #1779
- Improve `@param` parse errors #1777 - Improve `@param` parse errors #1777
- Improved `#foo` resolution inside of the compiler. - Improved `#foo` resolution inside of the compiler.
- Deprecated '&' macro arguments.
### Fixes ### Fixes
- Fix case trying to initialize a `char[*]*` from a String. - Fix case trying to initialize a `char[*]*` from a String.

View File

@@ -1,14 +1,14 @@
module test; module test;
import libc; import std::io;
<* <*
@require values::@assign_to(*b, *a) && values::@assign_to(*a, *b) @require $defined(#a = #b, #b = #a)
*> *>
macro void @swap(&a, &b) macro void @swap(#a, #b)
{ {
var temp = *a; var temp = #a;
*a = *b; #a = #b;
*b = temp; #b = temp;
} }
fn void main() fn void main()
@@ -16,5 +16,5 @@ fn void main()
int x = 123; int x = 123;
int y = 456; int y = 456;
@swap(x, y); @swap(x, y);
libc::printf("x: %d y: %d\n", x, y); io::printfn("x: %d y: %d", x, y);
} }

View File

@@ -11,7 +11,7 @@
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl); static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl);
static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export); static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated);
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl); static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current, static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
unsigned current_index, unsigned count); unsigned current_index, unsigned count);
@@ -1085,7 +1085,7 @@ ERROR:
return decl_poison(decl); return decl_poison(decl);
} }
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export) static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated)
{ {
Variadic variadic_type = sig->variadic; Variadic variadic_type = sig->variadic;
Decl **params = sig->params; Decl **params = sig->params;
@@ -1149,7 +1149,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
case VARDECL_PARAM_REF: case VARDECL_PARAM_REF:
inferred_type = type_get_ptr(method_parent->type); inferred_type = type_get_ptr(method_parent->type);
param->var.not_null = true; param->var.not_null = true;
if (!is_macro) param->var.kind = VARDECL_PARAM; param->var.kind = VARDECL_PARAM;
break; break;
case VARDECL_PARAM: case VARDECL_PARAM:
case VARDECL_PARAM_EXPR: case VARDECL_PARAM_EXPR:
@@ -1224,6 +1224,10 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
switch (var_kind) switch (var_kind)
{ {
case VARDECL_PARAM_REF: case VARDECL_PARAM_REF:
if ((i != 0 || !method_parent) && !is_deprecated)
{
SEMA_DEPRECATED(param, "Reference macro arguments are deprecated.");
}
if (type_info && !type_is_pointer(param->type)) if (type_info && !type_is_pointer(param->type))
{ {
SEMA_ERROR(type_info, "A pointer type was expected for a ref argument, did you mean %s?", SEMA_ERROR(type_info, "A pointer type was expected for a ref argument, did you mean %s?",
@@ -1239,7 +1243,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
} }
if (!is_macro_at_name && (!method_parent || i != 0 || var_kind != VARDECL_PARAM_REF)) if (!is_macro_at_name && (!method_parent || i != 0 || var_kind != VARDECL_PARAM_REF))
{ {
SEMA_ERROR(param, "Ref and expression parameters are not allowed in function-like macros. Prefix the macro name with '@'."); SEMA_ERROR(param, "Expression parameters are not allowed in function-like macros. Prefix the macro name with '@'.");
return decl_poison(param); return decl_poison(param);
} }
FALLTHROUGH; FALLTHROUGH;
@@ -1333,7 +1337,9 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Type
// Get param count and variadic type // Get param count and variadic type
Decl **params = signature->params; Decl **params = signature->params;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export)) return false; bool deprecated = func_decl->resolved_attributes && func_decl->attrs_resolved && func_decl->attrs_resolved->deprecated;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export, deprecated)) return false;
Variadic variadic_type = signature->variadic; Variadic variadic_type = signature->variadic;
@@ -3696,9 +3702,12 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
if (!sema_analyse_func_macro(context, decl, ATTR_MACRO, erase_decl)) return false; if (!sema_analyse_func_macro(context, decl, ATTR_MACRO, erase_decl)) return false;
if (*erase_decl) return true; if (*erase_decl) return true;
bool deprecated = decl->resolved_attributes && decl->attrs_resolved && decl->attrs_resolved->deprecated;
if (!sema_analyse_signature(context, &decl->func_decl.signature, if (!sema_analyse_signature(context, &decl->func_decl.signature,
type_infoptrzero(decl->func_decl.type_parent), type_infoptrzero(decl->func_decl.type_parent),
false)) return false; false, deprecated)) return false;
if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param && !decl->func_decl.signature.is_safemacro) if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param && !decl->func_decl.signature.is_safemacro)
{ {

View File

@@ -36,7 +36,7 @@ static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, Che
static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bool *missing_ref, CheckType check); static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bool *missing_ref, CheckType check);
static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr);
static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error); static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error);
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr); static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr, bool *failed_ref);
static inline bool sema_expr_analyse_ct_eval(SemaContext *context, Expr *expr, CheckType check); static inline bool sema_expr_analyse_ct_eval(SemaContext *context, Expr *expr, CheckType check);
static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr); static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr);
static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr, CheckType check); static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *expr, CheckType check);
@@ -77,7 +77,7 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E
static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped); static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped);
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right); static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right); static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right); static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, Expr *right); static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool int_only, static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool int_only,
bool allow_bitstruct, bool is_add_sub); bool allow_bitstruct, bool is_add_sub);
@@ -124,7 +124,7 @@ static bool sema_binary_arithmetic_promotion(SemaContext *context, Expr *left, E
Expr *parent, const char *error_message, bool allow_bool_vec); Expr *parent, const char *error_message, bool allow_bool_vec);
static bool sema_binary_is_unsigned_always_same_comparison(SemaContext *context, Expr *expr, Expr *left, Expr *right, static bool sema_binary_is_unsigned_always_same_comparison(SemaContext *context, Expr *expr, Expr *left, Expr *right,
Type *lhs_type, Type *rhs_type); Type *lhs_type, Type *rhs_type);
static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Expr *expr); static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Expr *expr, bool *failed_ref);
static void sema_binary_unify_voidptr(SemaContext *context, Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref); static void sema_binary_unify_voidptr(SemaContext *context, Expr *left, Expr *right, Type **left_type_ref, Type **right_type_ref);
// -- function helper functions // -- function helper functions
@@ -436,40 +436,45 @@ CondResult sema_check_comp_time_bool(SemaContext *context, Expr *expr)
} }
static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Expr *expr) static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Expr *expr, bool *failed_ref)
{ {
switch (expr->expr_kind) switch (expr->expr_kind)
{ {
case EXPR_SWIZZLE: case EXPR_SWIZZLE:
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(expr, "You cannot use swizzling to assign to multiple elements, use element-wise assign instead."); RETURN_SEMA_ERROR(expr, "You cannot use swizzling to assign to multiple elements, use element-wise assign instead.");
case EXPR_LAMBDA: case EXPR_LAMBDA:
case EXPR_EMBED: case EXPR_EMBED:
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(expr, "This expression is a value and cannot be assigned to."); RETURN_SEMA_ERROR(expr, "This expression is a value and cannot be assigned to.");
case EXPR_CT_IDENT: case EXPR_CT_IDENT:
return true; return true;
case EXPR_EXT_TRUNC: case EXPR_EXT_TRUNC:
case EXPR_INT_TO_BOOL: case EXPR_INT_TO_BOOL:
case EXPR_DISCARD: case EXPR_DISCARD:
return false; if (failed_ref) goto FAILED_REF;
goto ERR;
case EXPR_OTHER_CONTEXT: case EXPR_OTHER_CONTEXT:
return sema_binary_is_expr_lvalue(context, top_expr, expr->expr_other_context.inner); return sema_binary_is_expr_lvalue(context, top_expr, expr->expr_other_context.inner, failed_ref);
case EXPR_IDENTIFIER: case EXPR_IDENTIFIER:
{ {
Decl *decl = expr->identifier_expr.decl; Decl *decl = expr->identifier_expr.decl;
if (decl->decl_kind != DECL_VAR) if (decl->decl_kind != DECL_VAR)
{ {
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl)); RETURN_SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl));
} }
if (decl->var.kind == VARDECL_CONST) if (decl->var.kind == VARDECL_CONST)
{ {
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant."); RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant.");
} }
decl = decl_raw(decl); decl = decl_raw(decl);
switch (decl->var.kind) switch (decl->var.kind)
{ {
case VARDECL_PARAM_REF: case VARDECL_PARAM_REF:
SEMA_ERROR(top_expr, "You cannot assign to a ref parameter."); if (failed_ref) goto FAILED_REF;
return false; RETURN_SEMA_ERROR(top_expr, "You cannot assign to a ref parameter.");
case VARDECL_LOCAL_CT: case VARDECL_LOCAL_CT:
case VARDECL_LOCAL_CT_TYPE: case VARDECL_LOCAL_CT_TYPE:
case VARDECL_LOCAL: case VARDECL_LOCAL:
@@ -495,13 +500,13 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
if (expr->unary_expr.operator != UNARYOP_DEREF) goto ERR; if (expr->unary_expr.operator != UNARYOP_DEREF) goto ERR;
if (IS_OPTIONAL(expr)) if (IS_OPTIONAL(expr))
{ {
SEMA_ERROR(top_expr, "You cannot assign to a dereferenced optional."); if (failed_ref) goto FAILED_REF;
return false; RETURN_SEMA_ERROR(top_expr, "You cannot assign to a dereferenced optional.");
} }
return true; return true;
case EXPR_BITACCESS: case EXPR_BITACCESS:
case EXPR_ACCESS: case EXPR_ACCESS:
if (!sema_binary_is_expr_lvalue(context, top_expr, expr->access_expr.parent)) return false; if (!sema_binary_is_expr_lvalue(context, top_expr, expr->access_expr.parent, failed_ref)) return false;
goto CHECK_OPTIONAL; goto CHECK_OPTIONAL;
case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT:
case EXPR_SLICE: case EXPR_SLICE:
@@ -509,12 +514,13 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
case EXPR_SUBSCRIPT_ADDR: case EXPR_SUBSCRIPT_ADDR:
goto CHECK_OPTIONAL; goto CHECK_OPTIONAL;
case EXPR_HASH_IDENT: case EXPR_HASH_IDENT:
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression."); RETURN_SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression.");
case EXPR_EXPRESSION_LIST: case EXPR_EXPRESSION_LIST:
if (!vec_size(expr->expression_list)) return false; if (!vec_size(expr->expression_list)) goto ERR;
return sema_binary_is_expr_lvalue(context, top_expr, VECLAST(expr->expression_list)); return sema_binary_is_expr_lvalue(context, top_expr, VECLAST(expr->expression_list), failed_ref);
goto CHECK_OPTIONAL;
case EXPR_CONST: case EXPR_CONST:
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant expression."); RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant expression.");
case EXPR_POISONED: case EXPR_POISONED:
case EXPR_ADDR_CONVERSION: case EXPR_ADDR_CONVERSION:
@@ -594,15 +600,18 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp
} }
UNREACHABLE UNREACHABLE
ERR: ERR:
SEMA_ERROR(top_expr, "An assignable expression, like a variable, was expected here."); if (failed_ref) goto FAILED_REF;
return false; RETURN_SEMA_ERROR(top_expr, "An assignable expression, like a variable, was expected here.");
CHECK_OPTIONAL: CHECK_OPTIONAL:
if (IS_OPTIONAL(expr)) if (IS_OPTIONAL(expr))
{ {
if (failed_ref) goto FAILED_REF;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to an optional value."); RETURN_SEMA_ERROR(top_expr, "You cannot assign to an optional value.");
} }
return true; return true;
FAILED_REF:
*failed_ref = true;
return false;
} }
static bool expr_may_ref(Expr *expr) static bool expr_may_ref(Expr *expr)
@@ -744,10 +753,10 @@ static bool expr_may_ref(Expr *expr)
UNREACHABLE UNREACHABLE
} }
bool sema_expr_check_assign(SemaContext *context, Expr *expr) bool sema_expr_check_assign(SemaContext *context, Expr *expr, bool *failed_ref)
{ {
Expr *inner; Expr *inner;
if (!sema_binary_is_expr_lvalue(context, expr, expr)) return false; if (!sema_binary_is_expr_lvalue(context, expr, expr, failed_ref)) return false;
if (expr->expr_kind == EXPR_SUBSCRIPT) if (expr->expr_kind == EXPR_SUBSCRIPT)
{ {
inner = exprptr(expr->subscript_expr.expr); inner = exprptr(expr->subscript_expr.expr);
@@ -766,8 +775,7 @@ CHECK_INNER:
Decl *decl = inner->identifier_expr.decl; Decl *decl = inner->identifier_expr.decl;
if (decl->decl_kind != DECL_VAR) return true; if (decl->decl_kind != DECL_VAR) return true;
if (!decl->var.in_param) return true; if (!decl->var.in_param) return true;
SEMA_ERROR(inner, "'in' parameters may not be assigned to."); RETURN_SEMA_ERROR(inner, "'in' parameters may not be assigned to.");
return false;
} }
static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
@@ -1309,7 +1317,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
break; break;
} }
if (!sema_analyse_expr_address(context, arg)) return false; if (!sema_analyse_expr_address(context, arg)) return false;
if (sema_arg_is_pass_through_ref(arg) && !sema_expr_check_assign(context, arg)) if (sema_arg_is_pass_through_ref(arg) && !sema_expr_check_assign(context, arg, NULL))
{ {
SEMA_NOTE(definition, "The definition is here."); SEMA_NOTE(definition, "The definition is here.");
return false; return false;
@@ -3003,7 +3011,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
if (!sema_analyse_expr_check(context, subscripted, CHECK_VALUE)) return false; if (!sema_analyse_expr_check(context, subscripted, CHECK_VALUE)) return false;
// If it is an lvalue then check that it is assignable. // If it is an lvalue then check that it is assignable.
if (check == CHECK_LVALUE && !sema_expr_check_assign(context, expr)) return false; if (check == CHECK_LVALUE && !sema_expr_check_assign(context, expr, NULL)) return false;
// 2. Evaluate the index. // 2. Evaluate the index.
Expr *index = exprptr(expr->subscript_expr.index.expr); Expr *index = exprptr(expr->subscript_expr.index.expr);
@@ -5677,7 +5685,7 @@ static bool sema_expr_fold_hash(SemaContext *context, Expr *expr)
* Analyse a = b * Analyse a = b
* @return true if analysis works * @return true if analysis works
*/ */
static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right) static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref)
{ {
if (!sema_expr_fold_hash(context, left)) return false; if (!sema_expr_fold_hash(context, left)) return false;
// 1. Evaluate left side // 1. Evaluate left side
@@ -5698,7 +5706,7 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef
break; break;
} }
// 2. Check assignability // 2. Check assignability
if (!sema_expr_check_assign(context, left)) return false; if (!sema_expr_check_assign(context, left, failed_ref)) return false;
bool is_unwrapped_var = expr_is_unwrapped_ident(left); bool is_unwrapped_var = expr_is_unwrapped_ident(left);
@@ -5742,7 +5750,7 @@ static bool sema_binary_analyse_ct_common_assign(SemaContext *context, Expr *exp
expr->binary_expr.operator = binaryop_assign_base_op(expr->binary_expr.operator); expr->binary_expr.operator = binaryop_assign_base_op(expr->binary_expr.operator);
if (!sema_expr_analyse_binary(context, expr)) return false; if (!sema_expr_analyse_binary(context, expr, NULL)) return false;
if (!sema_cast_const(expr)) if (!sema_cast_const(expr))
{ {
@@ -5771,7 +5779,7 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *
if (!sema_analyse_expr_lvalue(context, left)) return false; if (!sema_analyse_expr_lvalue(context, left)) return false;
// 2. Verify that the left side is assignable. // 2. Verify that the left side is assignable.
if (!sema_expr_check_assign(context, left)) return false; if (!sema_expr_check_assign(context, left, NULL)) return false;
Type *left_type_canonical = left->type->canonical; Type *left_type_canonical = left->type->canonical;
@@ -6620,7 +6628,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp
bool optional = IS_OPTIONAL(left) || IS_OPTIONAL(right); bool optional = IS_OPTIONAL(left) || IS_OPTIONAL(right);
// 2. Ensure the lhs side is assignable // 2. Ensure the lhs side is assignable
if (!sema_expr_check_assign(context, left)) return false; if (!sema_expr_check_assign(context, left, NULL)) return false;
// 3. Only integers may be shifted. // 3. Only integers may be shifted.
if (!expr_both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(context, expr); if (!expr_both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(context, expr);
@@ -7397,7 +7405,7 @@ static inline bool sema_expr_analyse_incdec(SemaContext *context, Expr *expr)
if (!sema_analyse_expr_lvalue(context, inner)) return false; if (!sema_analyse_expr_lvalue(context, inner)) return false;
// 2. Assert it's an l-value // 2. Assert it's an l-value
if (!sema_expr_check_assign(context, inner)) return false; if (!sema_expr_check_assign(context, inner, NULL)) return false;
// 3. This might be a $foo, if to handle it. // 3. This might be a $foo, if to handle it.
if (inner->expr_kind == EXPR_CT_IDENT) if (inner->expr_kind == EXPR_CT_IDENT)
@@ -7587,7 +7595,7 @@ static inline bool sema_expr_analyse_ct_and_or(SemaContext *context, Expr *expr,
return true; return true;
} }
static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr) static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr, bool *failed_ref)
{ {
if (expr->binary_expr.operator == BINARYOP_ELSE) return sema_expr_analyse_or_error(context, expr); if (expr->binary_expr.operator == BINARYOP_ELSE) return sema_expr_analyse_or_error(context, expr);
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING); ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING);
@@ -7609,7 +7617,7 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Expr *expr)
case BINARYOP_CT_AND: case BINARYOP_CT_AND:
return sema_expr_analyse_ct_and_or(context, expr, left, right); return sema_expr_analyse_ct_and_or(context, expr, left, right);
case BINARYOP_ASSIGN: case BINARYOP_ASSIGN:
return sema_expr_analyse_assign(context, expr, left, right); return sema_expr_analyse_assign(context, expr, left, right, failed_ref);
case BINARYOP_MULT: case BINARYOP_MULT:
return sema_expr_analyse_mult(context, expr, left, right); return sema_expr_analyse_mult(context, expr, left, right);
case BINARYOP_ADD: case BINARYOP_ADD:
@@ -8986,9 +8994,15 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
case EXPR_DEFAULT_ARG: case EXPR_DEFAULT_ARG:
case EXPR_NAMED_ARGUMENT: case EXPR_NAMED_ARGUMENT:
UNREACHABLE UNREACHABLE
case EXPR_CT_ARG:
FALLTHROUGH;
case EXPR_BINARY: case EXPR_BINARY:
main_expr->resolve_status = RESOLVE_RUNNING;
if (!sema_expr_analyse_binary(context, main_expr, &failed))
{
if (!failed) goto FAIL;
success = false;
}
break;
case EXPR_CT_ARG:
case EXPR_BITACCESS: case EXPR_BITACCESS:
case EXPR_BITASSIGN: case EXPR_BITASSIGN:
case EXPR_COMPOUND_LITERAL: case EXPR_COMPOUND_LITERAL:
@@ -9546,7 +9560,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
case EXPR_CT_EVAL: case EXPR_CT_EVAL:
return sema_expr_analyse_ct_eval(context, expr, check); return sema_expr_analyse_ct_eval(context, expr, check);
case EXPR_BINARY: case EXPR_BINARY:
return sema_expr_analyse_binary(context, expr); return sema_expr_analyse_binary(context, expr, NULL);
case EXPR_TERNARY: case EXPR_TERNARY:
return sema_expr_analyse_ternary(context, NULL, expr); return sema_expr_analyse_ternary(context, NULL, expr);
case EXPR_UNARY: case EXPR_UNARY:

View File

@@ -109,7 +109,8 @@ bool sema_analyse_asm(SemaContext *context, AsmInlineBlock *block, Ast *asm_stmt
bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member); bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member);
CondResult sema_check_comp_time_bool(SemaContext *context, Expr *expr); CondResult sema_check_comp_time_bool(SemaContext *context, Expr *expr);
bool sema_expr_check_assign(SemaContext *context, Expr *expr);
bool sema_expr_check_assign(SemaContext *context, Expr *expr, bool *failed_ref);
bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, TypeInfo *parent, CallABI abi, Signature *signature); bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, TypeInfo *parent, CallABI abi, Signature *signature);
Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs); Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs);
ConstInitializer *sema_merge_bitstruct_const_initializers(ConstInitializer *lhs, ConstInitializer *rhs, BinaryOp op); ConstInitializer *sema_merge_bitstruct_const_initializers(ConstInitializer *lhs, ConstInitializer *rhs, BinaryOp op);

View File

@@ -9,12 +9,16 @@ fn void main()
{ {
Foo* foo; Foo* foo;
float[<4>] a @align(1) @noinit; float[<4>] a @align(1) @noinit;
float[<4>] b @align(1) @noinit;
a = *(float[<4>]*)&foo.a; a = *(float[<4>]*)&foo.a;
*(float[<4>]*)&foo.a = a; *(float[<4>]*)&foo.a = a;
a = $$unaligned_load((float[<4>]*)&foo.a, 1); a = $$unaligned_load((float[<4>]*)&foo.a, 1);
$$unaligned_store((float[<4>]*)&foo.a, a, 1); $$unaligned_store((float[<4>]*)&foo.a, a, 1);
b = @unaligned_load(*(float[<4>]*)&foo.a, 1);
@unaligned_store(*(float[<4>]*)&foo.a, b, 1);
} }
/* #expect: test.ll /* #expect: test.ll
@@ -23,6 +27,8 @@ define void @test.main() #0 {
entry: entry:
%foo = alloca ptr, align 8 %foo = alloca ptr, align 8
%a = alloca <4 x float>, align 1 %a = alloca <4 x float>, align 1
%b = alloca <4 x float>, align 1
%value = alloca <4 x float>, align 16
store ptr null, ptr %foo, align 8 store ptr null, ptr %foo, align 8
%0 = load ptr, ptr %foo, align 8 %0 = load ptr, ptr %foo, align 8
%1 = load <4 x float>, ptr %0, align 16 %1 = load <4 x float>, ptr %0, align 16
@@ -36,5 +42,13 @@ entry:
%6 = load ptr, ptr %foo, align 8 %6 = load ptr, ptr %foo, align 8
%7 = load <4 x float>, ptr %a, align 1 %7 = load <4 x float>, ptr %a, align 1
store <4 x float> %7, ptr %6, align 1 store <4 x float> %7, ptr %6, align 1
%8 = load ptr, ptr %foo, align 8
%9 = load <4 x float>, ptr %8, align 1
store <4 x float> %9, ptr %b, align 1
%10 = load <4 x float>, ptr %b, align 1
store <4 x float> %10, ptr %value, align 16
%11 = load ptr, ptr %foo, align 8
%12 = load <4 x float>, ptr %value, align 16
store <4 x float> %12, ptr %11, align 1
ret void ret void
} }

View File

@@ -31,42 +31,30 @@ define void @test.main() #0 !dbg !8 {
entry: entry:
%a = alloca i32, align 4 %a = alloca i32, align 4
%x = alloca i32, align 4 %x = alloca i32, align 4
%x1 = alloca ptr, align 8
%y = alloca i32, align 4 %y = alloca i32, align 4
%x2 = alloca ptr, align 8
%x3 = alloca ptr, align 8
%value = alloca i32, align 4 %value = alloca i32, align 4
%x4 = alloca ptr, align 8 %value2 = alloca i32, align 4
%value6 = alloca i32, align 4
%varargslots = alloca [1 x %any], align 16 %varargslots = alloca [1 x %any], align 16
%retparam = alloca i64, align 8 %retparam = alloca i64, align 8
store i32 111, ptr %a, align 4, !dbg !15 store i32 111, ptr %a, align 4, !dbg !15
store ptr %a, ptr %x1, align 8 %0 = load atomic i32, ptr %a seq_cst, align 4, !dbg !18
%0 = load ptr, ptr %x1, align 8, !dbg !18 store i32 %0, ptr %x, align 4, !dbg !18
%1 = load atomic i32, ptr %0 seq_cst, align 4, !dbg !18 %1 = load atomic volatile i32, ptr %a monotonic, align 4, !dbg !24
store i32 %1, ptr %x, align 4, !dbg !18 store i32 %1, ptr %y, align 4, !dbg !24
store ptr %a, ptr %x2, align 8 %2 = load i32, ptr %x, align 4, !dbg !27
%2 = load ptr, ptr %x2, align 8, !dbg !24 %add = add i32 123, %2, !dbg !28
%3 = load atomic volatile i32, ptr %2 monotonic, align 4, !dbg !24
store i32 %3, ptr %y, align 4, !dbg !24
store ptr %a, ptr %x3, align 8
%4 = load i32, ptr %x, align 4, !dbg !27
%add = add i32 123, %4, !dbg !28
store i32 %add, ptr %value, align 4 store i32 %add, ptr %value, align 4
%5 = load ptr, ptr %x3, align 8, !dbg !29 %3 = load i32, ptr %value, align 4, !dbg !29
%6 = load i32, ptr %value, align 4, !dbg !29 store atomic i32 %3, ptr %a seq_cst, align 4, !dbg !29
store atomic i32 %6, ptr %5 seq_cst, align 4, !dbg !29 %4 = load i32, ptr %y, align 4, !dbg !32
store ptr %a, ptr %x4, align 8 %add1 = add i32 33, %4, !dbg !33
%7 = load i32, ptr %y, align 4, !dbg !32 store i32 %add1, ptr %value2, align 4
%add5 = add i32 33, %7, !dbg !33 %5 = load i32, ptr %value2, align 4, !dbg !34
store i32 %add5, ptr %value6, align 4 store atomic volatile i32 %5, ptr %a monotonic, align 4, !dbg !34
%8 = load ptr, ptr %x4, align 8, !dbg !34 %6 = insertvalue %any undef, ptr %a, 0, !dbg !37
%9 = load i32, ptr %value6, align 4, !dbg !34 %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1, !dbg !37
store atomic volatile i32 %9, ptr %8 monotonic, align 4, !dbg !34 store %any %7, ptr %varargslots, align 16, !dbg !37
%10 = insertvalue %any undef, ptr %a, 0, !dbg !37 %8 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1), !dbg !38
%11 = insertvalue %any %10, i64 ptrtoint (ptr @"$ct.int" to i64), 1, !dbg !37
store %any %11, ptr %varargslots, align 16, !dbg !37
%12 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1), !dbg !38
ret void, !dbg !38 ret void, !dbg !38
} }
@@ -118,17 +106,17 @@ declare i1 @llvm.expect.i1(i1, i1)
!22 = !DILocalVariable(name: "y", scope: !8, file: !7, line: 14, type: !13, align: 4) !22 = !DILocalVariable(name: "y", scope: !8, file: !7, line: 14, type: !13, align: 4)
!23 = !DILocation(line: 14, column: 6, scope: !8) !23 = !DILocation(line: 14, column: 6, scope: !8)
!24 = !DILocation( !24 = !DILocation(
!25 = distinct !DISubprogram(name: "@atomic_load", linkageName: "@atomic_load", scope: !20, file: !20, line: 225, scopeLine: 225, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !25 = distinct !DISubprogram(name: "@atomic_load", linkageName: "@atomic_load", scope: !20, file: !20
!26 = !DILocation(line: 14, column: 10, scope: !8) !26 = !DILocation(line: 14, column: 10, scope: !8)
!27 = !DILocation(line: 15, column: 25, scope: !8) !27 = !DILocation(line: 15, column: 25, scope: !8)
!28 = !DILocation(line: 15, column: 19, scope: !8) !28 = !DILocation(line: 15, column: 19, scope: !8)
!29 = !DILocation( !29 = !DILocation(
!30 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !20, file: !20, line: 240, scopeLine: 240, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !30 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !20, file: !20
!31 = !DILocation(line: 15, column: 2, scope: !8) !31 = !DILocation(line: 15, column: 2, scope: !8)
!32 = !DILocation(line: 16, column: 24, scope: !8) !32 = !DILocation(line: 16, column: 24, scope: !8)
!33 = !DILocation(line: 16, column: 19, scope: !8) !33 = !DILocation(line: 16, column: 19, scope: !8)
!34 = !DILocation( !34 = !DILocation(
!35 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !20, file: !20, line: 240, scopeLine: 240, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !35 = distinct !DISubprogram(name: "@atomic_store", linkageName: "@atomic_store", scope: !20, file: !20
!36 = !DILocation(line: 16, column: 2, scope: !8) !36 = !DILocation(line: 16, column: 2, scope: !8)
!37 = !DILocation(line: 17, column: 20, scope: !8) !37 = !DILocation(line: 17, column: 20, scope: !8)
!38 = !DILocation(line: 17, column: 2, scope: !8) !38 = !DILocation(line: 17, column: 2, scope: !8)

View File

@@ -664,7 +664,7 @@ no_match: ; preds = %compare
!73 = !DILocalVariable(name: "name", arg: 3, scope: !66, file: !7, line: 33, type: !39) !73 = !DILocalVariable(name: "name", arg: 3, scope: !66, file: !7, line: 33, type: !39)
!74 = !DILocation(line: 33, column: 63, scope: !66) !74 = !DILocation(line: 33, column: 63, scope: !66)
!75 = !DILocation(line: !75 = !DILocation(line:
!76 = distinct !DISubprogram(name: "new", linkageName: "new", scope: !77, file: !77, line: 624, scopeLine: 624, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !76 = distinct !DISubprogram(name: "new", linkageName: "new", scope: !77, file: !77, line:
!77 = !DIFile(filename: "mem.c3" !77 = !DIFile(filename: "mem.c3"
!78 = !DILocation(line: 34, column: 10, scope: !66) !78 = !DILocation(line: 34, column: 10, scope: !66)
!79 = distinct !DISubprogram(name: "test", linkageName: "test.test", scope: !7, file: !7, line: 41, type: !80, scopeLine: 41, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !21) !79 = distinct !DISubprogram(name: "test", linkageName: "test.test", scope: !7, file: !7, line: 41, type: !80, scopeLine: 41, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !21)
@@ -743,9 +743,9 @@ no_match: ; preds = %compare
!152 = distinct !DISubprogram(name: "alloc_array_try", linkageName: "alloc_array_try", scope: !153, file: !153, line: 284, scopeLine: 284, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !152 = distinct !DISubprogram(name: "alloc_array_try", linkageName: "alloc_array_try", scope: !153, file: !153, line: 284, scopeLine: 284, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6)
!153 = !DIFile(filename: "mem_allocator.c3" !153 = !DIFile(filename: "mem_allocator.c3"
!154 = !DILocation !154 = !DILocation
!155 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !153, file: !153, line: 267, scopeLine: 267, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !155 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !153
!156 = !DILocation !156 = !DILocation
!157 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !77, file: !77, line: 710, scopeLine: 710, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6) !157 = distinct !DISubprogram(name: "alloc_array", linkageName: "alloc_array", scope: !77
!158 = !DILocation !158 = !DILocation
!159 = !DILocation !159 = !DILocation
!160 = !DILocation !160 = !DILocation

View File

@@ -7,8 +7,6 @@ fn void foo3(bar) { } // #error: Only typed parameters are allowed for functions
fn void foo4($Type) { } // #error: Only regular parameters are allowed for functions. fn void foo4($Type) { } // #error: Only regular parameters are allowed for functions.
fn void foo8(int* &foo) {} // #error: Only regular parameters are allowed for functions.
fn void foo9(int x, int x) {} // #error: Duplicate parameter name 'x'. fn void foo9(int x, int x) {} // #error: Duplicate parameter name 'x'.
macro @foo($a, $b, $c, ...) {} macro @foo($a, $b, $c, ...) {}

View File

@@ -1,15 +0,0 @@
module test;
fn void test(int* a) {}
macro @abc(&self)
{
test(self); // #error: Implicitly casting 'int**' to 'int*'
}
fn void! test1()
{
int* a;
int b;
@abc(a);
@abc(b);
}

View File

@@ -4,17 +4,17 @@ import std::io;
fn void main() fn void main()
{ {
@boba(;#hash_val, &foo, int $value, $Type) @boba(;#hash_val, #foo, int $value, $Type)
{ {
io::printn("Now invoking hash"); io::printn("Now invoking hash");
#hash_val; #hash_val;
#hash_val; #hash_val;
*foo += $value; #foo += $value;
io::printfn("The type was: %s", $Type.nameof); io::printfn("The type was: %s", $Type.nameof);
}; };
} }
macro void @boba(;@body(#hash, &foo, $val, $Type)) macro void @boba(;@body(#hash, #foo, $val, $Type))
{ {
io::printn("Boba"); io::printn("Boba");
int a = 0; int a = 0;
@@ -34,7 +34,6 @@ entry:
%error_var8 = alloca i64, align 8 %error_var8 = alloca i64, align 8
%a = alloca i32, align 4 %a = alloca i32, align 4
%b = alloca i32, align 4 %b = alloca i32, align 4
%foo = alloca ptr, align 8
%len14 = alloca i64, align 8 %len14 = alloca i64, align 8
%error_var15 = alloca i64, align 8 %error_var15 = alloca i64, align 8
%retparam17 = alloca i64, align 8 %retparam17 = alloca i64, align 8
@@ -54,17 +53,13 @@ entry:
%not_err = icmp eq i64 %1, 0 %not_err = icmp eq i64 %1, 0
%2 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) %2 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %2, label %after_check, label %assign_optional br i1 %2, label %after_check, label %assign_optional
assign_optional: ; preds = %entry assign_optional: ; preds = %entry
store i64 %1, ptr %error_var, align 8 store i64 %1, ptr %error_var, align 8
br label %guard_block br label %guard_block
after_check: ; preds = %entry after_check: ; preds = %entry
br label %noerr_block br label %noerr_block
guard_block: ; preds = %assign_optional guard_block: ; preds = %assign_optional
br label %voiderr br label %voiderr
noerr_block: ; preds = %after_check noerr_block: ; preds = %after_check
%3 = load i64, ptr %retparam, align 8 %3 = load i64, ptr %retparam, align 8
store i64 %3, ptr %len, align 8 store i64 %3, ptr %len, align 8
@@ -72,58 +67,44 @@ noerr_block: ; preds = %after_check
%not_err3 = icmp eq i64 %4, 0 %not_err3 = icmp eq i64 %4, 0
%5 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) %5 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
br i1 %5, label %after_check5, label %assign_optional4 br i1 %5, label %after_check5, label %assign_optional4
assign_optional4: ; preds = %noerr_block assign_optional4: ; preds = %noerr_block
store i64 %4, ptr %error_var2, align 8 store i64 %4, ptr %error_var2, align 8
br label %guard_block6 br label %guard_block6
after_check5: ; preds = %noerr_block after_check5: ; preds = %noerr_block
br label %noerr_block7 br label %noerr_block7
guard_block6: ; preds = %assign_optional4 guard_block6: ; preds = %assign_optional4
br label %voiderr br label %voiderr
noerr_block7: ; preds = %after_check5 noerr_block7: ; preds = %after_check5
%6 = call i64 @std.io.File.flush(ptr %0) %6 = call i64 @std.io.File.flush(ptr %0)
%not_err9 = icmp eq i64 %6, 0 %not_err9 = icmp eq i64 %6, 0
%7 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true) %7 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
br i1 %7, label %after_check11, label %assign_optional10 br i1 %7, label %after_check11, label %assign_optional10
assign_optional10: ; preds = %noerr_block7 assign_optional10: ; preds = %noerr_block7
store i64 %6, ptr %error_var8, align 8 store i64 %6, ptr %error_var8, align 8
br label %guard_block12 br label %guard_block12
after_check11: ; preds = %noerr_block7 after_check11: ; preds = %noerr_block7
br label %noerr_block13 br label %noerr_block13
guard_block12: ; preds = %assign_optional10 guard_block12: ; preds = %assign_optional10
br label %voiderr br label %voiderr
noerr_block13: ; preds = %after_check11 noerr_block13: ; preds = %after_check11
%8 = load i64, ptr %len, align 8 %8 = load i64, ptr %len, align 8
%add = add i64 %8, 1 %add = add i64 %8, 1
br label %voiderr br label %voiderr
voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block
store i32 0, ptr %a, align 4 store i32 0, ptr %a, align 4
store i32 0, ptr %b, align 4 store i32 0, ptr %b, align 4
store ptr %b, ptr %foo, align 8
%9 = call ptr @std.io.stdout() %9 = call ptr @std.io.stdout()
%10 = call i64 @std.io.File.write(ptr %retparam17, ptr %9, ptr @.str.1, i64 17) %10 = call i64 @std.io.File.write(ptr %retparam17, ptr %9, ptr @.str.1, i64 17)
%not_err18 = icmp eq i64 %10, 0 %not_err18 = icmp eq i64 %10, 0
%11 = call i1 @llvm.expect.i1(i1 %not_err18, i1 true) %11 = call i1 @llvm.expect.i1(i1 %not_err18, i1 true)
br i1 %11, label %after_check20, label %assign_optional19 br i1 %11, label %after_check20, label %assign_optional19
assign_optional19: ; preds = %voiderr assign_optional19: ; preds = %voiderr
store i64 %10, ptr %error_var15, align 8 store i64 %10, ptr %error_var15, align 8
br label %guard_block21 br label %guard_block21
after_check20: ; preds = %voiderr after_check20: ; preds = %voiderr
br label %noerr_block22 br label %noerr_block22
guard_block21: ; preds = %assign_optional19 guard_block21: ; preds = %assign_optional19
br label %voiderr36 br label %voiderr36
noerr_block22: ; preds = %after_check20 noerr_block22: ; preds = %after_check20
%12 = load i64, ptr %retparam17, align 8 %12 = load i64, ptr %retparam17, align 8
store i64 %12, ptr %len14, align 8 store i64 %12, ptr %len14, align 8
@@ -131,38 +112,29 @@ noerr_block22: ; preds = %after_check20
%not_err24 = icmp eq i64 %13, 0 %not_err24 = icmp eq i64 %13, 0
%14 = call i1 @llvm.expect.i1(i1 %not_err24, i1 true) %14 = call i1 @llvm.expect.i1(i1 %not_err24, i1 true)
br i1 %14, label %after_check26, label %assign_optional25 br i1 %14, label %after_check26, label %assign_optional25
assign_optional25: ; preds = %noerr_block22 assign_optional25: ; preds = %noerr_block22
store i64 %13, ptr %error_var23, align 8 store i64 %13, ptr %error_var23, align 8
br label %guard_block27 br label %guard_block27
after_check26: ; preds = %noerr_block22 after_check26: ; preds = %noerr_block22
br label %noerr_block28 br label %noerr_block28
guard_block27: ; preds = %assign_optional25 guard_block27: ; preds = %assign_optional25
br label %voiderr36 br label %voiderr36
noerr_block28: ; preds = %after_check26 noerr_block28: ; preds = %after_check26
%15 = call i64 @std.io.File.flush(ptr %9) %15 = call i64 @std.io.File.flush(ptr %9)
%not_err30 = icmp eq i64 %15, 0 %not_err30 = icmp eq i64 %15, 0
%16 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true) %16 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true)
br i1 %16, label %after_check32, label %assign_optional31 br i1 %16, label %after_check32, label %assign_optional31
assign_optional31: ; preds = %noerr_block28 assign_optional31: ; preds = %noerr_block28
store i64 %15, ptr %error_var29, align 8 store i64 %15, ptr %error_var29, align 8
br label %guard_block33 br label %guard_block33
after_check32: ; preds = %noerr_block28 after_check32: ; preds = %noerr_block28
br label %noerr_block34 br label %noerr_block34
guard_block33: ; preds = %assign_optional31 guard_block33: ; preds = %assign_optional31
br label %voiderr36 br label %voiderr36
noerr_block34: ; preds = %after_check32 noerr_block34: ; preds = %after_check32
%17 = load i64, ptr %len14, align 8 %17 = load i64, ptr %len14, align 8
%add35 = add i64 %17, 1 %add35 = add i64 %17, 1
br label %voiderr36 br label %voiderr36
voiderr36: ; preds = %noerr_block34, %guard_block33, %guard_block27, %guard_block21 voiderr36: ; preds = %noerr_block34, %guard_block33, %guard_block27, %guard_block21
%18 = insertvalue %any undef, ptr %a, 0 %18 = insertvalue %any undef, ptr %a, 0
%19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.int" to i64), 1 %19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.int" to i64), 1
@@ -178,18 +150,17 @@ voiderr36: ; preds = %noerr_block34, %gua
%25 = load i32, ptr %a, align 4 %25 = load i32, ptr %a, align 4
%add45 = add i32 %25, 1 %add45 = add i32 %25, 1
store i32 %add45, ptr %a, align 4 store i32 %add45, ptr %a, align 4
%26 = load ptr, ptr %foo, align 8 %26 = load i32, ptr %b, align 4
%27 = load i32, ptr %26, align 4 %add46 = add i32 %26, 3
%add46 = add i32 %27, 3 store i32 %add46, ptr %b, align 4
store i32 %add46, ptr %26, align 4
store %"char[]" { ptr @.str.5, i64 3 }, ptr %taddr, align 8 store %"char[]" { ptr @.str.5, i64 3 }, ptr %taddr, align 8
%28 = insertvalue %any undef, ptr %taddr, 0 %27 = insertvalue %any undef, ptr %taddr, 0
%29 = insertvalue %any %28, i64 ptrtoint (ptr @"$ct.String" to i64), 1 %28 = insertvalue %any %27, i64 ptrtoint (ptr @"$ct.String" to i64), 1
store %any %29, ptr %varargslots47, align 16 store %any %28, ptr %varargslots47, align 16
%30 = call i64 @std.io.printfn(ptr %retparam48, ptr @.str.4, i64 16, ptr %varargslots47, i64 1) %29 = call i64 @std.io.printfn(ptr %retparam48, ptr @.str.4, i64 16, ptr %varargslots47, i64 1)
%31 = insertvalue %any undef, ptr %b, 0 %30 = insertvalue %any undef, ptr %b, 0
%32 = insertvalue %any %31, i64 ptrtoint (ptr @"$ct.int" to i64), 1 %31 = insertvalue %any %30, i64 ptrtoint (ptr @"$ct.int" to i64), 1
store %any %32, ptr %varargslots51, align 16 store %any %31, ptr %varargslots51, align 16
%33 = call i64 @std.io.printfn(ptr %retparam52, ptr @.str.6, i64 2, ptr %varargslots51, i64 1) %32 = call i64 @std.io.printfn(ptr %retparam52, ptr @.str.6, i64 2, ptr %varargslots51, i64 1)
ret void ret void
} }

View File

@@ -2,10 +2,7 @@ macro foo(a, $b, $Type) {}
macro @foo2(a, $b, $Type) {} macro @foo2(a, $b, $Type) {}
macro bar(&x) // #error: Ref and expression parameters macro baz(#y) {} // #error: are not allowed in function-like
{}
macro baz(#y) {} // #error: Ref and expression parameters
macro baz2(a; @body()) {} // #error: Names of macros macro baz2(a; @body()) {} // #error: Names of macros

View File

@@ -1,28 +0,0 @@
module test;
import std::io;
macro @foo(int* &hello)
{
hello = hello; // #error: You cannot assign to a ref
}
macro @bar(Foo* &f)
{
f.a = 1;
int* x = &f.a;
Foo **ff = &f; // #error: You may not take the address
}
struct Foo
{
int a;
}
fn void main()
{
int a;
@foo(a);
Foo x;
@bar(x);
}

View File

@@ -14,10 +14,10 @@ fn int Foo.mutate(Foo *foo)
return 10 * ++foo.x; return 10 * ++foo.x;
} }
macro @macro_with_body(foo, &x; @body(x, y)) macro @macro_with_body(foo, #x; @body(x, y))
{ {
*x = foo.x; #x = foo.x;
@body(foo.mutate(), *x); @body(foo.mutate(), #x);
} }
macro @repeat(int times; @body(x)) macro @repeat(int times; @body(x))

View File

@@ -14,10 +14,10 @@ fn int Foo.mutate(Foo *foo)
return 10 * ++foo.x; return 10 * ++foo.x;
} }
macro @macro_with_body(foo, &x; @body(x, y)) macro @macro_with_body(foo, #x; @body(x, y))
{ {
*x = foo.x; #x = foo.x;
@body(foo.mutate(), x); // #error: 'int*' to 'int' @body(foo.mutate(), &#x); // #error: 'int*' to 'int'
} }

View File

@@ -10,8 +10,8 @@ fn int main() {
return 1; return 1;
} }
macro @foo(&ref) { macro @foo(#ref) {
*ref += 1; #ref += 1;
} }
/* #expect: test.ll /* #expect: test.ll
@@ -21,20 +21,34 @@ define i32 @main() #0 {
entry: entry:
%vec = alloca <4 x i32>, align 16 %vec = alloca <4 x i32>, align 16
store <4 x i32> zeroinitializer, ptr %vec, align 16 store <4 x i32> zeroinitializer, ptr %vec, align 16
%0 = load i32, ptr %vec, align 4 %0 = load <4 x i32>, ptr %vec, align 16
%add = add i32 %0, 1 %elem = extractelement <4 x i32> %0, i64 0
store i32 %add, ptr %vec, align 4 %add = add i32 %elem, 1
%ptradd = getelementptr inbounds i8, ptr %vec, i64 8 %elemset = insertelement <4 x i32> %0, i32 %add, i64 0
%1 = load i32, ptr %ptradd, align 4 store <4 x i32> %elemset, ptr %vec, align 16
%add1 = add i32 %1, 1 %1 = load <4 x i32>, ptr %vec, align 16
store i32 %add1, ptr %ptradd, align 4 %elem1 = extractelement <4 x i32> %1, i64 2
%add2 = add i32 %elem1, 1
%elemset3 = insertelement <4 x i32> %1, i32 %add2, i64 2
store <4 x i32> %elemset3, ptr %vec, align 16
%2 = load <4 x i32>, ptr %vec, align 16 %2 = load <4 x i32>, ptr %vec, align 16
%3 = extractelement <4 x i32> %2, i64 0 %3 = extractelement <4 x i32> %2, i64 0
%eq = icmp eq i32 %3, 1 %eq = icmp eq i32 %3, 1
call void @llvm.assume(i1 %eq) call void @llvm.assume(i1 %eq)
%4 = load <4 x i32>, ptr %vec, align 16 %4 = load <4 x i32>, ptr %vec, align 16
%5 = extractelement <4 x i32> %4, i64 2 %5 = extractelement <4 x i32> %4, i64 2
%eq2 = icmp eq i32 %5, 1 %eq4 = icmp eq i32 %5, 1
call void @llvm.assume(i1 %eq2) call void @llvm.assume(i1 %eq4)
ret i32 1 ret i32 1
} }
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write)
declare void @llvm.assume(i1 noundef) #1
attributes #0 = { nounwind uwtable "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }
!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 2, !"wchar_size", i32 4}
!3 = !{i32 4, !"PIC Level", i32 2}
!4 = !{i32 1, !"uwtable", i32 2}
!5 = !{i32 2, !"frame-pointer", i32 2}

View File

@@ -4,9 +4,9 @@ import std, test2;
int[2] x; int[2] x;
macro @test2(&a = x[1]) macro @test2(#a = x[1])
{ {
*a = 123; #a = 123;
} }
macro test($Type = int) { io::printn($Type.nameof); } macro test($Type = int) { io::printn($Type.nameof); }
@@ -31,9 +31,9 @@ import std;
int[2] x; int[2] x;
macro @test2(&a = x[1]) macro @test2(#a = x[1])
{ {
*a = 12; #a = 12;
} }
macro test($Type = double) { io::printn($Type.nameof); } macro test($Type = double) { io::printn($Type.nameof); }

View File

@@ -68,4 +68,4 @@ fn usz! TestReader.read(&self, char[] bytes) @dynamic
return n; return n;
} }
fn char! TestReader.read_byte(&self) @dynamic => io::@read_byte_using_read(self); fn char! TestReader.read_byte(&self) @dynamic => io::read_byte_using_read(self);