From 06e18857ed87f7ec006bfa2631e346b31a92bcc4 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Sat, 9 Aug 2025 10:57:38 +0200 Subject: [PATCH] Fix type of char literals in C mode Fixes #576 Signed-off-by: Roberto Raggi --- src/parser/cxx/parser.cc | 33 +++++++++++++-------- tests/unit_tests/ast/generic_selection_01.c | 28 ++++++++--------- tests/unit_tests/sema/char_c_01.c | 13 ++++++++ tests/unit_tests/sema/typeof_01.c | 11 +++++-- 4 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 tests/unit_tests/sema/char_c_01.c diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 22b9d750..8c7f37a0 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -424,16 +424,20 @@ auto Parser::parse_literal(ExpressionAST*& yyast) -> bool { auto prefix = ast->literal->components().prefix; - if (prefix == "u8") - ast->type = control_->getChar8Type(); - else if (prefix == "u") - ast->type = control_->getChar16Type(); - else if (prefix == "U") - ast->type = control_->getChar32Type(); - else if (prefix == "L") - ast->type = control_->getWideCharType(); - else - ast->type = control_->getCharType(); + if (is_parsing_cxx()) { + if (prefix == "u8") + ast->type = control_->getChar8Type(); + else if (prefix == "u") + ast->type = control_->getChar16Type(); + else if (prefix == "U") + ast->type = control_->getChar32Type(); + else if (prefix == "L") + ast->type = control_->getWideCharType(); + else + ast->type = control_->getCharType(); + } else { + ast->type = control_->getIntType(); + } return true; } @@ -540,9 +544,12 @@ auto Parser::parse_literal(ExpressionAST*& yyast) -> bool { static_cast(unit->literal(literalLoc)); if (unit->tokenKind(literalLoc) == TokenKind::T_STRING_LITERAL) { - ast->type = control_->getBoundedArrayType( - control_->add_const(control_->getCharType()), - ast->literal->stringValue().size() + 1); + const Type* elementType = control_->getCharType(); + if (is_parsing_cxx()) elementType = control_->add_const(elementType); + + auto extent = ast->literal->stringValue().size() + 1; + + ast->type = control_->getBoundedArrayType(elementType, extent); ast->valueCategory = ValueCategory::kLValue; } diff --git a/tests/unit_tests/ast/generic_selection_01.c b/tests/unit_tests/ast/generic_selection_01.c index 8670fbec..c336690a 100644 --- a/tests/unit_tests/ast/generic_selection_01.c +++ b/tests/unit_tests/ast/generic_selection_01.c @@ -1,5 +1,5 @@ // clang-format off -// RUN: %cxx -verify -fcheck -ast-dump -xc %s | %filecheck %s --match-full-lines +// RUN: %cxx -verify -ast-dump %s | %filecheck %s --match-full-lines // clang-format on int main() { @@ -30,33 +30,33 @@ int main() { // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: void-type-specifier -// CHECK-NEXT: expression: generic-selection-expression [lvalue const char [8]] +// CHECK-NEXT: expression: generic-selection-expression [lvalue char [8]] // CHECK-NEXT: matched-assoc-index: 0 // CHECK-NEXT: expression: int-literal-expression [prvalue int] // CHECK-NEXT: literal: 1 // CHECK-NEXT: generic-association-list // CHECK-NEXT: default-generic-association -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [8]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [8]] // CHECK-NEXT: literal: "default" // CHECK-NEXT: expression-statement // CHECK-NEXT: expression: cast-expression [prvalue void] // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: void-type-specifier -// CHECK-NEXT: expression: generic-selection-expression [lvalue const char [4]] +// CHECK-NEXT: expression: generic-selection-expression [lvalue char [4]] // CHECK-NEXT: matched-assoc-index: 1 // CHECK-NEXT: expression: int-literal-expression [prvalue int] // CHECK-NEXT: literal: 1 // CHECK-NEXT: generic-association-list // CHECK-NEXT: default-generic-association -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [8]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [8]] // CHECK-NEXT: literal: "default" // CHECK-NEXT: type-generic-association // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: integral-type-specifier // CHECK-NEXT: specifier: int -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [4]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [4]] // CHECK-NEXT: literal: "int" // CHECK-NEXT: type-generic-association // CHECK-NEXT: type-id: type-id @@ -67,14 +67,14 @@ int main() { // CHECK-NEXT: declarator: declarator // CHECK-NEXT: ptr-op-list // CHECK-NEXT: pointer-operator -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [12]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [12]] // CHECK-NEXT: literal: "const char*" // CHECK-NEXT: expression-statement // CHECK-NEXT: expression: cast-expression [prvalue void] // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: void-type-specifier -// CHECK-NEXT: expression: generic-selection-expression [lvalue const char [4]] +// CHECK-NEXT: expression: generic-selection-expression [lvalue char [4]] // CHECK-NEXT: matched-assoc-index: 0 // CHECK-NEXT: expression: int-literal-expression [prvalue int] // CHECK-NEXT: literal: 1 @@ -84,7 +84,7 @@ int main() { // CHECK-NEXT: type-specifier-list // CHECK-NEXT: integral-type-specifier // CHECK-NEXT: specifier: int -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [4]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [4]] // CHECK-NEXT: literal: "int" // CHECK-NEXT: type-generic-association // CHECK-NEXT: type-id: type-id @@ -95,17 +95,17 @@ int main() { // CHECK-NEXT: declarator: declarator // CHECK-NEXT: ptr-op-list // CHECK-NEXT: pointer-operator -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [12]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [12]] // CHECK-NEXT: literal: "const char*" // CHECK-NEXT: default-generic-association -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [8]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [8]] // CHECK-NEXT: literal: "default" // CHECK-NEXT: expression-statement // CHECK-NEXT: expression: cast-expression [prvalue void] // CHECK-NEXT: type-id: type-id // CHECK-NEXT: type-specifier-list // CHECK-NEXT: void-type-specifier -// CHECK-NEXT: expression: generic-selection-expression [lvalue const char [4]] +// CHECK-NEXT: expression: generic-selection-expression [lvalue char [4]] // CHECK-NEXT: matched-assoc-index: 0 // CHECK-NEXT: expression: int-literal-expression [prvalue int] // CHECK-NEXT: literal: 1 @@ -115,7 +115,7 @@ int main() { // CHECK-NEXT: type-specifier-list // CHECK-NEXT: integral-type-specifier // CHECK-NEXT: specifier: int -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [4]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [4]] // CHECK-NEXT: literal: "int" // CHECK-NEXT: type-generic-association // CHECK-NEXT: type-id: type-id @@ -126,5 +126,5 @@ int main() { // CHECK-NEXT: declarator: declarator // CHECK-NEXT: ptr-op-list // CHECK-NEXT: pointer-operator -// CHECK-NEXT: expression: string-literal-expression [lvalue const char [12]] +// CHECK-NEXT: expression: string-literal-expression [lvalue char [12]] // CHECK-NEXT: literal: "const char*" diff --git a/tests/unit_tests/sema/char_c_01.c b/tests/unit_tests/sema/char_c_01.c new file mode 100644 index 00000000..dcd74660 --- /dev/null +++ b/tests/unit_tests/sema/char_c_01.c @@ -0,0 +1,13 @@ +// RUN: %cxx %s + +char ch = 'a'; + +_Static_assert(_Generic(ch, int: 123, char: 321) == 321); + +_Static_assert(_Generic('a', int: 123, char: 321) == 123); + +_Static_assert(_Generic("str", char*: 123, const char*: 321) == 123); + +_Static_assert(_Generic(true ? "str" : (const char*)0, + char*: 123, + const char*: 321) == 321); \ No newline at end of file diff --git a/tests/unit_tests/sema/typeof_01.c b/tests/unit_tests/sema/typeof_01.c index a82b4a7b..60c5f790 100644 --- a/tests/unit_tests/sema/typeof_01.c +++ b/tests/unit_tests/sema/typeof_01.c @@ -1,7 +1,12 @@ -// RUN: %cxx -xc -verify -fcheck -dump-symbols %s | %filecheck %s +// RUN: %cxx -verify -dump-symbols %s | %filecheck %s -typeof('x') c; +char ch; + +typeof(ch) c1; +typeof('x') c2; typeof(0) i; -// CHECK: variable char c +// CHECK: variable char ch +// CHECK-NEXT: variable char c1 +// CHECK-NEXT: variable int c2 // CHECK-NEXT: variable int i