How to achieve RAII with #pragma's?

103 Views Asked by At

Currently, I have the following piece of code:

enum class Letters {
    A,
    B,
    C
};

#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"
        
Letters e(Letters::A);
switch(e){
    case Letters::A: break;
    case Letters::B: break;
}

#pragma GCC diagnostic pop

I want to use something like this:

class DiagnosticError {
public:
    constexpr DiagnosticError() {
        #pragma GCC diagnostic push
        #pragma GCC diagnostic error "-Wswitch"
    }

    constexpr ~DiagnosticError() {
        #pragma GCC diagnostic pop
    }
};

enum class Letters {
    A,
    B,
    C
};

{
    constexpr DiagnosticError switchError;
        
    Letters e(Letters::A);
    switch(e){
        case Letters::A: break;
        case Letters::B: break;
    }
}

The code compiles fine under C++20, but without generating the error:

error: enumeration value 'C' not handled in switch [-Werror=switch]
   38 |         switch(e){

Why is that? Is it possible to achieve what I want?

2

There are 2 best solutions below

0
StoryTeller - Unslander Monica On BEST ANSWER

Pragmas are handled by too early a translation phase to apply something like a guard object to a block. The best you can do is write your macros to cut a bit on the boiler-plate

#define DIAG_ERR_PUSH(flags) _Pragma("GCC diagnostic push") DIAG_ERR_PUSH_(GCC diagnostic error flags)
#define DIAG_ERR_PUSH_(str) _Pragma(#str)

#define DIAG_POP() _Pragma("GCC diagnostic pop")

enum class Letters {
    A,
    B,
    C
};

DIAG_ERR_PUSH("-Wswitch")
    
Letters e(Letters::A);
switch(e){
    case Letters::A: break;
    case Letters::B: break;
}

DIAG_POP()

Since C++11 we have the _Pragma form of the directive, to embed pragmas into other expansions. DIAG_ERR_PUSH(...) takes the place of your guard object, and DIAG_POP() delimits the region (instead of curly braces).

Not quite RAII, but sure better than having to type all the minutia for the pragma. Here's a live example.

0
Blindy On

No, all preprocessor directives get read and interpreted in place before any compilation takes place (it's actually a separate step on some compilers). In other words, your #pragma was already applied to exactly the lines you see in code between the start and end parts.

It seems what you're after is source code generation, which would require an additional tool to pre-process your file and insert those statements where you want them (or use a compiler that allows you to inject hooks to generate them at build time, like clang).