From d3759a9b36be36af5a7e01bf5853143dece4980f Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 8 Jul 2022 15:23:05 +1200 Subject: [PATCH 1/4] Avoid parse errors for C++ attributes Just ignore anything in between [[ and ]] in the scanner, which is better that failing with a parse error. Fixes #1158 Fixes #2286 --- Examples/test-suite/common.mk | 1 + .../test-suite/cpp11_attribute_specifiers.i | 41 +++++++++++++++++++ Source/CParse/cscanner.c | 12 ++++++ Source/CParse/parser.y | 1 + Source/Swig/scanner.c | 33 +++++++++++++-- Source/Swig/swigscan.h | 2 + 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 Examples/test-suite/cpp11_attribute_specifiers.i diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index bf0e52f02..c654807d7 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -583,6 +583,7 @@ CPP11_TEST_CASES += \ cpp11_alias_nested_template_scoping \ cpp11_alignment \ cpp11_alternate_function_syntax \ + cpp11_attribute_specifiers \ cpp11_constexpr \ cpp11_decltype \ cpp11_default_delete \ diff --git a/Examples/test-suite/cpp11_attribute_specifiers.i b/Examples/test-suite/cpp11_attribute_specifiers.i new file mode 100644 index 000000000..aa6de312e --- /dev/null +++ b/Examples/test-suite/cpp11_attribute_specifiers.i @@ -0,0 +1,41 @@ +%module cpp11_attribute_specifiers + +%inline %{ + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // We're using a deprecated attribute here... +#pragma GCC diagnostic ignored "-Wattributes" // likely is C++20 +#pragma GCC diagnostic ignored "-Wunused-variable" // We are using an unused variable on purpose here +#pragma GCC diagnostic ignored "-Wunused-parameter" // We are using an unused param on purpose here +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif + + +[[noreturn]] void noReturn() { throw; } +[[nodiscard]] bool noDiscard() { return true; } +[[nodiscard, deprecated("This has been replaced")]] bool noDiscardDeprecated() { return true; } +void maybeUnused1([[maybe_unused]] bool b) { } +bool maybeUnused2(bool a, [[maybe_unused]] bool b) { return a; } + +[[deprecated, nodiscard]] bool likely([[maybe_unused]] bool a, bool b) { + [[maybe_unused]] bool c = b; + if (b) [[likely]] { + return true; + } else [[unlikely]] { + if(a) { + return true; + } + } + return false; +} + +struct [[nodiscard]] S { }; + +%} diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c index 155c7c81b..75f100d1c 100644 --- a/Source/CParse/cscanner.c +++ b/Source/CParse/cscanner.c @@ -354,6 +354,18 @@ static int yylook(void) { case SWIG_TOKEN_ELLIPSIS: return ELLIPSIS; + case SWIG_TOKEN_LLBRACKET: + do { + tok = Scanner_token(scan); + } while ((tok != SWIG_TOKEN_RRBRACKET) && (tok > 0)); + if (tok <= 0) { + Swig_error(cparse_file, cparse_line, "Unbalanced double brackets, missing closing (']]'). Reached end of input.\n"); + } + break; + + case SWIG_TOKEN_RRBRACKET: + return RRBRACKET; + /* Look for multi-character sequences */ case SWIG_TOKEN_RSTRING: diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index ddb9634b2..010df3c1c 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -1613,6 +1613,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) %token TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64 %token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD ELLIPSIS %token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET +%token LLBRACKET RRBRACKET /* C++11 Attribute specifier sequence */ %token BEGINFILE ENDOFFILE %token ILLEGAL CONSTANT %token NAME RENAME NAMEWARN EXTEND PRAGMA FEATURE VARARGS diff --git a/Source/Swig/scanner.c b/Source/Swig/scanner.c index 65f534a79..b03a07a5b 100644 --- a/Source/Swig/scanner.c +++ b/Source/Swig/scanner.c @@ -596,10 +596,6 @@ static int look(Scanner *s) { state = 3; else if (c == '\\') return SWIG_TOKEN_BACKSLASH; - else if (c == '[') - return SWIG_TOKEN_LBRACKET; - else if (c == ']') - return SWIG_TOKEN_RBRACKET; else if (c == '@') return SWIG_TOKEN_AT; else if (c == '$') @@ -637,6 +633,10 @@ static int look(Scanner *s) { else if (c == '.') state = 100; /* Maybe a number, maybe ellipsis, just a period */ + else if (c == '[') + state = 102; /* Maybe a bracket or a double bracket */ + else if (c == ']') + state = 103; /* Maybe a bracket or a double bracket */ else if (isdigit(c)) state = 8; /* A numerical value */ else @@ -1358,6 +1358,31 @@ static int look(Scanner *s) { } break; + /* A left bracket or a double left bracket */ + case 102: + + if ((c = nextchar(s)) == 0) { + return SWIG_TOKEN_LBRACKET; + } else if (c == '[') { + return SWIG_TOKEN_LLBRACKET; + } else { + retract(s, 1); + return SWIG_TOKEN_LBRACKET; + } + break; + + /* a right bracket or a double right bracket */ + case 103: + if ((c = nextchar(s)) == 0) { + return SWIG_TOKEN_RBRACKET; + } else if (c == ']') { + return SWIG_TOKEN_RRBRACKET; + } else { + retract(s, 1); + return SWIG_TOKEN_RBRACKET; + } + break; + case 200: /* PLUS, PLUSPLUS, PLUSEQUAL */ if ((c = nextchar(s)) == 0) return SWIG_TOKEN_PLUS; diff --git a/Source/Swig/swigscan.h b/Source/Swig/swigscan.h index 4f66de8a2..526413a14 100644 --- a/Source/Swig/swigscan.h +++ b/Source/Swig/swigscan.h @@ -71,6 +71,8 @@ extern void Scanner_locator(Scanner *, String *loc); #define SWIG_TOKEN_WSTRING 33 /* L"str" */ #define SWIG_TOKEN_WCHAR 34 /* L'c' */ #define SWIG_TOKEN_ELLIPSIS 35 /* ... */ +#define SWIG_TOKEN_LLBRACKET 36 /* [[ */ +#define SWIG_TOKEN_RRBRACKET 37 /* ]] */ #define SWIG_TOKEN_ILLEGAL 99 #define SWIG_TOKEN_ERROR -1 From 5ddcbac56b1e1d5716ace67412c82ba6ed55ec98 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Fri, 8 Jul 2022 15:33:01 +1200 Subject: [PATCH 2/4] Test [[ and ]] in string literal are preserved Suggested by wsfulton in #1158 --- Examples/test-suite/cpp11_attribute_specifiers.i | 2 ++ .../php/cpp11_attribute_specifiers_runme.php | 14 ++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 Examples/test-suite/php/cpp11_attribute_specifiers_runme.php diff --git a/Examples/test-suite/cpp11_attribute_specifiers.i b/Examples/test-suite/cpp11_attribute_specifiers.i index aa6de312e..0d49b8615 100644 --- a/Examples/test-suite/cpp11_attribute_specifiers.i +++ b/Examples/test-suite/cpp11_attribute_specifiers.i @@ -38,4 +38,6 @@ bool maybeUnused2(bool a, [[maybe_unused]] bool b) { return a; } struct [[nodiscard]] S { }; +const char *test_string_literal() { return "Test [[ and ]] in string literal"; } + %} diff --git a/Examples/test-suite/php/cpp11_attribute_specifiers_runme.php b/Examples/test-suite/php/cpp11_attribute_specifiers_runme.php new file mode 100644 index 000000000..2336b319a --- /dev/null +++ b/Examples/test-suite/php/cpp11_attribute_specifiers_runme.php @@ -0,0 +1,14 @@ + Date: Fri, 8 Jul 2022 15:50:51 +1200 Subject: [PATCH 3/4] Turn an unmatched ]] back into two ] Needed to handle e.g. `a[a[0]]`. SWIG's parser doesn't seem to handle that currently though. See #2286. --- Examples/test-suite/cpp11_attribute_specifiers.i | 7 +++++++ Source/CParse/cscanner.c | 4 +++- Source/CParse/parser.y | 1 - 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Examples/test-suite/cpp11_attribute_specifiers.i b/Examples/test-suite/cpp11_attribute_specifiers.i index 0d49b8615..063e431e0 100644 --- a/Examples/test-suite/cpp11_attribute_specifiers.i +++ b/Examples/test-suite/cpp11_attribute_specifiers.i @@ -40,4 +40,11 @@ struct [[nodiscard]] S { }; const char *test_string_literal() { return "Test [[ and ]] in string literal"; } +#if 0 +// Check that SWIG doesn't choke on ]] when it's not part of an attribute. +// FIXME: SWIG's parser doesn't handle this case currently. +int *a; +int b = a[a[0]]; +#endif + %} diff --git a/Source/CParse/cscanner.c b/Source/CParse/cscanner.c index 75f100d1c..558a9c6cf 100644 --- a/Source/CParse/cscanner.c +++ b/Source/CParse/cscanner.c @@ -364,7 +364,9 @@ static int yylook(void) { break; case SWIG_TOKEN_RRBRACKET: - return RRBRACKET; + /* Turn an unmatched ]] back into two ] - e.g. `a[a[0]]` */ + scanner_next_token(RBRACKET); + return RBRACKET; /* Look for multi-character sequences */ diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 010df3c1c..ddb9634b2 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -1613,7 +1613,6 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier) %token TYPE_INT TYPE_UNSIGNED TYPE_SHORT TYPE_LONG TYPE_FLOAT TYPE_DOUBLE TYPE_CHAR TYPE_WCHAR TYPE_VOID TYPE_SIGNED TYPE_BOOL TYPE_COMPLEX TYPE_TYPEDEF TYPE_RAW TYPE_NON_ISO_INT8 TYPE_NON_ISO_INT16 TYPE_NON_ISO_INT32 TYPE_NON_ISO_INT64 %token LPAREN RPAREN COMMA SEMI EXTERN INIT LBRACE RBRACE PERIOD ELLIPSIS %token CONST_QUAL VOLATILE REGISTER STRUCT UNION EQUAL SIZEOF MODULE LBRACKET RBRACKET -%token LLBRACKET RRBRACKET /* C++11 Attribute specifier sequence */ %token BEGINFILE ENDOFFILE %token ILLEGAL CONSTANT %token NAME RENAME NAMEWARN EXTEND PRAGMA FEATURE VARARGS From a5380ed1c52e015c3a8c000306c0704a26260708 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Fri, 8 Jul 2022 15:57:29 +1200 Subject: [PATCH 4/4] Update docs for C++ attribute support --- CHANGES.current | 5 +++++ Doc/Manual/CPlusPlus11.html | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES.current b/CHANGES.current index 3a10743e5..c78242886 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-07-07: jmarrec + #1158 #2286 Add basic support for C++11 attributes. These are now + crudely ignored by SWIG's parser's tokeniser, which is better that + failing with a parse error. + 2022-07-05: ianlancetaylor [Go] #2245 Handle NULL pointers for string* conversions. Rearrange generation of director methods and rename diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html index 52764eeef..7618b6dbe 100644 --- a/Doc/Manual/CPlusPlus11.html +++ b/Doc/Manual/CPlusPlus11.html @@ -1089,7 +1089,9 @@ Use the preprocessor to work around this for now:

-Attributes such as those shown below, are not yet supported and will give a syntax error. +Attributes such as those shown below, are supported since SWIG 4.1.0 but are +currently crudely ignored by the parser's tokeniser so they have no effect on +SWIG's code generation.