mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
4 Commits
release_0.
...
v0.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d61ace302 | ||
|
|
a50c5f4f7c | ||
|
|
a46bf4fbe0 | ||
|
|
0d1eab5c15 |
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ fn Char32! StringIterator.next(&self)
|
||||
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
|
||||
self.current += read;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`
|
||||
*/
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -113,6 +113,7 @@ typedef enum
|
||||
CAST_SABOOL,
|
||||
CAST_SAPTR,
|
||||
CAST_SASA,
|
||||
CAST_SAARR,
|
||||
CAST_STRPTR,
|
||||
CAST_STINLINE,
|
||||
CAST_VECARR,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.5.0"
|
||||
#define COMPILER_VERSION "0.5.1"
|
||||
|
||||
8
test/test_suite/constants/assign_to_const.c3
Normal file
8
test/test_suite/constants/assign_to_const.c3
Normal 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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
17
test/unit/regression/cast_slice_to_arr.c3
Normal file
17
test/unit/regression/cast_slice_to_arr.c3
Normal 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 });
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user