diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index 72c49648b..c502cfb65 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -162,6 +162,7 @@ CPP_TEST_CASES += \ cpp_nodefault \ cpp_static \ cpp_typedef \ + cpp17_nested_namespaces \ curiously_recurring_template_pattern \ default_args \ default_arg_expressions \ diff --git a/Examples/test-suite/cpp17_nested_namespaces.i b/Examples/test-suite/cpp17_nested_namespaces.i new file mode 100644 index 000000000..b9ec9bd5a --- /dev/null +++ b/Examples/test-suite/cpp17_nested_namespaces.i @@ -0,0 +1,199 @@ +%module cpp17_nested_namespaces +// Tests c++17 style nested namespaces +// Tests are designed so that code compiles with C++98 compilers + +#define CPP17 1 +%{ +#if __cplusplus >= 201703L +#define CPP17 1 +#endif +%} + +%inline %{ +// Tests with namespaces already defined using C++98 style (non-nested) namespaces +namespace A1 { + struct A1Struct { + void A1Method() {} + }; + namespace B1 { + struct B1Struct { + void B1Method() {} + }; + } +} +#if defined(CPP17) +namespace A1::B1 { +#else +namespace A1 { + namespace B1 { +#endif + A1Struct createA1Struct() { return ::A1::A1Struct(); } + B1Struct createB1Struct() { return ::A1::B1::B1Struct(); } +#if !defined(CPP17) + } +} +#else +} +#endif + +namespace A1 { + namespace B1 { + namespace C1 { + struct C1Struct { + void C1Method() {} + }; + } + } +} + +#if defined(CPP17) +namespace A1::B1::C1 { +#else +namespace A1 { + namespace B1 { + namespace C1 { +#endif + C1Struct createC1Struct() { return ::A1::B1::C1::C1Struct(); } +#if !defined(CPP17) + } + } +} +#else +} +#endif +%} + +%inline %{ +// Tests with namespaces already defined using C++17 style (nested) namespaces +#if defined(CPP17) +namespace A2::B2 { +#else +namespace A2 { + namespace B2 { +#endif + struct B2Struct { + void B2Method() {} + }; +#if !defined(CPP17) + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A2::B2 { +#else +namespace A2 { + namespace B2 { +#endif + B2Struct createB2Struct() { return ::A2::B2::B2Struct(); } +#if !defined(CPP17) + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A2::B2::C2 { +#else +namespace A2 { + namespace B2 { + namespace C2 { +#endif + struct C2Struct { + void C2Method() {} + }; +#if !defined(CPP17) + } + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A2::B2::C2 { +#else +namespace A2 { + namespace B2 { + namespace C2 { +#endif + C2Struct createC2Struct() { return ::A2::B2::C2::C2Struct(); } +#if !defined(CPP17) + } + } +} +#else +} +#endif +%} + + +%inline %{ +// Tests with namespaces already defined using C++17 style (nested) namespaces to 3 levels +#if defined(CPP17) +namespace A3::B3::C3 { +#else +namespace A3 { + namespace B3 { + namespace C3 { +#endif + struct C3Struct { + void C3Method() {} + }; +#if !defined(CPP17) + } + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A3::B3::C3 { +#else +namespace A3 { + namespace B3 { + namespace C3 { +#endif + C3Struct createC3Struct() { return ::A3::B3::C3::C3Struct(); } +#if !defined(CPP17) + } + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A3::B3 { +#else +namespace A3 { + namespace B3 { +#endif + struct B3Struct { + void B3Method() {} + }; +#if !defined(CPP17) + } +} +#else +} +#endif + +#if defined(CPP17) +namespace A3::B3 { +#else +namespace A3 { + namespace B3 { +#endif + B3Struct createB3Struct() { return ::A3::B3::B3Struct(); } +#if !defined(CPP17) + } +} +#else +} +#endif +%} diff --git a/Examples/test-suite/java/cpp17_nested_namespaces_runme.java b/Examples/test-suite/java/cpp17_nested_namespaces_runme.java new file mode 100644 index 000000000..ac29dee19 --- /dev/null +++ b/Examples/test-suite/java/cpp17_nested_namespaces_runme.java @@ -0,0 +1,32 @@ +import cpp17_nested_namespaces.*; + +public class cpp17_nested_namespaces_runme { + + static { + try { + System.loadLibrary("cpp17_nested_namespaces"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + new A1Struct().A1Method(); + new B1Struct().B1Method(); + new C1Struct().C1Method(); + cpp17_nested_namespaces.createA1Struct().A1Method(); + cpp17_nested_namespaces.createB1Struct().B1Method(); + cpp17_nested_namespaces.createC1Struct().C1Method(); + + new B2Struct().B2Method(); + new C2Struct().C2Method(); + cpp17_nested_namespaces.createB2Struct().B2Method(); + cpp17_nested_namespaces.createC2Struct().C2Method(); + + new B3Struct().B3Method(); + new C3Struct().C3Method(); + cpp17_nested_namespaces.createB3Struct().B3Method(); + cpp17_nested_namespaces.createC3Struct().C3Method(); + } +} diff --git a/Source/CParse/parser.y b/Source/CParse/parser.y index 0c8d95ecd..cae20eb3f 100644 --- a/Source/CParse/parser.y +++ b/Source/CParse/parser.y @@ -4400,32 +4400,61 @@ cpp_using_decl : USING idcolon SEMI { cpp_namespace_decl : NAMESPACE idcolon LBRACE { Hash *h; - $1 = Swig_symbol_current(); - h = Swig_symbol_clookup($2,0); - if (h && ($1 == Getattr(h,"sym:symtab")) && (Strcmp(nodeType(h),"namespace") == 0)) { - if (Getattr(h,"alias")) { - h = Getattr(h,"namespace"); - Swig_warning(WARN_PARSE_NAMESPACE_ALIAS, cparse_file, cparse_line, "Namespace alias '%s' not allowed here. Assuming '%s'\n", - $2, Getattr(h,"name")); - $2 = Getattr(h,"name"); + Node *parent_ns = 0; + List *scopes = Swig_scopename_tolist($2); + int ilen = Len(scopes); + int i; + +/* +Printf(stdout, "==== Namespace %s creation...\n", $2); +*/ + $$ = 0; + for (i = 0; i < ilen; i++) { + Node *ns = new_node("namespace"); + Symtab *current_symtab = Swig_symbol_current(); + String *scopename = Getitem(scopes, i); + Setattr(ns, "name", scopename); + $$ = ns; + if (parent_ns) + appendChild(parent_ns, ns); + parent_ns = ns; + h = Swig_symbol_clookup(scopename, 0); + if (h && (current_symtab == Getattr(h, "sym:symtab")) && (Strcmp(nodeType(h), "namespace") == 0)) { +/* +Printf(stdout, " Scope %s [found C++17 style]\n", scopename); +*/ + if (Getattr(h, "alias")) { + h = Getattr(h, "namespace"); + Swig_warning(WARN_PARSE_NAMESPACE_ALIAS, cparse_file, cparse_line, "Namespace alias '%s' not allowed here. Assuming '%s'\n", + scopename, Getattr(h, "name")); + scopename = Getattr(h, "name"); + } + Swig_symbol_setscope(Getattr(h, "symtab")); + } else { +/* +Printf(stdout, " Scope %s [creating single scope C++17 style]\n", scopename); +*/ + h = Swig_symbol_newscope(); + Swig_symbol_setscopename(scopename); } - Swig_symbol_setscope(Getattr(h,"symtab")); - } else { - Swig_symbol_newscope(); - Swig_symbol_setscopename($2); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); } - Delete(Namespaceprefix); - Namespaceprefix = Swig_symbol_qualifiedscopename(0); + Delete(scopes); } interface RBRACE { - Node *n = $5; - set_nodeType(n,"namespace"); - Setattr(n,"name",$2); - Setattr(n,"symtab", Swig_symbol_popscope()); - Swig_symbol_setscope($1); - $$ = n; - Delete(Namespaceprefix); - Namespaceprefix = Swig_symbol_qualifiedscopename(0); - add_symbols($$); + Node *n = $4; + Node *top_ns = 0; + do { + Setattr(n, "symtab", Swig_symbol_popscope()); + Delete(Namespaceprefix); + Namespaceprefix = Swig_symbol_qualifiedscopename(0); + add_symbols(n); + top_ns = n; + n = parentNode(n); + } while(n); + appendChild($4, firstChild($5)); + Delete($5); + $$ = top_ns; } | NAMESPACE LBRACE { Hash *h;