mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Do not allow parameters in naked functions.
This commit is contained in:
@@ -87,7 +87,7 @@
|
||||
- Lambdas now properly follow its attributes #2346.
|
||||
- Not setting android-ndk resulted in a "set ndk-path" error.
|
||||
- Lambda deduplication would be incorrect when generated at the global scope.
|
||||
- Allow accessing parameters in a naked function, just disallow `return`, this fixes #1955.
|
||||
- Disallow accessing parameters in a naked function, as well as `return`, this fixes #1955.
|
||||
|
||||
### Stdlib changes
|
||||
- Improve contract for readline. #2280
|
||||
|
||||
@@ -497,6 +497,7 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, FunctionPrototype *pro
|
||||
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
|
||||
FOREACH_IDX(i, Decl *, param, signature->params)
|
||||
{
|
||||
if (!param->name && is_naked) continue;
|
||||
llvm_emit_func_parameter(c, param, prototype->abi_args[i], &arg, i);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,29 @@ static inline AsmArgGroup sema_ireg_for_type(Type *type)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static inline Decl *sema_resolve_external_symbol(SemaContext *context, Expr *expr, const char *name)
|
||||
{
|
||||
Decl *decl = sema_resolve_symbol(context, name, NULL, expr->span);
|
||||
if (!decl) return NULL;
|
||||
|
||||
if (decl->decl_kind != DECL_VAR)
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected a global or local variable.");
|
||||
return NULL;
|
||||
}
|
||||
if (IS_OPTIONAL(decl))
|
||||
{
|
||||
SEMA_ERROR(expr, "Optional variables are not allowed in asm.");
|
||||
return NULL;
|
||||
}
|
||||
if (decl->var.kind == VARDECL_PARAM && context->call_env.is_naked_fn)
|
||||
{
|
||||
SEMA_ERROR(expr, "Function parameters in '@naked' functions may not be directly referenced.");
|
||||
return NULL;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
static inline bool sema_reg_int_suported_type(AsmArgType arg, Type *type)
|
||||
{
|
||||
ASSERT(type_flatten(type) == type);
|
||||
@@ -347,21 +370,11 @@ static inline bool sema_check_asm_var(SemaContext *context, AsmInlineBlock *bloc
|
||||
{
|
||||
ExprAsmArg *arg = &expr->expr_asm_arg;
|
||||
const char *name = arg->ident.name;
|
||||
Decl *decl = sema_resolve_symbol(context, name, NULL, expr->span);
|
||||
Decl *decl = sema_resolve_external_symbol(context, expr, name);
|
||||
if (!decl) return false;
|
||||
|
||||
ASSERT(arg->kind == ASM_ARG_REGVAR);
|
||||
arg->ident.ident_decl = decl;
|
||||
if (decl->decl_kind != DECL_VAR)
|
||||
{
|
||||
SEMA_ERROR(expr, "Expected a global or local variable.");
|
||||
return false;
|
||||
}
|
||||
if (IS_OPTIONAL(decl))
|
||||
{
|
||||
SEMA_ERROR(expr, "Optional variables are not allowed in asm.");
|
||||
return false;
|
||||
}
|
||||
bool is_write = arg_type.is_write;
|
||||
bool is_read = !arg_type.is_write || arg_type.is_readwrite;
|
||||
arg->ident.is_input = !is_write;
|
||||
@@ -441,18 +454,10 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
|
||||
{
|
||||
ExprAsmArg *arg = &expr->expr_asm_arg;
|
||||
const char *name = arg->ident.name;
|
||||
Decl *decl = sema_resolve_symbol(context, name, NULL, expr->span);
|
||||
Decl *decl = sema_resolve_external_symbol(context, expr, name);
|
||||
if (!decl) return false;
|
||||
ASSERT(arg->kind == ASM_ARG_MEMVAR);
|
||||
arg->ident.ident_decl = decl;
|
||||
if (decl->decl_kind != DECL_VAR)
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "Expected a global or local variable.");
|
||||
}
|
||||
if (IS_OPTIONAL(decl))
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "Optional variables are not allowed in asm.");
|
||||
}
|
||||
bool is_write = arg_type.is_write;
|
||||
bool is_read = !arg_type.is_write || arg_type.is_readwrite;
|
||||
arg->ident.is_input = !is_write;
|
||||
|
||||
@@ -1262,12 +1262,18 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case VARDECL_PARAM:
|
||||
if (context->call_env.is_naked_fn)
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "Parameters may not be directly accessed in '@naked' functions.");
|
||||
}
|
||||
break;
|
||||
case VARDECL_GLOBAL:
|
||||
if (context->call_env.pure)
|
||||
{
|
||||
SEMA_ERROR(expr, "'@pure' functions may not access globals.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR(expr, "'@pure' functions may not access globals.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
char[8] foo = {255, 0, 0, 0, 0, 0, 0, 0};
|
||||
io::printn(to_ulong(&foo));
|
||||
ulong a = to_ulong2(&foo);
|
||||
ulong b = to_ulong(&foo);
|
||||
}
|
||||
|
||||
fn ulong to_ulong(char[8]* buf) @naked @noinline
|
||||
fn ulong to_ulong(char[8]*) @naked @noinline
|
||||
{
|
||||
asm
|
||||
{
|
||||
movq $rax, [buf];
|
||||
movq [$rsp - 8], $rdi;
|
||||
movq $rax, [$rsp - 8];
|
||||
movq $rax, [$rax];
|
||||
ret;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
fn ulong to_ulong2(char[8]* buf)
|
||||
{
|
||||
return *(ulong*)buf;
|
||||
}
|
||||
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i64 @test.to_ulong(ptr %0) #1 {
|
||||
entry:
|
||||
call void asm sideeffect alignstack "movq ($0), %rax\0Aret \0A", "r,~{rax},~{flags},~{dirflag},~{fspr}"(ptr %0)
|
||||
call void asm sideeffect alignstack "movq %rdi, -8(%rsp)\0Amovq -8(%rsp), %rax\0Amovq (%rax), %rax\0Aret \0A", "~{rax},~{flags},~{dirflag},~{fspr}"()
|
||||
unreachable
|
||||
}
|
||||
|
||||
attributes #1 = { naked noinline nounwind uwtable "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
|
||||
|
||||
@@ -10,4 +10,10 @@ fn ulong? test() @naked @noinline
|
||||
int? z;
|
||||
z!; // #error: Rethrow is not allowed in a '@naked' function
|
||||
unreachable();
|
||||
}
|
||||
|
||||
fn ulong test2(int a) @naked @noinline
|
||||
{
|
||||
int x = a; // #error: Parameters may not be directly accessed in '@naked' functions
|
||||
unreachable();
|
||||
}
|
||||
Reference in New Issue
Block a user