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:
William S Fulton 2022-10-02 13:47:15 +01:00
commit ba279ae939
9 changed files with 267 additions and 24 deletions

View file

@ -592,6 +592,7 @@ CPP11_TEST_CASES += \
cpp11_director_enums \
cpp11_directors \
cpp11_explicit_conversion_operators \
cpp11_final_class \
cpp11_final_directors \
cpp11_final_override \
cpp11_function_objects \
@ -755,6 +756,7 @@ C_TEST_CASES += \
enum_macro \
enum_missing \
extern_declaration \
final_c \
funcptr \
function_typedef \
global_functions \

View 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;
}
%}

View file

@ -27,7 +27,7 @@ struct Base {
virtual ~Base() {}
};
struct Derived /*final*/ : Base {
struct Derived final : Base {
virtual void stuff() const noexcept override final {}
virtual void override1() const noexcept override;
virtual void override2() const noexcept override;

View file

@ -0,0 +1,11 @@
%module final_c
%inline %{
struct Y {
int yval;
};
struct Y final;
void init() {
final.yval = 123;
}
%}

View 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();

View 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")