commit 33d98c62e5201d8ce5e5436096615915e6d7e6c3
parent e7429a445bea41bca5c1199bb98c3ca6ddced92e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 25 May 2026 13:12:17 -0700
cc: support default symbol visibility
Diffstat:
6 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/driver/cc.c b/driver/cc.c
@@ -132,6 +132,7 @@ typedef struct CcOptions {
uint16_t pe_subsystem; /* CfreePeSubsystem */
const char* sysroot; /* --sysroot / -isysroot */
int freestanding; /* -ffreestanding (suppresses sysroot headers) */
+ uint8_t default_visibility; /* CfreeSymVis; -fvisibility=... */
int nostdinc; /* -nostdinc (suppresses sysroot headers) */
const char* support_dir; /* --support-dir */
int probe_kind; /* CcProbeKind */
@@ -1154,6 +1155,19 @@ static int cc_parse(int argc, char** argv, CcOptions* o) {
o->freestanding = 1;
continue;
}
+ if (driver_streq(a, "-fvisibility=hidden")) {
+ o->default_visibility = CFREE_SV_HIDDEN;
+ continue;
+ }
+ if (driver_streq(a, "-fvisibility=default")) {
+ o->default_visibility = CFREE_SV_DEFAULT;
+ continue;
+ }
+ if (driver_strneq(a, "-fvisibility=", 13)) {
+ driver_errf(CC_TOOL, "unsupported visibility: %.*s",
+ CFREE_SLICE_ARG(cfree_slice_cstr(a + 13)));
+ return 1;
+ }
if (driver_streq(a, "-fhosted")) {
o->freestanding = 0;
continue;
@@ -2089,6 +2103,7 @@ static void cc_fill_c_opts(const CcOptions* o, const CfreePreprocessOptions* pp,
copts->code.opt_level = o->syntax_only ? 0 : o->opt_level;
copts->code.debug_info = o->debug_info;
copts->code.check_only = o->syntax_only ? true : false;
+ copts->code.default_visibility = o->default_visibility;
copts->code.emit_c_source = o->emit_c_source ? true : false;
copts->code.emit_asm_source = o->emit_asm_source ? true : false;
copts->code.epoch = o->epoch;
diff --git a/include/cfree/core.h b/include/cfree/core.h
@@ -198,6 +198,7 @@ typedef struct CfreeCodeOptions {
/* Run the frontend and CG validation path without emitting target code.
* Drivers use this for syntax/semantic checking modes. */
bool check_only;
+ uint8_t default_visibility; /* CfreeSymVis; 0 => CFREE_SV_DEFAULT */
/* When set, CG emits portable C source instead of machine-code bytes.
* The TU is still target-locked: the emitted source uses the configured
* triple's struct layouts and pointer width. Forces opt_level=0.
diff --git a/lang/c/c.c b/lang/c/c.c
@@ -116,7 +116,8 @@ static CfreeStatus c_frontend_compile(
cfree_frontend_metrics_scope_end(c, "compile.c.pp_push_input");
cfree_frontend_metrics_scope_begin(c, "compile.c.parse_codegen");
- parse_c(c, pool, pp, decls, cg);
+ parse_c(c, pool, pp, decls, cg,
+ (CfreeSymVis)opts->code.default_visibility);
cfree_frontend_metrics_scope_end(c, "compile.c.parse_codegen");
cfree_frontend_metrics_scope_begin(c, "compile.c.cleanup");
diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c
@@ -820,7 +820,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) {
decl_in.loc = loc;
decl_in.storage = DS_EXTERN;
decl_in.linkage = DL_EXTERNAL;
- decl_in.visibility = SV_DEFAULT;
+ decl_in.visibility = p->default_visibility;
decl_in.flags = specs->flags & DF_THREAD;
attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in);
did = decl_declare(p->decls, &decl_in);
@@ -1100,7 +1100,8 @@ static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty,
: DS_EXTERN;
decl_in.linkage =
(decl_in.storage == DS_STATIC) ? DL_INTERNAL : DL_EXTERNAL;
- decl_in.visibility = SV_DEFAULT;
+ decl_in.visibility =
+ decl_in.linkage == DL_EXTERNAL ? p->default_visibility : SV_DEFAULT;
attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in);
attr_list_to_decl(p->c, p->decls, dattrs, &decl_in);
did = decl_declare(p->decls, &decl_in);
@@ -1310,7 +1311,11 @@ static void parse_external_decl(Parser* p) {
alias.target = te->v.sym;
alias.sym.bind =
(fn_decl_flags & DF_WEAK) ? CFREE_SB_WEAK : CFREE_SB_GLOBAL;
- alias.sym.visibility = CFREE_CG_VIS_DEFAULT;
+ {
+ const Decl* fd = decl_get(p->decls, fent->decl_id);
+ alias.sym.visibility =
+ fd ? (CfreeCgVisibility)fd->visibility : CFREE_CG_VIS_DEFAULT;
+ }
if (cfree_cg_alias(p->cg, alias) == CFREE_CG_SYM_NONE) {
const char* nm = cfree_sym_str(p->pool->c, fn_alias_target).s;
compiler_panic(p->c, loc, "alias target '%.*s' is undefined",
@@ -1368,7 +1373,8 @@ static void parse_external_decl(Parser* p) {
decl_in.storage = DS_EXTERN;
decl_in.linkage = DL_EXTERNAL;
}
- decl_in.visibility = SV_DEFAULT;
+ decl_in.visibility =
+ decl_in.linkage == DL_EXTERNAL ? p->default_visibility : SV_DEFAULT;
decl_in.flags = specs.flags & DF_THREAD;
attr_list_to_decl(p->c, p->decls, specs.attrs, &decl_in);
attr_list_to_decl(p->c, p->decls, dattrs, &decl_in);
@@ -1476,7 +1482,21 @@ static void parse_translation_unit(Parser* p) {
* Entry point
* ============================================================ */
-void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg) {
+static u8 parser_default_visibility(CfreeSymVis vis) {
+ switch (vis) {
+ case CFREE_SV_HIDDEN:
+ case CFREE_SV_INTERNAL:
+ return SV_HIDDEN;
+ case CFREE_SV_PROTECTED:
+ return SV_PROTECTED;
+ case CFREE_SV_DEFAULT:
+ default:
+ return SV_DEFAULT;
+ }
+}
+
+void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg,
+ CfreeSymVis default_visibility) {
Parser p;
CKw i;
@@ -1487,6 +1507,7 @@ void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg) {
p.cg = cg;
p.abi = c;
p.pool = pool;
+ p.default_visibility = parser_default_visibility(default_visibility);
for (i = (CKw)1; i < KW_COUNT; ++i) {
p.kw_sym[i] = cfree_sym_intern(p.pool->c, cfree_slice_cstr(kw_names[i]));
diff --git a/lang/c/parse/parse.h b/lang/c/parse/parse.h
@@ -7,6 +7,6 @@
/* C11 frontend. Reads preprocessed tokens, records C declarations, and drives
* the public CG API for executable code and object data. */
-void parse_c(Compiler*, Pool*, Pp*, DeclTable*, CG*);
+void parse_c(Compiler*, Pool*, Pp*, DeclTable*, CG*, CfreeSymVis);
#endif
diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h
@@ -194,6 +194,7 @@ typedef struct Parser {
CG* cg;
TargetABI* abi;
Pool* pool;
+ u8 default_visibility; /* SymVis */
const Type** cg_type_stack;
u8* cg_value_flags;