glslang icon indicating copy to clipboard operation
glslang copied to clipboard

Apparent C vs GLSLang preprocessor differences

Open floopfloopfloopfloopfloop opened this issue 4 months ago • 3 comments

https://c.godbolt.org/z/9zYTvWcqM

#include "stdio.h"
#include "stdbool.h"

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS true

#define THING_NAME FOO

#if CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS) == true
    void Foo() { puts("It worked"); }
#else
    void Foo() { puts("It didn't work"); }
#endif


int main() {
    Foo();
    return 0;
}
Program returned: 0
Program stdout

It worked

vs

https://glsl.godbolt.org/z/6ofsE9Es8

// This will be consumed as a .glsl file and needs the stage and target profile. Example options:
// -S comp --target-env vulkan1.2
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_int32 : require

#define U32 uint32_t

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS true

#define THING_NAME FOO

#if CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS) == true
    U32 Foo() { return 1; }
#else
    U32 Foo() { return 0; }
#endif

void main() {
    U32 a = Foo();
}
<source>
<source>:17: '#if' : unexpected tokens following directive 
<source>:17: '' : missing #endif 
<source>:17: '' : compilation terminated 
3 compilation errors.  No code generated.


Linking compute stage: Missing entry point: Each stage requires one entry point

SPIR-V is not generated for failed compile or link
Compiler returned: 2

nani

From the GLSL spec, I don't think true is defined in the GLSL preprocessor:

  • Expressions following #if and #elif are further restricted to expressions operating on literal integer constants, plus identifiers consumed by the defined operator.
  • Character constants are not supported.

So, I'm guessing it's the comparison of true == true that is failing. If you changed it to #if defined(CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS)) does it work correctly?

dj2 avatar Nov 11 '25 14:11 dj2

nope, that doesn't work for anything

https://c.godbolt.org/z/jT1YM848c

#include "stdio.h"
#include "stdbool.h"

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS true

#define THING_NAME FOO

#if defined(CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS))
    void Foo() { puts("It worked"); }
#else
    void Foo() { puts("It didn't work"); }
#endif


int main() {
    Foo();
    return 0;
}
<source>:13:20: error: missing ')' after "defined"
   13 | #if defined(CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS))
      |                    ^
<source>:13:21: error: missing binary operator before token "USE_"
   13 | #if defined(CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS))
      |                     ^~~~

https://glsl.godbolt.org/z/YzPjEfMno

// This will be consumed as a .glsl file and needs the stage and target profile. Example options:
// -S comp --target-env vulkan1.2
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_int32 : require

#define U32 uint32_t

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS true

#define THING_NAME FOO

#if defined(CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS))
    U32 Foo() { return 1; }
#else
    U32 Foo() { return 0; }
#endif

void main() {
    U32 a = Foo();
}
<source>
<source>:17: 'preprocessor evaluation' : expected ')' 
<source>:17: '#if' : unexpected tokens following directive 
<source>:17: '' : missing #endif 
<source>:17: '' : compilation terminated 
4 compilation errors.  No code generated.


Linking compute stage: Missing entry point: Each stage requires one entry point

if I try using 1|0 instead of true|false, C works, but GLSL still fails

https://c.godbolt.org/z/qvK1azjxn

#include "stdio.h"
#include "stdbool.h"

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS 1

#define THING_NAME FOO

#if CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS) == 1
    void Foo() { puts("It worked"); }
#else
    void Foo() { puts("It didn't work"); }
#endif


int main() {
    Foo();
    return 0;
}
Program returned: 0
Program stdout

It worked

https://glsl.godbolt.org/z/Gn8Y7YW5G

// This will be consumed as a .glsl file and needs the stage and target profile. Example options:
// -S comp --target-env vulkan1.2
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_int32 : require

#define U32 uint32_t

#define CONCAT3_IMPLX(x, y, z) x##y##z
#define CONCAT3_IMPL1(x, y, z) CONCAT3_IMPLX(x, y, z)
#define CONCAT3_IMPL0(x, y, z) CONCAT3_IMPL1(x, y, z)
#define CONCAT3(x, y, z) CONCAT3_IMPL0(x, y, z)

#define USE_FOO_PUSH_CONSTANTS 1

#define THING_NAME FOO

#if CONCAT3(USE_,THING_NAME,_PUSH_CONSTANTS) == 1
    U32 Foo() { return 1; }
#else
    U32 Foo() { return 0; }
#endif

void main() {
    U32 a = Foo();
}
<source>
<source>:17: '#if' : unexpected tokens following directive 
<source>:17: '' : missing #endif 
<source>:17: '' : compilation terminated 
3 compilation errors.  No code generated.


Linking compute stage: Missing entry point: Each stage requires one entry point

SPIR-V is not generated for failed compile or link
Compiler returned: 2

May or may not warrant a separate issue, but I've run into the preprocessor differences again with this example:

https://c.godbolt.org/z/7G65Yx3aM

#define _CONCAT_IMPLX(x, y) x##y
#define _CONCAT_IMPL1(x, y) _CONCAT_IMPLX(x, y)
#define _CONCAT_IMPL0(x, y) _CONCAT_IMPL1(x, y)
#define CONCAT(x, y) _CONCAT_IMPL0(x, y)

// X macro
#define XS \
    X(VALUE, int, foo, 0) \
    X(VALUE, int, bar, 0)

// Define each X to actually be a specialized macro based on the 'kind_' parameter
#define X(kind_, type_, name_, defaultValue_) \
    CONCAT(X_,kind_)(type_, name_, defaultValue_)

// said specialized macro, only one variant is needed to demonstrate the issue
#define X_VALUE(type_, name_, defaultValue_) 1 &&

// the macros should be expanded so this value is '(1 && 1 && 1)`, which evaluates true
#define SHARED_TYPE_IS_POD (XS 1)

void main() {
    #if SHARED_TYPE_IS_POD
        return;
    #else
        return;
    #endif
}
Compiler returned: 0

https://glsl.godbolt.org/z/avqacq6oc

// This will be consumed as a .glsl file and needs the stage and target profile. Example options:
// -S comp --target-env vulkan1.1
#version 450
#define _CONCAT_IMPLX(x, y) x##y
#define _CONCAT_IMPL1(x, y) _CONCAT_IMPLX(x, y)
#define _CONCAT_IMPL0(x, y) _CONCAT_IMPL1(x, y)
#define CONCAT(x, y) _CONCAT_IMPL0(x, y)

// X macro
#define XS \
    X(VALUE, int, foo, 0) \
    X(VALUE, int, bar, 0)

// Define each X to actually be a specialized macro based on the 'kind_' parameter
#define X(kind_, type_, name_, defaultValue_) \
    CONCAT(X_,kind_)(type_, name_, defaultValue_)

// said specialized macro, only one variant is needed to demonstrate the issue
#define X_VALUE(type_, name_, defaultValue_) 1 &&

// the macros should be expanded so this value is '(1 && 1 && 1)`, which evaluates true
#define SHARED_TYPE_IS_POD (XS 1)

void main() {
    #if SHARED_TYPE_IS_POD
        return;
    #else
        return;
    #endif
}
<source>
<source>:25: 'preprocessor evaluation' : expected ')' 
<source>:25: '#if' : unexpected tokens following directive 
<source>:25: '' : missing #endif 
<source>:25: '' : compilation terminated 
4 compilation errors.  No code generated.


SPIR-V is not generated for failed compile or link
Compiler returned: 2