Add support for parsing C++11 final classes
Such as:
class X final {};
This no longer gives a syntax error.
This change has introduced one more shift-reduce conflict in the parser.
with a conflict with a C style variable declaration with name final:
class X final;
resulting in a syntax error (for C++ not C). This is an an unusual style
for C++ code and more typical declarations do work:
X final;
Closes #672
This commit is contained in:
parent
76f5670fa4
commit
ba279ae939
9 changed files with 267 additions and 24 deletions
|
|
@ -7,6 +7,13 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
||||||
Version 4.1.0 (in progress)
|
Version 4.1.0 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2022-10-05: olly, wsfulton
|
||||||
|
#672 Add support for parsing C++11 final classes such as:
|
||||||
|
|
||||||
|
class X final {};
|
||||||
|
|
||||||
|
This no longer gives a syntax error.
|
||||||
|
|
||||||
2022-10-05: wsfulton
|
2022-10-05: wsfulton
|
||||||
[OCaml] Fix %rename for enum items. Previously the rename had no effect.
|
[OCaml] Fix %rename for enum items. Previously the rename had no effect.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -891,6 +891,19 @@ struct DerivedStruct : BaseStruct {
|
||||||
};
|
};
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Classes can also be marked as final, such as
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="code"><pre>
|
||||||
|
struct FinalDerivedStruct final : BaseStruct {
|
||||||
|
virtual void ab() const override;
|
||||||
|
};
|
||||||
|
</pre></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<b>Compatibility note:</b> Final methods were supported much earlier than final classes. SWIG-4.1.0 was the first version to support classes marked as final.
|
||||||
|
</p>
|
||||||
|
|
||||||
<H3><a name="CPlusPlus11_null_pointer_constant">7.2.12 Null pointer constant</a></H3>
|
<H3><a name="CPlusPlus11_null_pointer_constant">7.2.12 Null pointer constant</a></H3>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -592,6 +592,7 @@ CPP11_TEST_CASES += \
|
||||||
cpp11_director_enums \
|
cpp11_director_enums \
|
||||||
cpp11_directors \
|
cpp11_directors \
|
||||||
cpp11_explicit_conversion_operators \
|
cpp11_explicit_conversion_operators \
|
||||||
|
cpp11_final_class \
|
||||||
cpp11_final_directors \
|
cpp11_final_directors \
|
||||||
cpp11_final_override \
|
cpp11_final_override \
|
||||||
cpp11_function_objects \
|
cpp11_function_objects \
|
||||||
|
|
@ -755,6 +756,7 @@ C_TEST_CASES += \
|
||||||
enum_macro \
|
enum_macro \
|
||||||
enum_missing \
|
enum_missing \
|
||||||
extern_declaration \
|
extern_declaration \
|
||||||
|
final_c \
|
||||||
funcptr \
|
funcptr \
|
||||||
function_typedef \
|
function_typedef \
|
||||||
global_functions \
|
global_functions \
|
||||||
|
|
|
||||||
129
Examples/test-suite/cpp11_final_class.i
Normal file
129
Examples/test-suite/cpp11_final_class.i
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
%module cpp11_final_class
|
||||||
|
|
||||||
|
%warnfilter(SWIGWARN_PARSE_KEYWORD) final; // 'final' is a java keyword, renaming to '_final'
|
||||||
|
%warnfilter(SWIGWARN_PARSE_KEYWORD) override; // 'override' is a C# keyword, renaming to '_override'
|
||||||
|
|
||||||
|
%ignore Space1::final::operator=;
|
||||||
|
#if defined(SWIGPHP)
|
||||||
|
%rename(Space1_final) Space1::final::final;
|
||||||
|
#endif
|
||||||
|
#if defined(SWIGOCAML)
|
||||||
|
%rename(finale) Space2::FinalEnum1::final;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
struct FinalBase {
|
||||||
|
virtual ~FinalBase() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinalClass1 final : FinalBase {
|
||||||
|
void method1() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FinalClass2 final : public FinalBase {
|
||||||
|
public:
|
||||||
|
void method2() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinalClass3 final {
|
||||||
|
void method3() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinalClass4 {
|
||||||
|
void method4() {}
|
||||||
|
} final;
|
||||||
|
|
||||||
|
struct override final {
|
||||||
|
void omethod() {}
|
||||||
|
};
|
||||||
|
%}
|
||||||
|
|
||||||
|
%rename(Space1_final) Space1::final;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
namespace Space1 {
|
||||||
|
struct final final {
|
||||||
|
void finalmethod() {}
|
||||||
|
final() {}
|
||||||
|
final(const final &other) = default;
|
||||||
|
final& operator=(const final &other) = default;
|
||||||
|
};
|
||||||
|
struct FinalClass5 final {
|
||||||
|
void method5() {}
|
||||||
|
final final_member_var;
|
||||||
|
final get_final_member() { return final_member_var; }
|
||||||
|
Space1::final get_final_member2() { return final_member_var; }
|
||||||
|
};
|
||||||
|
struct FinalClass6 {
|
||||||
|
void method6() {}
|
||||||
|
virtual void final() final {}
|
||||||
|
virtual ~FinalClass6() = default;
|
||||||
|
};
|
||||||
|
typedef final Space1_final_typedef1;
|
||||||
|
typedef struct final Space1_final_typedef2;
|
||||||
|
}
|
||||||
|
typedef Space1::final Space1_final_typedef3;
|
||||||
|
typedef struct Space1::final Space1_final_typedef4;
|
||||||
|
%}
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
namespace Space2 {
|
||||||
|
class Y {
|
||||||
|
public:
|
||||||
|
Y(int i=0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinalVar1 {
|
||||||
|
class Y notfinal;
|
||||||
|
// class Y final; // SWIG (C++ only) fails to parse (same for struct and union)
|
||||||
|
};
|
||||||
|
struct FinalVar2 {
|
||||||
|
class Y notfinal = {};
|
||||||
|
// class Y final = {}; // SWIG (C++ only) fails to parse (same for struct and union)
|
||||||
|
};
|
||||||
|
struct FinalVar3 {
|
||||||
|
class Y notfinal = Y();
|
||||||
|
// class Y final = Y(); // SWIG (C++ only) fails to parse (same for struct and union)
|
||||||
|
};
|
||||||
|
struct FinalVar4 {
|
||||||
|
class Y* final;
|
||||||
|
FinalVar4() : final() {}
|
||||||
|
};
|
||||||
|
struct FinalVar5 {
|
||||||
|
Y final;
|
||||||
|
};
|
||||||
|
struct FinalVar6 {
|
||||||
|
Y final = {};
|
||||||
|
};
|
||||||
|
struct FinalVar7 {
|
||||||
|
Y final = Y();
|
||||||
|
};
|
||||||
|
struct FinalVar8 {
|
||||||
|
Y final{};
|
||||||
|
};
|
||||||
|
struct FinalVar9 {
|
||||||
|
Y final{9};
|
||||||
|
};
|
||||||
|
struct FinalVar10 {
|
||||||
|
void a10(class Y final) {}
|
||||||
|
void b10(Y final) {}
|
||||||
|
};
|
||||||
|
struct FinalEnum1 {
|
||||||
|
enum Enum1 { one, two, final };
|
||||||
|
void enum_in(Enum1 e) {}
|
||||||
|
};
|
||||||
|
struct FinalEnum2 {
|
||||||
|
enum Enum2 { one, two, three, four };
|
||||||
|
enum Enum2 final;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
||||||
|
%rename(Space3_final) Space3::final;
|
||||||
|
%inline %{
|
||||||
|
namespace Space3 {
|
||||||
|
typedef struct final {
|
||||||
|
void fmethod() {}
|
||||||
|
} final;
|
||||||
|
}
|
||||||
|
%}
|
||||||
|
|
@ -27,7 +27,7 @@ struct Base {
|
||||||
virtual ~Base() {}
|
virtual ~Base() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Derived /*final*/ : Base {
|
struct Derived final : Base {
|
||||||
virtual void stuff() const noexcept override final {}
|
virtual void stuff() const noexcept override final {}
|
||||||
virtual void override1() const noexcept override;
|
virtual void override1() const noexcept override;
|
||||||
virtual void override2() const noexcept override;
|
virtual void override2() const noexcept override;
|
||||||
|
|
|
||||||
11
Examples/test-suite/final_c.i
Normal file
11
Examples/test-suite/final_c.i
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
%module final_c
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
struct Y {
|
||||||
|
int yval;
|
||||||
|
};
|
||||||
|
struct Y final;
|
||||||
|
void init() {
|
||||||
|
final.yval = 123;
|
||||||
|
}
|
||||||
|
%}
|
||||||
62
Examples/test-suite/python/cpp11_final_class_runme.py
Normal file
62
Examples/test-suite/python/cpp11_final_class_runme.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
from cpp11_final_class import *
|
||||||
|
|
||||||
|
fc1 = FinalClass1()
|
||||||
|
fc1.method1()
|
||||||
|
|
||||||
|
fc2 = FinalClass2()
|
||||||
|
fc2.method2()
|
||||||
|
|
||||||
|
fc3 = FinalClass3()
|
||||||
|
fc3.method3()
|
||||||
|
|
||||||
|
fc4 = FinalClass4()
|
||||||
|
fc4.method4()
|
||||||
|
fc4final = cvar.final
|
||||||
|
cvar.final.method4()
|
||||||
|
|
||||||
|
fc5 = FinalClass5()
|
||||||
|
fc5.method5()
|
||||||
|
fc5.final_member_var.finalmethod()
|
||||||
|
fc5final = fc5.get_final_member()
|
||||||
|
fc5final.finalmethod()
|
||||||
|
fc5final = fc5.get_final_member2()
|
||||||
|
fc5final.finalmethod()
|
||||||
|
|
||||||
|
fc6 = FinalClass6()
|
||||||
|
fc6.method6()
|
||||||
|
fc6.final()
|
||||||
|
|
||||||
|
o = override()
|
||||||
|
o.omethod();
|
||||||
|
|
||||||
|
y = Y()
|
||||||
|
fv4 = FinalVar4()
|
||||||
|
yy = fv4.final
|
||||||
|
|
||||||
|
fv5 = FinalVar5()
|
||||||
|
yy = fv5.final
|
||||||
|
|
||||||
|
fv6 = FinalVar6()
|
||||||
|
yy = fv6.final
|
||||||
|
|
||||||
|
fv7 = FinalVar7()
|
||||||
|
yy = fv7.final
|
||||||
|
|
||||||
|
fv8 = FinalVar8()
|
||||||
|
yy = fv8.final
|
||||||
|
|
||||||
|
fv9 = FinalVar9()
|
||||||
|
yy = fv9.final
|
||||||
|
|
||||||
|
fv10 = FinalVar10()
|
||||||
|
fv10.a10(y)
|
||||||
|
fv10.b10(y)
|
||||||
|
|
||||||
|
fe1 = FinalEnum1()
|
||||||
|
fe1.enum_in(FinalEnum1.final)
|
||||||
|
|
||||||
|
fe2 = FinalEnum2()
|
||||||
|
fe2f = fe2.final
|
||||||
|
|
||||||
|
s3f = Space3_final()
|
||||||
|
s3f.fmethod();
|
||||||
6
Examples/test-suite/python/final_c_runme.py
Normal file
6
Examples/test-suite/python/final_c_runme.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import final_c
|
||||||
|
|
||||||
|
final_c.init()
|
||||||
|
f = final_c.cvar.final
|
||||||
|
if (f.yval != 123):
|
||||||
|
raise RuntimeError("f.yval fail")
|
||||||
|
|
@ -13,14 +13,14 @@
|
||||||
* some point. Beware.
|
* some point. Beware.
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* There are 6 known shift-reduce conflicts in this file, fail compilation if any
|
/* There are a small number of known shift-reduce conflicts in this file, fail
|
||||||
more are introduced.
|
compilation if any more are introduced.
|
||||||
|
|
||||||
Please don't increase the number of the conflicts if at all possible. And if
|
Please don't increase the number of the conflicts if at all possible. And if
|
||||||
you really have no choice but to do it, make sure you clearly document each
|
you really have no choice but to do it, make sure you clearly document each
|
||||||
new conflict in this file.
|
new conflict in this file.
|
||||||
*/
|
*/
|
||||||
%expect 6
|
%expect 7
|
||||||
|
|
||||||
%{
|
%{
|
||||||
#define yylex yylex
|
#define yylex yylex
|
||||||
|
|
@ -1716,6 +1716,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
|
||||||
%type <node> lambda_introducer lambda_body lambda_template;
|
%type <node> lambda_introducer lambda_body lambda_template;
|
||||||
%type <pl> lambda_tail;
|
%type <pl> lambda_tail;
|
||||||
%type <str> virt_specifier_seq virt_specifier_seq_opt;
|
%type <str> virt_specifier_seq virt_specifier_seq_opt;
|
||||||
|
%type <str> class_virt_specifier_opt;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|
@ -3708,7 +3709,11 @@ cpp_declaration : cpp_class_decl { $$ = $1; }
|
||||||
|
|
||||||
|
|
||||||
/* A simple class/struct/union definition */
|
/* A simple class/struct/union definition */
|
||||||
cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
|
||||||
|
/* Note that class_virt_specifier_opt for supporting final classes introduces one shift-reduce conflict
|
||||||
|
with C style variable declarations, such as: struct X final; */
|
||||||
|
|
||||||
|
cpp_class_decl: storage_class cpptype idcolon class_virt_specifier_opt inherit LBRACE {
|
||||||
String *prefix;
|
String *prefix;
|
||||||
List *bases = 0;
|
List *bases = 0;
|
||||||
Node *scope = 0;
|
Node *scope = 0;
|
||||||
|
|
@ -3716,10 +3721,10 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
$<node>$ = new_node("class");
|
$<node>$ = new_node("class");
|
||||||
Setline($<node>$,cparse_start_line);
|
Setline($<node>$,cparse_start_line);
|
||||||
Setattr($<node>$,"kind",$2);
|
Setattr($<node>$,"kind",$2);
|
||||||
if ($4) {
|
if ($5) {
|
||||||
Setattr($<node>$,"baselist", Getattr($4,"public"));
|
Setattr($<node>$,"baselist", Getattr($5,"public"));
|
||||||
Setattr($<node>$,"protectedbaselist", Getattr($4,"protected"));
|
Setattr($<node>$,"protectedbaselist", Getattr($5,"protected"));
|
||||||
Setattr($<node>$,"privatebaselist", Getattr($4,"private"));
|
Setattr($<node>$,"privatebaselist", Getattr($5,"private"));
|
||||||
}
|
}
|
||||||
Setattr($<node>$,"allows_typedef","1");
|
Setattr($<node>$,"allows_typedef","1");
|
||||||
|
|
||||||
|
|
@ -3747,8 +3752,8 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
Setattr($<node>$, "Classprefix", $3);
|
Setattr($<node>$, "Classprefix", $3);
|
||||||
Classprefix = NewString($3);
|
Classprefix = NewString($3);
|
||||||
/* Deal with inheritance */
|
/* Deal with inheritance */
|
||||||
if ($4)
|
if ($5)
|
||||||
bases = Swig_make_inherit_list($3,Getattr($4,"public"),Namespaceprefix);
|
bases = Swig_make_inherit_list($3,Getattr($5,"public"),Namespaceprefix);
|
||||||
prefix = SwigType_istemplate_templateprefix($3);
|
prefix = SwigType_istemplate_templateprefix($3);
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
String *fbase, *tbase;
|
String *fbase, *tbase;
|
||||||
|
|
@ -3828,7 +3833,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
Delattr($$, "prev_symtab");
|
Delattr($$, "prev_symtab");
|
||||||
|
|
||||||
/* Check for pure-abstract class */
|
/* Check for pure-abstract class */
|
||||||
Setattr($$,"abstracts", pure_abstracts($7));
|
Setattr($$,"abstracts", pure_abstracts($8));
|
||||||
|
|
||||||
/* This bit of code merges in a previously defined %extend directive (if any) */
|
/* This bit of code merges in a previously defined %extend directive (if any) */
|
||||||
{
|
{
|
||||||
|
|
@ -3844,12 +3849,12 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
scpname = Swig_symbol_qualifiedscopename(0);
|
scpname = Swig_symbol_qualifiedscopename(0);
|
||||||
Setattr(classes, scpname, $$);
|
Setattr(classes, scpname, $$);
|
||||||
|
|
||||||
appendChild($$, $7);
|
appendChild($$, $8);
|
||||||
|
|
||||||
if (am)
|
if (am)
|
||||||
Swig_extend_append_previous($$, am);
|
Swig_extend_append_previous($$, am);
|
||||||
|
|
||||||
p = $9;
|
p = $10;
|
||||||
if (p && !nscope_inner) {
|
if (p && !nscope_inner) {
|
||||||
if (!cparse_cplusplus && currentOuterClass)
|
if (!cparse_cplusplus && currentOuterClass)
|
||||||
appendChild(currentOuterClass, p);
|
appendChild(currentOuterClass, p);
|
||||||
|
|
@ -3873,8 +3878,8 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
}
|
}
|
||||||
p = nextSibling(p);
|
p = nextSibling(p);
|
||||||
}
|
}
|
||||||
if ($9 && Cmp($1,"typedef") == 0)
|
if ($10 && Cmp($1,"typedef") == 0)
|
||||||
add_typedef_name($$, $9, $3, cscope, scpname);
|
add_typedef_name($$, $10, $3, cscope, scpname);
|
||||||
Delete(scpname);
|
Delete(scpname);
|
||||||
|
|
||||||
if (cplus_mode != CPLUS_PUBLIC) {
|
if (cplus_mode != CPLUS_PUBLIC) {
|
||||||
|
|
@ -3896,12 +3901,12 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
if (cplus_mode == CPLUS_PRIVATE) {
|
if (cplus_mode == CPLUS_PRIVATE) {
|
||||||
$$ = 0; /* skip private nested classes */
|
$$ = 0; /* skip private nested classes */
|
||||||
} else if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) {
|
} else if (cparse_cplusplus && currentOuterClass && ignore_nested_classes && !GetFlag($$, "feature:flatnested")) {
|
||||||
$$ = nested_forward_declaration($1, $2, $3, Copy($3), $9);
|
$$ = nested_forward_declaration($1, $2, $3, Copy($3), $10);
|
||||||
} else if (nscope_inner) {
|
} else if (nscope_inner) {
|
||||||
/* this is tricky */
|
/* this is tricky */
|
||||||
/* we add the declaration in the original namespace */
|
/* we add the declaration in the original namespace */
|
||||||
if (Strcmp(nodeType(nscope_inner), "class") == 0 && cparse_cplusplus && ignore_nested_classes && !GetFlag($$, "feature:flatnested"))
|
if (Strcmp(nodeType(nscope_inner), "class") == 0 && cparse_cplusplus && ignore_nested_classes && !GetFlag($$, "feature:flatnested"))
|
||||||
$$ = nested_forward_declaration($1, $2, $3, Copy($3), $9);
|
$$ = nested_forward_declaration($1, $2, $3, Copy($3), $10);
|
||||||
appendChild(nscope_inner, $$);
|
appendChild(nscope_inner, $$);
|
||||||
Swig_symbol_setscope(Getattr(nscope_inner, "symtab"));
|
Swig_symbol_setscope(Getattr(nscope_inner, "symtab"));
|
||||||
Delete(Namespaceprefix);
|
Delete(Namespaceprefix);
|
||||||
|
|
@ -3913,14 +3918,14 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
Swig_symbol_setscope(cscope);
|
Swig_symbol_setscope(cscope);
|
||||||
Delete(Namespaceprefix);
|
Delete(Namespaceprefix);
|
||||||
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
|
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
|
||||||
add_symbols($9);
|
add_symbols($10);
|
||||||
if (nscope) {
|
if (nscope) {
|
||||||
$$ = nscope; /* here we return recreated namespace tower instead of the class itself */
|
$$ = nscope; /* here we return recreated namespace tower instead of the class itself */
|
||||||
if ($9) {
|
if ($10) {
|
||||||
appendSibling($$, $9);
|
appendSibling($$, $10);
|
||||||
}
|
}
|
||||||
} else if (!SwigType_istemplate(ty) && template_parameters == 0) { /* for template we need the class itself */
|
} else if (!SwigType_istemplate(ty) && template_parameters == 0) { /* for template we need the class itself */
|
||||||
$$ = $9;
|
$$ = $10;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Delete(yyrename);
|
Delete(yyrename);
|
||||||
|
|
@ -3931,7 +3936,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
outer = Getattr(outer, "nested:outer");
|
outer = Getattr(outer, "nested:outer");
|
||||||
appendSibling(outer, $$);
|
appendSibling(outer, $$);
|
||||||
Swig_symbol_setscope(cscope); /* declaration goes in the parent scope */
|
Swig_symbol_setscope(cscope); /* declaration goes in the parent scope */
|
||||||
add_symbols($9);
|
add_symbols($10);
|
||||||
set_scope_to_global();
|
set_scope_to_global();
|
||||||
Delete(Namespaceprefix);
|
Delete(Namespaceprefix);
|
||||||
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
|
Namespaceprefix = Swig_symbol_qualifiedscopename(0);
|
||||||
|
|
@ -3944,7 +3949,7 @@ cpp_class_decl : storage_class cpptype idcolon inherit LBRACE {
|
||||||
} else {
|
} else {
|
||||||
yyrename = Copy(Getattr($<node>$, "class_rename"));
|
yyrename = Copy(Getattr($<node>$, "class_rename"));
|
||||||
add_symbols($$);
|
add_symbols($$);
|
||||||
add_symbols($9);
|
add_symbols($10);
|
||||||
Delattr($$, "class_rename");
|
Delattr($$, "class_rename");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7062,6 +7067,14 @@ virt_specifier_seq_opt : virt_specifier_seq {
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
class_virt_specifier_opt : FINAL {
|
||||||
|
$$ = NewString("1");
|
||||||
|
}
|
||||||
|
| empty {
|
||||||
|
$$ = 0;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
exception_specification : THROW LPAREN parms RPAREN {
|
exception_specification : THROW LPAREN parms RPAREN {
|
||||||
$$.throws = $3;
|
$$.throws = $3;
|
||||||
$$.throwf = NewString("1");
|
$$.throwf = NewString("1");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue