Skip to content

Commit ea46e20

Browse files
authored
[clang] fix classification of a string literal expression used as initializer (#101447)
1 parent 18b58d4 commit ea46e20

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ Improvements to Clang's diagnostics
130130
- Some template related diagnostics have been improved.
131131

132132
.. code-block:: c++
133-
133+
134134
void foo() { template <typename> int i; } // error: templates can only be declared in namespace or class scope
135135

136136
struct S {
@@ -170,6 +170,8 @@ Bug Fixes to C++ Support
170170
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
171171
- Fix a crash when checking destructor reference with an invalid initializer. (#GH97230)
172172
- Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
173+
- Fix a crash when checking the initialzier of an object that was initialized
174+
with a string literal. (#GH82167)
173175

174176
Bug Fixes to AST Handling
175177
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprClassification.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
119119

120120
// First come the expressions that are always lvalues, unconditionally.
121121
case Expr::ObjCIsaExprClass:
122-
// C++ [expr.prim.general]p1: A string literal is an lvalue.
123-
case Expr::StringLiteralClass:
124-
// @encode is equivalent to its string
125-
case Expr::ObjCEncodeExprClass:
126-
// __func__ and friends are too.
127-
case Expr::PredefinedExprClass:
128122
// Property references are lvalues
129123
case Expr::ObjCSubscriptRefExprClass:
130124
case Expr::ObjCPropertyRefExprClass:
@@ -150,6 +144,26 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
150144
case Expr::OMPIteratorExprClass:
151145
return Cl::CL_LValue;
152146

147+
// C++ [expr.prim.general]p1: A string literal is an lvalue.
148+
case Expr::StringLiteralClass:
149+
// @encode is equivalent to its string
150+
case Expr::ObjCEncodeExprClass:
151+
// Except we special case them as prvalues when they are used to
152+
// initialize a char array.
153+
return E->isLValue() ? Cl::CL_LValue : Cl::CL_PRValue;
154+
155+
// __func__ and friends are too.
156+
// The char array initialization special case also applies
157+
// when they are transparent.
158+
case Expr::PredefinedExprClass: {
159+
auto *PE = cast<PredefinedExpr>(E);
160+
const StringLiteral *SL = PE->getFunctionName();
161+
if (PE->isTransparent())
162+
return SL ? ClassifyInternal(Ctx, SL) : Cl::CL_LValue;
163+
assert(!SL || SL->isLValue());
164+
return Cl::CL_LValue;
165+
}
166+
153167
// C99 6.5.2.5p5 says that compound literals are lvalues.
154168
// In C++, they're prvalue temporaries, except for file-scope arrays.
155169
case Expr::CompoundLiteralExprClass:

clang/test/SemaCXX/GH82167.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++23 -fsyntax-only -verify -xobjective-c++ %s
2+
// expected-no-diagnostics
3+
4+
namespace t1 {
5+
struct array {
6+
char elems[2];
7+
};
8+
9+
template <unsigned> struct Literal {
10+
array arr;
11+
constexpr Literal() : arr("") {}
12+
};
13+
14+
template struct Literal<0>;
15+
} // namespace t1
16+
17+
namespace t2 {
18+
struct array {
19+
char elems[2];
20+
};
21+
22+
template <unsigned> struct Literal {
23+
array arr;
24+
constexpr Literal() : arr(@encode(int)) {}
25+
};
26+
27+
template struct Literal<0>;
28+
} // namespace t2

0 commit comments

Comments
 (0)