Compare commits

...

4 Commits

32 changed files with 354 additions and 53 deletions

View File

@@ -99,8 +99,8 @@ jobs:
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
- shell: msys2 {0}
run: |
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-17.0.4-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-17.0.4-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-17.0.6-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-17.0.6-1-any.pkg.tar.zst
- name: CMake
run: |
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}

View File

@@ -280,6 +280,37 @@ fn void DString.append_char(&self, char c)
data.chars[data.len++] = c;
}
/**
* @require start < self.len()
* @require end < self.len()
* @require end >= start "End must be same or equal to the start"
**/
fn void DString.delete_range(&self, usz start, usz end)
{
self.delete(start, end - start + 1);
}
/**
* @require start < self.len()
* @require start + len <= self.len()
**/
fn void DString.delete(&self, usz start, usz len = 1)
{
if (!len) return;
StringData* data = self.data();
usz new_len = data.len - len;
if (new_len == 0)
{
data.len = 0;
return;
}
usz len_after = data.len - start - len;
if (len_after > 0)
{
data.chars[start:len_after] = data.chars[start + len:len_after];
}
data.len = new_len;
}
macro void DString.append(&self, value)
{

View File

@@ -444,6 +444,11 @@ fn String String.new_ascii_to_upper(s, Allocator* allocator = mem::heap())
return copy;
}
fn StringIterator String.iterator(s)
{
return { s, 0 };
}
fn String String.temp_ascii_to_upper(s)
{
return s.new_ascii_to_upper(mem::temp());
@@ -575,3 +580,38 @@ fn char! String.to_uchar(s) => s.to_integer(char);
fn double! String.to_double(s) => s.to_real(double);
fn float! String.to_float(s) => s.to_real(float);
fn Splitter String.splitter(self, String split)
{
return Splitter { self, split, 0 };
}
struct Splitter
{
String string;
String split;
usz current;
}
fn void Splitter.reset(&self)
{
self.current = 0;
}
fn String! Splitter.next(&self)
{
usz len = self.string.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
String remaining = self.string[current..];
usz! next = remaining.index_of(self.split);
if (try next)
{
defer self.current = current + next + self.split.len;
return remaining[:next];
}
self.current = len;
return remaining;
}

View File

@@ -20,4 +20,4 @@ fn Char32! StringIterator.next(&self)
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
self.current += read;
return res;
}
}

View File

@@ -138,6 +138,50 @@ fn char! File.read_byte(&self) @dynamic
return (char)c;
}
/**
* Load up to buffer.len characters. Returns IoError.OVERFLOW if the file is longer
* than the buffer.
*
* @param filename "The path to the file to read"
* @param [in] buffer "The buffer to read to"
**/
fn char[]! load_buffer(String filename, char[] buffer)
{
File file = open(filename, "rb")!;
defer (void)file.close();
usz len = file.seek(0, END)!;
if (len > buffer.len) return IoError.OVERFLOW?;
file.seek(0, SET)!;
usz read = 0;
while (read < len)
{
read += file.read(buffer[read:len - read])!;
}
return buffer[:len];
}
fn char[]! load_new(String filename, Allocator* allocator = mem::heap())
{
File file = open(filename, "rb")!;
defer (void)file.close();
usz len = file.seek(0, END)!;
file.seek(0, SET)!;
char* data = allocator.alloc_checked(len)!;
defer catch allocator.free(data);
usz read = 0;
while (read < len)
{
read += file.read(data[read:len - read])!;
}
return data[:len];
}
fn char[]! load_temp(String filename)
{
return load_new(filename, mem::temp());
}
/**
* @require self.file `File must be initialized`
*/

View File

