Add support for static_assert
Add C11's _Static_assert and static_assert macro. This is like #error, but is handled at a later stage of translation, so it is possible to check sizes of types, values of enums, etc. https://en.cppreference.com/w/c/language/_Static_assert https://port70.net/~nsz/c/c11/n1570.html#6.7.10
This commit is contained in:
parent
c72fa735b9
commit
3df6c383c0
10 changed files with 274 additions and 0 deletions
|
@ -46,6 +46,12 @@ extern void __fastcall__ _afailed (const char*, unsigned);
|
||||||
# define assert(expr) ((expr)? (void)0 : _afailed(__FILE__, __LINE__))
|
# define assert(expr) ((expr)? (void)0 : _afailed(__FILE__, __LINE__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** TODO: Guard with #if __STDC_VERSION__ >= 201112L or similar when there
|
||||||
|
** is a C11 mode.
|
||||||
|
*/
|
||||||
|
#define static_assert _Static_assert
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of assert.h */
|
/* End of assert.h */
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#include "pragma.h"
|
#include "pragma.h"
|
||||||
#include "preproc.h"
|
#include "preproc.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
|
#include "staticassert.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +109,12 @@ static void Parse (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for a _Static_assert */
|
||||||
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
|
ParseStaticAssert ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read variable defs and functions */
|
/* Read variable defs and functions */
|
||||||
ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
|
ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@
|
||||||
#include "pragma.h"
|
#include "pragma.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
|
#include "staticassert.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "wrappedcall.h"
|
#include "wrappedcall.h"
|
||||||
#include "typeconv.h"
|
#include "typeconv.h"
|
||||||
|
@ -935,6 +936,13 @@ static SymEntry* ParseStructDecl (const char* Name)
|
||||||
|
|
||||||
/* Get the type of the entry */
|
/* Get the type of the entry */
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
|
||||||
|
/* Check for a _Static_assert */
|
||||||
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
|
ParseStaticAssert ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
InitDeclSpec (&Spec);
|
InitDeclSpec (&Spec);
|
||||||
ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
|
ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "locals.h"
|
#include "locals.h"
|
||||||
#include "stackptr.h"
|
#include "stackptr.h"
|
||||||
#include "standard.h"
|
#include "standard.h"
|
||||||
|
#include "staticassert.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "typeconv.h"
|
#include "typeconv.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
@ -511,6 +512,13 @@ void DeclareLocals (void)
|
||||||
** declarations.
|
** declarations.
|
||||||
*/
|
*/
|
||||||
DeclSpec Spec;
|
DeclSpec Spec;
|
||||||
|
|
||||||
|
/* Check for a _Static_assert */
|
||||||
|
if (CurTok.Tok == TOK_STATIC_ASSERT) {
|
||||||
|
ParseStaticAssert ();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||||
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
||||||
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
||||||
|
|
|
@ -86,6 +86,7 @@ static const struct Keyword {
|
||||||
unsigned char Std; /* Token supported in which standards? */
|
unsigned char Std; /* Token supported in which standards? */
|
||||||
} Keywords [] = {
|
} Keywords [] = {
|
||||||
{ "_Pragma", TOK_PRAGMA, TT_C89 | TT_C99 | TT_CC65 }, /* !! */
|
{ "_Pragma", TOK_PRAGMA, TT_C89 | TT_C99 | TT_CC65 }, /* !! */
|
||||||
|
{ "_Static_assert", TOK_STATIC_ASSERT, TT_CC65 }, /* C11 */
|
||||||
{ "__AX__", TOK_AX, TT_C89 | TT_C99 | TT_CC65 },
|
{ "__AX__", TOK_AX, TT_C89 | TT_C99 | TT_CC65 },
|
||||||
{ "__A__", TOK_A, TT_C89 | TT_C99 | TT_CC65 },
|
{ "__A__", TOK_A, TT_C89 | TT_C99 | TT_CC65 },
|
||||||
{ "__EAX__", TOK_EAX, TT_C89 | TT_C99 | TT_CC65 },
|
{ "__EAX__", TOK_EAX, TT_C89 | TT_C99 | TT_CC65 },
|
||||||
|
|
|
@ -173,6 +173,7 @@ typedef enum token_t {
|
||||||
TOK_WCSCONST,
|
TOK_WCSCONST,
|
||||||
|
|
||||||
TOK_ATTRIBUTE,
|
TOK_ATTRIBUTE,
|
||||||
|
TOK_STATIC_ASSERT,
|
||||||
TOK_FAR,
|
TOK_FAR,
|
||||||
TOK_NEAR,
|
TOK_NEAR,
|
||||||
TOK_A,
|
TOK_A,
|
||||||
|
|
96
src/cc65/staticassert.c
Normal file
96
src/cc65/staticassert.c
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* staticassert.h */
|
||||||
|
/* */
|
||||||
|
/* _Static_assert handling for the cc65 C compiler */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2020 Google LLC */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
|
#include "error.h"
|
||||||
|
#include "expr.h"
|
||||||
|
#include "litpool.h"
|
||||||
|
#include "scanner.h"
|
||||||
|
#include "staticassert.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* _Static_assert handling functions */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ParseStaticAssert ()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
** static_assert-declaration ::=
|
||||||
|
** _Static_assert ( constant-expression , string-literal ) ;
|
||||||
|
*/
|
||||||
|
ExprDesc Expr;
|
||||||
|
int failed;
|
||||||
|
|
||||||
|
/* Skip the _Static_assert token itself */
|
||||||
|
CHECK (CurTok.Tok == TOK_STATIC_ASSERT);
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* We expect an opening paren */
|
||||||
|
if (!ConsumeLParen ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse assertion condition */
|
||||||
|
ConstAbsIntExpr (hie1, &Expr);
|
||||||
|
failed = !Expr.IVal;
|
||||||
|
|
||||||
|
/* We expect a comma */
|
||||||
|
if (!ConsumeComma ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* String literal */
|
||||||
|
if (CurTok.Tok != TOK_SCONST) {
|
||||||
|
Error ("String literal expected for static_assert message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue an error including the message if the static_assert failed. */
|
||||||
|
if (failed) {
|
||||||
|
Error ("static_assert failed '%s'", GetLiteralStr (CurTok.SVal));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Consume the string constant, now that we don't need it anymore.
|
||||||
|
** This should never fail since we checked the token type above.
|
||||||
|
*/
|
||||||
|
if (!Consume (TOK_SCONST, "String literal expected")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closing paren and semi-colon needed */
|
||||||
|
ConsumeRParen ();
|
||||||
|
ConsumeSemi ();
|
||||||
|
}
|
51
src/cc65/staticassert.h
Normal file
51
src/cc65/staticassert.h
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* */
|
||||||
|
/* staticassert.h */
|
||||||
|
/* */
|
||||||
|
/* _Static_assert handling for the cc65 C compiler */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* Copyright 2020 Google LLC */
|
||||||
|
/* */
|
||||||
|
/* */
|
||||||
|
/* This software is provided 'as-is', without any expressed or implied */
|
||||||
|
/* warranty. In no event will the authors be held liable for any damages */
|
||||||
|
/* arising from the use of this software. */
|
||||||
|
/* */
|
||||||
|
/* Permission is granted to anyone to use this software for any purpose, */
|
||||||
|
/* including commercial applications, and to alter it and redistribute it */
|
||||||
|
/* freely, subject to the following restrictions: */
|
||||||
|
/* */
|
||||||
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
||||||
|
/* claim that you wrote the original software. If you use this software */
|
||||||
|
/* in a product, an acknowledgment in the product documentation would be */
|
||||||
|
/* appreciated but is not required. */
|
||||||
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
||||||
|
/* be misrepresented as being the original software. */
|
||||||
|
/* 3. This notice may not be removed or altered from any source */
|
||||||
|
/* distribution. */
|
||||||
|
/* */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef STATICASSERT_H
|
||||||
|
#define STATICASSERT_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Code */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ParseStaticAssert (void);
|
||||||
|
/* Handle _Static_assert. These are a C11 feature. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of staticassert.h */
|
||||||
|
|
||||||
|
#endif
|
26
test/err/staticassert.c
Normal file
26
test/err/staticassert.c
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Google LLC
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Test of failing _Static_assert.
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
_Static_assert(0, "0 should be false.");
|
70
test/val/staticassert.c
Normal file
70
test/val/staticassert.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Google LLC
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Tests of passing _Static_asserts.
|
||||||
|
**/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
_Static_assert (1, "1 should be true.");
|
||||||
|
_Static_assert (!0, "!0 should be true.");
|
||||||
|
_Static_assert (1 == 1, "1 == 1 should be true.");
|
||||||
|
_Static_assert (1 == 1L, "1 == 1L should be true.");
|
||||||
|
_Static_assert (1 != 0, "1 != 0 should be true.");
|
||||||
|
_Static_assert (sizeof (char) == 1, "sizeof (char) should be 1.");
|
||||||
|
_Static_assert (sizeof (int) == 2, "sizeof (int) should be 2.");
|
||||||
|
|
||||||
|
/* Make sure we can also do structs. */
|
||||||
|
struct sc { char a; };
|
||||||
|
_Static_assert (sizeof (struct sc) == 1, "sizeof (struct sc) should be 1.");
|
||||||
|
struct si { int a; };
|
||||||
|
_Static_assert (sizeof (struct si) == 2, "sizeof (struct si) should be 2.");
|
||||||
|
|
||||||
|
/* Try enums. */
|
||||||
|
enum { k = 1 };
|
||||||
|
_Static_assert (k == 1, "k should be 1.");
|
||||||
|
|
||||||
|
/* Just test the macro version once. */
|
||||||
|
static_assert (1, "1 should be true.");
|
||||||
|
|
||||||
|
/* _Static_assert can appear anywhere a declaration can. */
|
||||||
|
void f (void)
|
||||||
|
{
|
||||||
|
_Static_assert (1, "1 should still be true.");
|
||||||
|
if (1) {
|
||||||
|
_Static_assert (1, "1 should still be true.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _Static_assert can also appear in structs. */
|
||||||
|
struct S {
|
||||||
|
int a;
|
||||||
|
_Static_assert (1, "1 should still be true.");
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue