Search code examples
c++debuggingcompiler-errorsnamespacesnvcc

How can I make common C++ compilers print the namespace a certain line is in?


I'm trying to figure where in a bunch of code I'm missing a closing-brace for a namespace (i.e. getting a:

At end of source: error: expected a "}"

error). Maybe there are smarter ways to go about it, but - I want to try and check, at different points in my code, what the current namespace is. I don't need a macro; and I don't need a string; and I don't need something that will exist at run-time. I just want to get the compiler to somehow print the namespace. It's fine by me if it's in an #error, a #warning, or some construct which, failing to compile, produces an error with the namespace in it.

Example I want to generalize:

namespace ns1 { }
namespace ns2 {
namespace ns3 {

// MAGIC GOES HERE

}

this source file is missing a } somewhere. But - did I forget to close ns1? Or maybe ns2? I don't remember - they are far away from the line I'm interested in. So I want to insert something magical, that will tell me what namespace I'm in right now. Well, for this example, I can write:

namespace ns1 { }
namespace ns2 {
namespace ns3 {

void ns_detector() { return 0; }

}

and with GCC 6.3, get the error:

b.cpp: In function ‘void ns2::ns3::ns_detector()’:
b.cpp:5:29: error: return-statement with a value, in function returning 'void' [-fpermissive]
 void ns_detector() { return 0; }
                             ^
b.cpp: At global scope:
b.cpp:7:1: error: expected ‘}’ at end of input
 }
 ^

The first line of that error tells me what I need to know: It's ns2 that hasn't been closed. But - this is not so reliable. For longer, more complex pieces of code, that I compile with nvcc, using the "ns detector" function only gives me something like:

/path/to/file.cu(135): error: return value type does not match the function type

At end of source: error: expected a "}"

So, I need something more robust.

Notes:

  • The solution needs to be a fixed piece of code I paste into my own code where I want to check what the namespace is, and possibly additional compiler flags to use.
  • The solution should work for as many of: gcc, clang, nvcc, msvc, icc as possible. I particularly care about nvcc (the CUDA compiler) and gcc.
  • I'd prefer the least amount of "noise" possible other than the namespace and some "marker text" I'll look for in the output.
  • Somewhat related question: How to get string for current namespace in Macro

Solution

  • A (possible) improvement on @Acorn's good and simple solution, which can be used many times, for detection in multiple places in the same file:

    #define CONCATENATE(s1, s2) s1##s2
    #define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
    #define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
    
    #define DETECT_NAMESPACE \
    struct UNIQUE_IDENTIFIER(namespace_detector_on_line_) { \
        void f() { look_at_the_class_name_above = 0; } \
    };
    

    Now you should be able to write DETECT_NAMESPACE on many different lines. Also, the macro definitions can be placed in a separate file.

    For the code in the example, this will give:

    b.cpp: In member function ‘void ns2::ns3::namespace_detector_on_line_13::f()’:
    b.cpp:5:93: error: ‘look_at_the_class_name_above’ was not declared in this scope
     #define DETECT_NAMESPACE struct UNIQUE_IDENTIFIER(namespace_detector_on_line_) { void f() { look_at_the_class_name_above! = 0; } };
                                                                                                 ^
    b.cpp:13:1: note: in expansion of macro ‘DETECT_NAMESPACE’
     DETECT_NAMESPACE
     ^~~~~~~~~~~~~~~~
    b.cpp: At global scope:
    b.cpp:15:1: error: expected ‘}’ at end of input
     }