@@ -49,7 +49,7 @@ fault IoError
* @param stream
* @require @is_instream(stream)
**/
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
{
bool $is_stream = @typeid(stream) == InStream*.typeid;
$if $is_stream:

View File

@@ -1,5 +1,15 @@
module libc @if(env::POSIX);
extern fn void* dlopen(ZString path, int flags);
extern fn CInt dlclose(void*);
extern fn void* dlsym(void* handle, ZString symbol);
const int RTLD_LAZY = 0x1;
const int RTLD_NOW = 0x2;
const int RTLD_LOCAL = 0x4;
const int RTLD_GLOBAL = 0x8;
def Pid_t = int;
def Uid_t = uint;
def Gid_t = uint;

View File

@@ -56,10 +56,21 @@ const CInt WNOHANG = 1;
const CInt WUNTRACES = 2;
JmpBuf backtrace_jmpbuf @local;
fn CInt backtrace(void** buffer, CInt size) @extern("backtrace") @weak
def BacktraceFn = fn CInt(void** buffer, CInt size);
fn CInt backtrace(void** buffer, CInt size)
{
if (size < 1) return 0;
void* handle = libc::dlopen("libc.so.6", libc::RTLD_LAZY);
if (handle)
{
BacktraceFn backtrace_fn = libc::dlsym(handle, "backtrace");
libc::dlclose(handle);
if (backtrace_fn)
{
return backtrace_fn(buffer, size);
}
}
// Loop through the return addresses until we hit a signal.
// This avoids using the frame address.
SignalFunction restore_backtrace = fn void(CInt) {

View File

@@ -1,5 +1,27 @@
# C3C Release Notes
## 0.5.1 Change list
### Changes / improvements
- Improved error messages for const errors.
- Do not link with debug libraries unless using static libraries.
- Add 'print-linking' build option.
- System linker may be used even if the target arch is different from current.
- Slice -> array/vector works for constant slice lenghts.
### Fixes
- On Aarch64 use the correct frame pointer type.
- On Aarch64 macOS, ensure the minimum version is 11.0 (Big Sur)
- Fixes to the yacc grammar.
- Dsym generation on macOS will correctly emit -arch.
- Stacktrace on signals on Linux when backtrace is available.
### Stdlib changes
- `delete` and `delete_range` added to DString.
- `Splitter` iterator added.
- `splitter` and `iterator` String methods.
- `load_new`, `load_buffer` and `load_temp` std::io::file functions.
## 0.5.0 Change List
### Changes / improvements

View File

@@ -41,6 +41,7 @@ int comment_level = 0;
"$alignof" { count(); return(CT_ALIGNOF); }
"$and" { count(); return(CT_AND); }
"$assert" { count(); return(CT_ASSERT); }
"$assignable" { count(); return(CT_ASSIGNABLE); }
"$case" { count(); return(CT_CASE); }
"$default" { count(); return(CT_DEFAULT); }
"$defined" { count(); return(CT_DEFINED); }
@@ -173,7 +174,7 @@ b64\'{B64}+\' { count(); return(BYTES); }
b64\"{B64}+\" { count(); return(BYTES); }
b64\`{B64}+\` { count(); return(BYTES); }
{INT}{E}{REALTYPE}? { count(); return(REAL); }
{INT}{E}?{REALTYPE}? { count(); return(REAL); }
0[xX]{HINT}{P}{REALTYPE}? { count(); return(REAL); }
{INT}"."{INT}{E}?{REALTYPE}? { count(); return(REAL); }
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { count(); return(REAL); }

View File

@@ -33,7 +33,7 @@ void yyerror(char *s);
%token CT_SIZEOF CT_STRINGIFY CT_QNAMEOF CT_OFFSETOF CT_VAEXPR CT_FEATURE
%token CT_EXTNAMEOF CT_EVAL CT_DEFINED CT_ALIGNOF ASSERT
%token ASM CHAR_LITERAL REAL TRUE FALSE CT_CONST_IDENT
%token LBRAPIPE RBRAPIPE HASH_CONST_IDENT CT_CASTABLE CT_ASSIGNABLE CT_AND CT_IS_CONST
%token LBRAPIPE RBRAPIPE HASH_CONST_IDENT CT_ASSIGNABLE CT_AND CT_IS_CONST
%start translation_unit
%%
@@ -142,7 +142,7 @@ base_expr
| expr_block
| ct_call '(' flat_path ')'
| ct_arg '(' expr ')'
| ct_analyse '(' expr ')'
| ct_analyse '(' expression_list ')'
| CT_VACOUNT
| CT_FEATURE '(' CONST_IDENT ')'
| CT_AND '(' expression_list ')'
@@ -522,8 +522,8 @@ base_type
| ANYFAULT
| ANY
| TYPEID
| TYPE_IDENT
| path TYPE_IDENT
| TYPE_IDENT opt_generic_parameters
| path TYPE_IDENT opt_generic_parameters
| CT_TYPE_IDENT
| CT_TYPEOF '(' expr ')'
| CT_TYPEFROM '(' constant_expr ')'
@@ -1095,8 +1095,12 @@ parameter
| CT_IDENT ELLIPSIS
;
func_definition
func_defintion_decl
: FN func_header fn_parameter_list opt_attributes ';'
;
func_definition
: func_defintion_decl
| FN func_header fn_parameter_list opt_attributes macro_func_body
;
@@ -1123,7 +1127,7 @@ generic_parameters
typedef_type
: func_typedef
| type opt_generic_parameters
| type
;
@@ -1189,8 +1193,8 @@ define_declaration
;
interface_body
: func_typedef
| interface_body func_typedef
: func_defintion_decl
| interface_body func_defintion_decl
;
interface_declaration
@@ -1199,7 +1203,7 @@ interface_declaration
;
distinct_declaration
: DISTINCT TYPE_IDENT opt_interface_impl opt_attributes '=' opt_inline type opt_generic_parameters ';'
: DISTINCT TYPE_IDENT opt_interface_impl opt_attributes '=' opt_inline type ';'
;
tl_ct_if

View File

@@ -379,6 +379,7 @@ typedef struct BuildOptions_
bool print_project_properties;
bool print_precedence;
bool print_build_settings;
bool print_linking;
bool benchmarking;
bool testing;
} BuildOptions;
@@ -450,6 +451,7 @@ typedef struct
bool testing;
bool read_stdin;
bool print_output;
bool print_linking;
bool no_entry;
int build_threads;
TrustLevel trust_level;

View File

@@ -123,6 +123,7 @@ static void usage(void)
OUTPUT(" -L <library dir> - Append the directory to the linker search paths.");
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
OUTPUT(" --system-linker=<yes|no> - Use the system linker (default: no for cross compilation, yes otherwise).");
OUTPUT(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
OUTPUT("");
OUTPUT(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
OUTPUT(" --link-libc=<yes|no> - Link libc other default libraries (default: yes).");
@@ -140,6 +141,7 @@ static void usage(void)
OUTPUT(" --fp-math=<option> - FP math behaviour: strict, relaxed, fast.");
OUTPUT("");
OUTPUT(" --debug-stats - Print debug statistics.");
OUTPUT(" --print-linking - Print linker arguments.");
#ifndef NDEBUG
OUTPUT(" --debug-log - Print debug logging to stdout.");
#endif
@@ -387,7 +389,7 @@ static void print_all_targets(void)
static void print_version(void)
{
OUTPUT("C3 Compiler Version (pre-alpha): %s", COMPILER_VERSION);
OUTPUT("C3 Compiler Version (alpha): %s", COMPILER_VERSION);
OUTPUT("Installed directory: %s", find_executable_path());
OUTPUT("LLVM version: %s", llvm_version);
OUTPUT("LLVM default target: %s", llvm_target);
@@ -747,6 +749,11 @@ static void parse_option(BuildOptions *options)
debug_stats = true;
return;
}
if (match_longopt("print-linking"))
{
options->print_linking = true;
return;
}
if (match_longopt("list-keywords"))
{
options->print_keywords = true;

View File

@@ -252,6 +252,7 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
{
target->arch_os_target = options->arch_os_target_override;
}
target->print_linking = options->print_linking;
if (options->reloc_model != RELOC_DEFAULT) target->reloc_model = options->reloc_model;
if (options->symtab_size) target->symtab_size = options->symtab_size;

View File

@@ -490,8 +490,25 @@ void compiler_compile(void)
{
error_exit("Cannot create exe with the name '%s' - there is already a directory with that name.", output_exe);
}
if (link_libc() && platform_target.os != OS_TYPE_WIN32
&& active_target.arch_os_target == default_target && active_target.system_linker != SYSTEM_LINKER_OFF)
bool system_linker_available = link_libc() && platform_target.os != OS_TYPE_WIN32;
bool use_system_linker = system_linker_available && active_target.arch_os_target == default_target;
switch (active_target.system_linker)
{
case SYSTEM_LINKER_ON:
if (!system_linker_available)
{
eprintf("System linker is not supported, defaulting to built-in linker\n");
break;
}
use_system_linker = true;
break;
case SYSTEM_LINKER_OFF:
use_system_linker = false;
break;
default:
break;
}
if (use_system_linker)
{
platform_linker(output_exe, obj_files, output_file_count);
compiler_link_time = bench_mark();
@@ -504,7 +521,7 @@ void compiler_compile(void)
if (!obj_format_linking_supported(platform_target.object_format) || !linker(output_exe, obj_files,
output_file_count))
{
printf("No linking is performed due to missing linker support.\n");
eprintf("No linking is performed due to missing linker support.\n");
active_target.run_after_compile = false;
}
else

View File

@@ -113,6 +113,7 @@ typedef enum
CAST_SABOOL,
CAST_SAPTR,
CAST_SASA,
CAST_SAARR,
CAST_STRPTR,
CAST_STINLINE,
CAST_VECARR,

View File

@@ -380,8 +380,10 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
case CAST_IDINT:
case CAST_INTARRBS:
case CAST_BSINTARR:
case CAST_SAARR:
if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false;
return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind);
}
UNREACHABLE
}

View File

@@ -98,6 +98,12 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
UNREACHABLE
}
if (!link_libc()) return;
bool link_with_dynamic_debug_libc = true;
#if !PLATFORM_WINDOWS
// The debug version of libc is usually not available on target machines,
// so we do not link with debug dll versions of libc.
link_with_dynamic_debug_libc = false;
#endif
if (!active_target.win.sdk)
{
const char *path = windows_cross_compile_library();
@@ -123,6 +129,9 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
if (file_exists(scratch_buffer_to_string()))
{
active_target.win.sdk = scratch_buffer_copy();
// If we only use the msvc cross compile on windows, we
// avoid linking with dynamic debug dlls.
link_with_dynamic_debug_libc = false;
}
}
}
@@ -171,7 +180,9 @@ static void linker_setup_windows(const char ***args_ref, LinkerType linker_type,
}
else
{
if (is_debug)
// When cross compiling we might not have the relevant debug libraries.
// if so, then exclude them.
if (is_debug && link_with_dynamic_debug_libc)
{
vec_add(*additional_linked_ref, "ucrtd");
vec_add(*additional_linked_ref, "vcruntimed");
@@ -284,6 +295,8 @@ static void linker_setup_macos(const char ***args_ref, LinkerType linker_type)
add_arg("CoreFoundation");
if (linker_type == LINKER_CC)
{
add_arg("-target");
add_arg(platform_target.target_triple);
return;
}
add_arg("-arch");
@@ -774,6 +787,7 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
vec_add(parts, "-lm");
}
const char *output = concat_string_parts(parts);
if (active_target.print_linking) puts(output);
if (system(output) != 0)
{
error_exit("Failed to link executable '%s' using command '%s'.\n", output_file, output);
@@ -782,7 +796,8 @@ void platform_linker(const char *output_file, const char **files, unsigned file_
{
// Create .dSYM
scratch_buffer_clear();
scratch_buffer_printf("dsymutil %s", output_file);
scratch_buffer_printf("dsymutil -arch %s %s", arch_to_linker_arch(platform_target.arch), output_file);
if (active_target.print_linking) puts(scratch_buffer_to_string());
if (system(scratch_buffer_to_string()) != 0)
{
puts("Failed to create .dSYM files, debugging will be impacted.");

View File

@@ -1067,7 +1067,7 @@ void llvm_append_function_attributes(GenContext *c, Decl *decl)
llvm_set_alignment(function, decl->alignment);
}
llvm_attribute_add(c, function, attribute_id.nounwind, -1);
llvm_attribute_add_int(c, function, attribute_id.uwtable, 2, -1);
llvm_attribute_add_int(c, function, attribute_id.uwtable, UWTABLE, -1);
if (decl->func_decl.attr_naked)
{

View File

@@ -1236,6 +1236,22 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type
}
void llvm_emit_subarray_to_vec_array_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type)
{
BEValue pointer;
Type *base = type_lowering(from_type)->array.base;
AlignSize element_alignment = type_abi_alignment(base);
llvm_emit_subarray_pointer(c, value, &pointer);
llvm_value_rvalue(c, &pointer);
LLVMTypeRef type = llvm_get_type(c, to_type);
AlignSize alignment = llvm_abi_alignment(c, type);
LLVMValueRef temp = llvm_emit_alloca(c, type, alignment, ".temp");
unsigned elements = LLVMGetTypeKind(type) == LLVMVectorTypeKind
? LLVMGetVectorSize(type) : LLVMGetArrayLength(type);
llvm_emit_memcpy(c, temp, alignment, pointer.value, element_alignment, elements);
llvm_value_set_address(value, temp, to_type, alignment);
}
void llvm_emit_expand_to_vec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type)
{
llvm_value_rvalue(c, value);
@@ -1356,6 +1372,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
switch (cast_kind)
{
case CAST_SAARR:
llvm_emit_subarray_to_vec_array_cast(c, value, to_type, from_type);
return;
case CAST_EXPVEC:
llvm_emit_expand_to_vec_cast(c, value, to_type, from_type);
return;

View File

@@ -522,6 +522,8 @@ void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index);
void llvm_emit_debug_local_var(GenContext *c, Decl *var);
void llvm_emit_debug_global_var(GenContext *c, Decl *global);
#define FRAMEPOINTER (platform_target.arch == ARCH_TYPE_AARCH64 ? 1 : 2)
#define UWTABLE (active_target.arch_os_target == MACOS_AARCH64 ? 1 : 2)
#define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0)
#define EMIT_SPAN(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x); } while (0)

View File

@@ -152,9 +152,9 @@ void gencontext_begin_module(GenContext *c)
{
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Dwarf Version", 4, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Debug Info Version", 3, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", 2, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", FRAMEPOINTER, type_uint);
}
llvm_set_module_flag(c, LLVMModuleFlagBehaviorError, "uwtable", 2, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorError, "uwtable", UWTABLE, type_uint);
c->debug.runtime_version = 1;
c->debug.builder = LLVMCreateDIBuilder(c->module);

View File

@@ -48,7 +48,6 @@ void recover_top_level(ParseContext *c)
case TOKEN_DEF:
case TOKEN_FAULT:
return;
case TOKEN_IDENT: // Incr arrays only
case TOKEN_CONST:
case TOKEN_ASM:
case TOKEN_CT_ASSERT:

View File

@@ -1859,10 +1859,24 @@ static void cast_sa_to_vecarr(SemaContext *context, Expr *expr, Type *to_type)
{
if (!expr_is_const(expr))
{
switch (expr->expr_kind)
{
case EXPR_CAST:
{
Expr *inner = exprptr(expr->cast_expr.expr)->unary_expr.expr;
expr_replace(expr, inner);
cast_no_check(context, expr, to_type, false);
return;
}
case EXPR_SLICE:
{
insert_runtime_cast(expr, CAST_SAARR, to_type);
return;
}
default:
UNREACHABLE;
}
assert(expr->expr_kind == EXPR_CAST);
Expr *inner = exprptr(expr->cast_expr.expr)->unary_expr.expr;
expr_replace(expr, inner);
cast_no_check(context, expr, to_type, false);
return;
}
assert(expr_is_const(expr));

View File

@@ -416,13 +416,11 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
Decl *decl = expr->identifier_expr.decl;
if (decl->decl_kind != DECL_VAR)
{
SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl));
return false;
RETURN_SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl));
}
if (decl->var.kind == VARDECL_CONST)
{
SEMA_ERROR(top_expr, "You cannot assign to a constant.");
return false;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant.");
}
decl = decl_raw(decl);
switch (decl->var.kind)
@@ -469,16 +467,16 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
case EXPR_SUBSCRIPT_ADDR:
if (IS_OPTIONAL(expr))
{
SEMA_ERROR(top_expr, "You cannot assign to an optional value.");
return false;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to an optional value.");
}
return true;
case EXPR_HASH_IDENT:
SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression.");
return false;
RETURN_SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression.");
case EXPR_EXPRESSION_LIST:
if (!vec_size(expr->expression_list)) return false;
return sema_binary_is_expr_lvalue(top_expr, VECLAST(expr->expression_list));
case EXPR_CONST:
RETURN_SEMA_ERROR(top_expr, "You cannot assign to a constant expression.");
case EXPR_POISONED:
case EXPR_ASM:
case EXPR_BINARY:
@@ -491,7 +489,6 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
case EXPR_COMPILER_CONST:
case EXPR_COMPOUND_LITERAL:
case EXPR_COND:
case EXPR_CONST:
case EXPR_CT_ARG:
case EXPR_CT_CALL:
case EXPR_CT_AND_OR:
@@ -4487,12 +4484,12 @@ static inline IndexDiff range_const_len(Range *range)
{
Expr *start = exprptr(range->start);
Expr *end = exprptrzero(range->end);
if (!expr_is_const_int(start)) return -1;
if (!end || !expr_is_const_int(end)) return -1;
if (!int_fits(end->const_expr.ixx, TYPE_I32)) return -1;
if (!int_fits(start->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff end_val = (IndexDiff)int_to_i64(end->const_expr.ixx);
if (range->is_len) return end_val;
if (!expr_is_const_int(start)) return -1;
if (!int_fits(start->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff start_val = (IndexDiff)int_to_i64(start->const_expr.ixx);
if (range->start_from_end && range->end_from_end) return start_val - end_val + 1;
if (range->start_from_end != range->end_from_end) return -1;
@@ -8390,7 +8387,11 @@ MemberIndex sema_len_from_const(Expr *expr)
// We also handle the case where we have a cast from a const array.
if (!expr_is_const(expr))
{
if (expr->type->type_kind != TYPE_SUBARRAY) return -1;
if (type_flatten(expr->type)->type_kind != TYPE_SUBARRAY) return -1;
if (expr->expr_kind == EXPR_SLICE)
{
return range_const_len(&expr->subscript_expr.range);
}
if (expr->expr_kind != EXPR_CAST) return -1;
if (expr->cast_expr.kind != CAST_APTSA) return -1;
Expr *inner = exprptr(expr->cast_expr.expr);

View File

@@ -1948,6 +1948,17 @@ void target_setup(BuildTarget *target)
{
DEBUG_LOG("Macos SDK: %s", sysroot);
active_target.macos.sdk = macos_sysroot_sdk_information(sysroot);
if (platform_target.arch == ARCH_TYPE_AARCH64)
{
if (active_target.macos.sdk->macos_min_deploy_target.major < 11)
{
active_target.macos.sdk->macos_min_deploy_target = (Version) { 11, 0 };
}
if (active_target.macos.sdk->macos_deploy_target.major < 11)
{
active_target.macos.sdk->macos_deploy_target = (Version) { 11, 0 };
}
}
}
platform_target.target_triple = strdup(llvm_macos_target_triple(platform_target.target_triple));

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.5.0"
#define COMPILER_VERSION "0.5.1"

View File

@@ -0,0 +1,8 @@
module test;
import std::io;
fn void main()
{
const NUM = 4;
NUM += 1; // #error: You cannot assign to a constant expression
}

View File

@@ -17,32 +17,32 @@ fn void test9()
fn void test10()
{
10 = 20; // #error: An assignable expression
10 = 20; // #error: to a constant expression
}
fn void test11()
{
'10' = '20'; // #error: An assignable expression
'10' = '20'; // #error: to a constant expression
}
fn void test12()
{
true = false; // #error: An assignable expression
true = false; // #error: to a constant expression
}
fn void test13()
{
"a" = "b"; // #error: An assignable expression
"a" = "b"; // #error: to a constant expression
}
fn void test14()
{
1.2 = 1.3; // #error: An assignable expression
1.2 = 1.3; // #error: to a constant expression
}
fn void test15()
{
null = null; // #error: An assignable expression
null = null; // #error: to a constant expression
}
fn void test16()

View File

@@ -2,27 +2,27 @@ def Number = int;
fn void test1()
{
10 = 20; // #error: An assignable expression
10 = 20; // #error: to a constant expression
}
fn void test2()
{
"foo" = "bar"; // #error: An assignable expression
"foo" = "bar"; // #error: to a constant expression
}
fn void test3()
{
true = false; // #error: An assignable expression
true = false; // #error: to a constant expression
}
fn void test4()
{
'c' = 'd'; // #error: An assignable expression
'c' = 'd'; // #error: to a constant expression
}
fn void test5()
{
3.14 = 2.14; // #error: An assignable expression
3.14 = 2.14; // #error: to a constant expression
}
fn void test21()

View File

@@ -0,0 +1,17 @@
module slice_to_arr @test;
fn void to_arr()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[2] y = x[z:2];
assert(y == int[2]{ 3, 4 });
}
fn void to_vec()
{
int[] x = { 1, 2, 3, 4, 5 };
int z = 2;
int[<2>] y = x[z:2];
assert(y == { 3, 4 });
}

View File

@@ -2,6 +2,28 @@ module std::core::dstring2 @test;
const TEST_STRING = "hello world";
fn void test_delete()
{
{
DString d;
d.append("Hello cruel world.");
d.delete_range(5, 10);
assert(d.str_view() == "Hello world.");
}
DString d;
d.append("Hello cruel world.");
d.delete(0, 2);
assert(d.str_view() == "llo cruel world.");
d.delete(14, 2);
assert(d.str_view() == "llo cruel worl");
d.delete(7);
assert(d.str_view() == "llo crul worl");
d.delete(2, 0);
assert(d.str_view() == "llo crul worl");
d.delete(0, 1);
assert(d.str_view() == "lo crul worl");
}
fn void test_append()
{
DString str = dstring::new(TEST_STRING);