[Regression] Constants referencing enum values are incorrectly passed to functions with nullable enum arguments
Vala 0.54.4 introduces a regression for constants referencing enum values being passed as nullable arguments. See a simplified test case below or real code triggering this issue here.
Test case:
enum Platform
{
LINUX, WINDOWS, MACOS;
public const Platform TEST = Platform.LINUX;
#if OS_LINUX
public const Platform CURRENT = Platform.LINUX;
#elif OS_WINDOWS
public const Platform CURRENT = Platform.WINDOWS;
#elif OS_MACOS
public const Platform CURRENT = Platform.MACOS;
#endif
}
static void test(string msg, Platform? platform = null)
{
platform = platform ?? Platform.CURRENT;
print("%s: %s", msg, platform.to_string());
}
static void main()
{
test("enum case", Platform.LINUX);
test("const (unconditional)", Platform.TEST);
test("const (#if)", Platform.CURRENT);
test("null (default - #if)");
}
This code builds correctly with valac 0.54.3, but fails with 0.54.4, 0.54.5 and 0.48.20:
test.vala.c: In function ‘test’:
test.vala.c:84:43: error: lvalue required as unary ‘&’ operand
84 | _tmp2_ = __platform_dup0 (&PLATFORM_CURRENT);
| ^
test.vala.c: In function ‘_vala_main’:
test.vala.c:100:40: error: lvalue required as unary ‘&’ operand
100 | test ("const (unconditional)", &PLATFORM_TEST);
| ^
test.vala.c:101:30: error: lvalue required as unary ‘&’ operand
101 | test ("const (#if)", &PLATFORM_CURRENT);
| ^
error: cc exited with status 256
This code compiles differently with different compiler versions:
valac 0.54.5
void
test (const gchar* msg,
Platform* platform)
{
Platform* _tmp0_ = NULL;
Platform* _tmp1_;
GEnumValue* _tmp3_;
g_return_if_fail (msg != NULL);
_tmp1_ = __platform_dup0 (platform);
_tmp0_ = _tmp1_;
if (_tmp0_ == NULL) {
Platform* _tmp2_;
_tmp2_ = __platform_dup0 (&PLATFORM_CURRENT);
_g_free0 (_tmp0_);
_tmp0_ = _tmp2_;
}
platform = _tmp0_;
_tmp3_ = g_enum_get_value (g_type_class_ref (TYPE_PLATFORM), *platform);
g_print ("%s: %s", msg, (_tmp3_ != NULL) ? _tmp3_->value_name : NULL);
_g_free0 (_tmp0_);
}
static void
_vala_main (void)
{
Platform _tmp0_;
_tmp0_ = PLATFORM_LINUX;
test ("enum case", &_tmp0_);
test ("const (unconditional)", &PLATFORM_TEST);
test ("const (#if)", &PLATFORM_CURRENT);
test ("null (default - #if)", NULL);
}
valac 0.54.3
void
test (const gchar* msg,
Platform* platform)
{
Platform* _tmp0_ = NULL;
Platform* _tmp1_;
GEnumValue* _tmp4_;
g_return_if_fail (msg != NULL);
_tmp1_ = __platform_dup0 (platform);
_tmp0_ = _tmp1_;
if (_tmp0_ == NULL) {
Platform _tmp2_;
Platform* _tmp3_;
_tmp2_ = PLATFORM_CURRENT;
_tmp3_ = __platform_dup0 (&_tmp2_);
_g_free0 (_tmp0_);
_tmp0_ = _tmp3_;
}
platform = _tmp0_;
_tmp4_ = g_enum_get_value (g_type_class_ref (TYPE_PLATFORM), *platform);
g_print ("%s: %s", msg, (_tmp4_ != NULL) ? _tmp4_->value_name : NULL);
_g_free0 (_tmp0_);
}
static void
_vala_main (void)
{
Platform _tmp0_;
Platform _tmp1_;
Platform _tmp2_;
_tmp0_ = PLATFORM_LINUX;
test ("enum case", &_tmp0_);
_tmp1_ = PLATFORM_TEST;
test ("const (unconditional)", &_tmp1_);
_tmp2_ = PLATFORM_CURRENT;
test ("const (#if)", &_tmp2_);
test ("null (default - #if)", NULL);
}
Both compiler versions compile the enum into:
typedef enum {
PLATFORM_LINUX,
PLATFORM_WINDOWS,
PLATFORM_MACOS
} Platform;
#define PLATFORM_TEST PLATFORM_LINUX
#define PLATFORM_CURRENT PLATFORM_LINUX
The difference is valac 0.54.4/0.54.5 only creates temporary variables when enum values are referenced directly, while older versions also create temporary variables when referencing constants.
This code compiles correctly and identically with both compiler versions if arguments are not nullable:
static void test(string msg, Platform platform)
{
print("%s: %s", msg, platform.to_string());
}
static void main()
{
test("enum case", Platform.LINUX);
test("const (unconditional)", Platform.TEST);
test("const (#if)", Platform.CURRENT);
}
void
test (const gchar* msg,
Platform platform)
{
GEnumValue* _tmp0_;
g_return_if_fail (msg != NULL);
_tmp0_ = g_enum_get_value (g_type_class_ref (TYPE_PLATFORM), platform);
g_print ("%s: %s", msg, (_tmp0_ != NULL) ? _tmp0_->value_name : NULL);
}
static void
_vala_main (void)
{
test ("enum case", PLATFORM_LINUX);
test ("const (unconditional)", PLATFORM_TEST);
test ("const (#if)", PLATFORM_CURRENT);
}