Skip to content

Commit 903c062

Browse files
committed
Implement operators __static_assert and __static_check
1 parent 3dfad1f commit 903c062

File tree

5 files changed

+117
-3
lines changed

5 files changed

+117
-3
lines changed

source/compiler/sc.h

+3
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ enum {
420420
tSLEEP,
421421
tSTATE,
422422
tSTATIC,
423+
t__STATIC_ASSERT,
424+
t__STATIC_CHECK,
423425
tSTOCK,
424426
tSWITCH,
425427
tTAGOF,
@@ -704,6 +706,7 @@ SC_FUNC void emit_parse_line(void);
704706
SC_FUNC void pragma_deprecated(symbol *sym);
705707
SC_FUNC void pragma_unused(symbol *sym,int unread,int unwritten);
706708
SC_FUNC void pragma_nodestruct(symbol *sym);
709+
SC_FUNC cell do_static_check(int use_warning);
707710

708711
/* function prototypes in SC2.C */
709712
#define PUSHSTK_P(v) { stkitem s_; s_.pv=(v); pushstk(s_); }

source/compiler/sc1.c

+100
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,13 @@ static void parse(void)
18021802
case tFORWARD:
18031803
funcstub(FALSE);
18041804
break;
1805+
case t__STATIC_ASSERT:
1806+
case t__STATIC_CHECK: {
1807+
int use_warning=(tok==t__STATIC_CHECK);
1808+
do_static_check(use_warning);
1809+
needtoken(';');
1810+
break;
1811+
} /* case */
18051812
case '}':
18061813
error(54); /* unmatched closing brace */
18071814
break;
@@ -8530,3 +8537,96 @@ SC_FUNC void pragma_nodestruct(symbol *sym)
85308537
if (sym->ident==iVARIABLE || sym->ident==iARRAY)
85318538
sym->usage |= uNODESTRUCT;
85328539
}
8540+
8541+
/* do_static_check()
8542+
* Checks compile-time assertions and triggers an error/warning.
8543+
*
8544+
* The 'use_warning' parameter is set to TRUE if warnings are to be
8545+
* used instead of errors to notify assertion failures.
8546+
*/
8547+
SC_FUNC cell do_static_check(int use_warning)
8548+
{
8549+
int already_staging,didalloc,optmsg;
8550+
int ident,index;
8551+
int bck_litidx;
8552+
int exprstartfline,exprendfline;
8553+
cell cidx,val;
8554+
char *str;
8555+
const unsigned char *exprstart,*exprend;
8556+
8557+
str=NULL;
8558+
didalloc=optmsg=FALSE;
8559+
index=0;
8560+
cidx=0;
8561+
8562+
needtoken('(');
8563+
already_staging=stgget(&index,&cidx);
8564+
if (!already_staging) {
8565+
stgset(TRUE); /* start stage-buffering */
8566+
errorset(sEXPRMARK,0);
8567+
} /* if */
8568+
exprstart=lptr;
8569+
exprstartfline=fline;
8570+
ident=expression(&val,NULL,NULL,FALSE);
8571+
if (ident!=iCONSTEXPR)
8572+
error(8); /* must be constant expression */
8573+
exprend=lptr;
8574+
exprendfline=fline;
8575+
stgdel(index,cidx); /* scratch generated code */
8576+
if (!already_staging) {
8577+
errorset(sEXPRRELEASE,0);
8578+
stgset(FALSE); /* stop stage-buffering */
8579+
} /* if */
8580+
8581+
/* don't bother allocating space and copying the message
8582+
* if the expression is true */
8583+
if (val==0) {
8584+
if (exprstartfline==exprendfline) {
8585+
/* skip leading whitespaces */
8586+
while (*exprstart==' ')
8587+
exprstart++;
8588+
/* strip the trailing ',' or ')'. as well as the whitespaces */
8589+
exprend--;
8590+
if (*exprend==')' || *exprend==',') {
8591+
while (*(exprend-1)==' ')
8592+
exprend--;
8593+
} /* if */
8594+
/* copy the expression string */
8595+
str=malloc((exprend-exprstart+1)*sizeof(char));
8596+
if (str==NULL)
8597+
error(103); /* insufficient memory */
8598+
memcpy(str,exprstart,exprend-exprstart);
8599+
str[exprend-exprstart]='\0';
8600+
didalloc=TRUE;
8601+
} else {
8602+
/* Currently there's no reliable way to capture multiline expressions,
8603+
* as the lexer would only keep the contents of the line the expression
8604+
* ends at, so try to print "-epression-" instead. Not the prefect
8605+
* solution, but at least it's better than not printing anything. */
8606+
str="-expression-";
8607+
} /* if */
8608+
} /* if */
8609+
8610+
/* read the optional message */
8611+
if (matchtoken(',')) {
8612+
if (didalloc) {
8613+
free(str);
8614+
didalloc=FALSE;
8615+
} /* if */
8616+
optmsg=TRUE;
8617+
str=parsestringparam(val!=0,&bck_litidx);
8618+
} /* if */
8619+
8620+
if (val==0) {
8621+
int errnum=use_warning ? 249 /* check failed */
8622+
: 110; /* assertion failed */
8623+
error(errnum,(str!=NULL) ? str : "");
8624+
if (didalloc)
8625+
free(str);
8626+
else if (optmsg && str!=NULL)
8627+
litidx=bck_litidx; /* remove the string from the literal queue */
8628+
} /* if */
8629+
8630+
needtoken(')');
8631+
return !!val;
8632+
}

source/compiler/sc3.c

+10
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,16 @@ static int hier2(value *lval)
16271627
} /* if */
16281628
return FALSE;
16291629
} /* case */
1630+
case t__STATIC_ASSERT:
1631+
case t__STATIC_CHECK: {
1632+
int use_warning=(tok==t__STATIC_CHECK);
1633+
clear_value(lval);
1634+
lval->ident=iCONSTEXPR;
1635+
lval->constval=do_static_check(use_warning);
1636+
lval->tag=BOOLTAG;
1637+
pc_sideeffect=TRUE;
1638+
return FALSE;
1639+
} /* case */
16301640
case t__EMIT:
16311641
paranthese=matchtoken('(');
16321642
emit_flags |= efEXPR;

source/compiler/sc5.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ static char *warnmsg[] = {
206206
/*245*/ "enum increment \"%s %d\" has no effect on zero value (symbol \"%s\")\n",
207207
/*246*/ "multiplication overflow in enum element declaration (symbol \"%s\")\n",
208208
/*247*/ "use of operator \"~\" on a \"bool:\" value always results in \"true\"\n",
209-
/*248*/ "possible misuse of comma operator\n"
209+
/*248*/ "possible misuse of comma operator\n",
210+
/*249*/ "check failed: %s\n"
210211
};
211212

212213
static char *noticemsg[] = {

source/compiler/scvars.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ SC_VDEFINE char *sc_tokens[] = {
111111
"__addressof", "assert", "*begin", "break", "case", "char", "const", "continue",
112112
"default", "defined", "do", "else", "__emit", "*end", "enum", "exit", "for",
113113
"forward", "goto", "if", "__nameof", "native", "new", "operator", "__pragma",
114-
"public", "return", "sizeof", "sleep", "state", "static", "stock", "switch",
115-
"tagof", "*then", "while",
114+
"public", "return", "sizeof", "sleep", "state", "static", "__static_assert",
115+
"__static_check", "stock", "switch", "tagof", "*then", "while",
116116
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",
117117
"#endscript", "#error", "#file", "#if", "#include", "#line", "#pragma",
118118
"#tryinclude", "#undef", "#warning",

0 commit comments

Comments
 (0)