1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
|
//===--- ExprClassification.cpp - Expression AST Node Implementation ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements Expr::classify.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
typedef Expr::Classification Cl;
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E);
static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D);
static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T);
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E);
static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E);
static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
const Expr *trueExpr,
const Expr *falseExpr);
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
Cl::Kinds Kind, SourceLocation &Loc);
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
Cl::Kinds kind = ClassifyInternal(Ctx, this);
// C99 6.3.2.1: An lvalue is an expression with an object type or an
// incomplete type other than void.
if (!Ctx.getLangOpts().CPlusPlus) {
// Thus, no functions.
if (TR->isFunctionType() || TR == Ctx.OverloadTy)
kind = Cl::CL_Function;
// No void either, but qualified void is OK because it is "other than void".
// Void "lvalues" are classified as addressable void values, which are void
// expressions whose address can be taken.
else if (TR->isVoidType() && !TR.hasQualifiers())
kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void);
}
// Enable this assertion for testing.
switch (kind) {
case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break;
case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break;
case Cl::CL_Function:
case Cl::CL_Void:
case Cl::CL_AddressableVoid:
case Cl::CL_DuplicateVectorComponents:
case Cl::CL_MemberFunction:
case Cl::CL_SubObjCPropertySetting:
case Cl::CL_ClassTemporary:
case Cl::CL_ArrayTemporary:
case Cl::CL_ObjCMessageRValue:
case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break;
}
Cl::ModifiableType modifiable = Cl::CM_Untested;
if (Loc)
modifiable = IsModifiable(Ctx, this, kind, *Loc);
return Classification(kind, modifiable);
}
/// Classify an expression which creates a temporary, based on its type.
static Cl::Kinds ClassifyTemporary(QualType T) {
if (T->isRecordType())
return Cl::CL_ClassTemporary;
if (T->isArrayType())
return Cl::CL_ArrayTemporary;
// No special classification: these don't behave differently from normal
// prvalues.
return Cl::CL_PRValue;
}
static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
const Expr *E,
ExprValueKind Kind) {
switch (Kind) {
case VK_RValue:
return Lang.CPlusPlus ? ClassifyTemporary(E->getType()) : Cl::CL_PRValue;
case VK_LValue:
return Cl::CL_LValue;
case VK_XValue:
return Cl::CL_XValue;
}
llvm_unreachable("Invalid value category of implicit cast.");
}
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
const LangOptions &Lang = Ctx.getLangOpts();
switch (E->getStmtClass()) {
case Stmt::NoStmtClass:
#define ABSTRACT_STMT(Kind)
#define STMT(Kind, Base) case Expr::Kind##Class:
#define EXPR(Kind, Base)
#include "clang/AST/StmtNodes.inc"
llvm_unreachable("cannot classify a statement");
// First come the expressions that are always lvalues, unconditionally.
case Expr::ObjCIsaExprClass:
// C++ [expr.prim.general]p1: A string literal is an lvalue.
case Expr::StringLiteralClass:
// @encode is equivalent to its string
case Expr::ObjCEncodeExprClass:
// __func__ and friends are too.
case Expr::PredefinedExprClass:
// Property references are lvalues
case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCPropertyRefExprClass:
// C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of...
case Expr::CXXTypeidExprClass:
// Unresolved lookups get classified as lvalues.
// FIXME: Is this wise? Should they get their own kind?
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
case Expr::FunctionParmPackExprClass:
case Expr::MSPropertyRefExprClass:
return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.
// In C++, they're prvalue temporaries.
case Expr::CompoundLiteralExprClass:
return Ctx.getLangOpts().CPlusPlus ? ClassifyTemporary(E->getType())
: Cl::CL_LValue;
// Expressions that are prvalues.
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::ImaginaryLiteralClass:
case Expr::GNUNullExprClass:
case Expr::OffsetOfExprClass:
case Expr::CXXThrowExprClass:
case Expr::ShuffleVectorExprClass:
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
case Expr::CXXDeleteExprClass:
case Expr::ImplicitValueInitExprClass:
case Expr::BlockExprClass:
case Expr::FloatingLiteralClass:
case Expr::CXXNoexceptExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
case Expr::TypeTraitExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::ObjCSelectorExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCBoxedExprClass:
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
case Expr::ObjCBoolLiteralExprClass:
case Expr::ParenListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
case Expr::AsTypeExprClass:
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::AtomicExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
case Expr::SubstNonTypeTemplateParmExprClass:
return ClassifyInternal(Ctx,
cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement());
// C++ [expr.sub]p1: The result is an lvalue of type "T".
// However, subscripting vector types is more like member access.
case Expr::ArraySubscriptExprClass:
if (cast<ArraySubscriptExpr>(E)->getBase()->getType()->isVectorType())
return ClassifyInternal(Ctx, cast<ArraySubscriptExpr>(E)->getBase());
return Cl::CL_LValue;
// C++ [expr.prim.general]p3: The result is an lvalue if the entity is a
// function or variable and a prvalue otherwise.
case Expr::DeclRefExprClass:
if (E->getType() == Ctx.UnknownAnyTy)
return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl())
? Cl::CL_PRValue : Cl::CL_LValue;
return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl());
// Member access is complex.
case Expr::MemberExprClass:
return ClassifyMemberExpr(Ctx, cast<MemberExpr>(E));
case Expr::UnaryOperatorClass:
switch (cast<UnaryOperator>(E)->getOpcode()) {
// C++ [expr.unary.op]p1: The unary * operator performs indirection:
// [...] the result is an lvalue referring to the object or function
// to which the expression points.
case UO_Deref:
return Cl::CL_LValue;
// GNU extensions, simply look through them.
case UO_Extension:
return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr());
// Treat _Real and _Imag basically as if they were member
// expressions: l-value only if the operand is a true l-value.
case UO_Real:
case UO_Imag: {
const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
Cl::Kinds K = ClassifyInternal(Ctx, Op);
if (K != Cl::CL_LValue) return K;
if (isa<ObjCPropertyRefExpr>(Op))
return Cl::CL_SubObjCPropertySetting;
return Cl::CL_LValue;
}
// C++ [expr.pre.incr]p1: The result is the updated operand; it is an
// lvalue, [...]
// Not so in C.
case UO_PreInc:
case UO_PreDec:
return Lang.CPlusPlus ? Cl::CL_LValue : Cl::CL_PRValue;
default:
return Cl::CL_PRValue;
}
case Expr::OpaqueValueExprClass:
return ClassifyExprValueKind(Lang, E, E->getValueKind());
// Pseudo-object expressions can produce l-values with reference magic.
case Expr::PseudoObjectExprClass:
return ClassifyExprValueKind(Lang, E,
cast<PseudoObjectExpr>(E)->getValueKind());
// Implicit casts are lvalues if they're lvalue casts. Other than that, we
// only specifically record class temporaries.
case Expr::ImplicitCastExprClass:
return ClassifyExprValueKind(Lang, E, E->getValueKind());
// C++ [expr.prim.general]p4: The presence of parentheses does not affect
// whether the expression is an lvalue.
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
// C11 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
// or a void expression if its result expression is, respectively, an
// lvalue, a function designator, or a void expression.
case Expr::GenericSelectionExprClass:
if (cast<GenericSelectionExpr>(E)->isResultDependent())
return Cl::CL_PRValue;
return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::BinaryOperatorClass:
case Expr::CompoundAssignOperatorClass:
// C doesn't have any binary expressions that are lvalues.
if (Lang.CPlusPlus)
return ClassifyBinaryOp(Ctx, cast<BinaryOperator>(E));
return Cl::CL_PRValue;
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::CXXMemberCallExprClass:
case Expr::UserDefinedLiteralClass:
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType());
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx));
// Extended vector element access is an lvalue unless there are duplicates
// in the shuffle expression.
case Expr::ExtVectorElementExprClass:
return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ?
Cl::CL_DuplicateVectorComponents : Cl::CL_LValue;
// Simply look at the actual default argument.
case Expr::CXXDefaultArgExprClass:
return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr());
// Same idea for default initializers.
case Expr::CXXDefaultInitExprClass:
return ClassifyInternal(Ctx, cast<CXXDefaultInitExpr>(E)->getExpr());
// Same idea for temporary binding.
case Expr::CXXBindTemporaryExprClass:
return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr());
// And the cleanups guard.
case Expr::ExprWithCleanupsClass:
return ClassifyInternal(Ctx, cast<ExprWithCleanups>(E)->getSubExpr());
// Casts depend completely on the target type. All casts work the same.
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXDynamicCastExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
case Expr::ObjCBridgedCastExprClass:
// Only in C++ can casts be interesting at all.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());
case Expr::CXXUnresolvedConstructExprClass:
return ClassifyUnnamed(Ctx,
cast<CXXUnresolvedConstructExpr>(E)->getTypeAsWritten());
case Expr::BinaryConditionalOperatorClass: {
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E);
return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
}
case Expr::ConditionalOperatorClass: {
// Once again, only C++ is interesting.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
const ConditionalOperator *co = cast<ConditionalOperator>(E);
return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
}
// ObjC message sends are effectively function calls, if the target function
// is known.
case Expr::ObjCMessageExprClass:
if (const ObjCMethodDecl *Method =
cast<ObjCMessageExpr>(E)->getMethodDecl()) {
Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType());
return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind;
}
return Cl::CL_PRValue;
// Some C++ expressions are always class temporaries.
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
return ClassifyUnnamed(Ctx, E->getType());
case Expr::DesignatedInitExprClass:
return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit());
case Expr::StmtExprClass: {
const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt();
if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back()))
return ClassifyUnnamed(Ctx, LastExpr->getType());
return Cl::CL_PRValue;
}
case Expr::CXXUuidofExprClass:
return Cl::CL_LValue;
case Expr::PackExpansionExprClass:
return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
case Expr::MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference()
? Cl::CL_LValue
: Cl::CL_XValue;
case Expr::InitListExprClass:
// An init list can be an lvalue if it is bound to a reference and
// contains only one element. In that case, we look at that element
// for an exact classification. Init list creation takes care of the
// value kind for us, so we only need to fine-tune.
if (E->isRValue())
return ClassifyExprValueKind(Lang, E, E->getValueKind());
assert(cast<InitListExpr>(E)->getNumInits() == 1 &&
"Only 1-element init lists can be glvalues.");
return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0));
}
llvm_unreachable("unhandled expression kind in classification");
}
/// ClassifyDecl - Return the classification of an expression referencing the
/// given declaration.
static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
// C++ [expr.prim.general]p6: The result is an lvalue if the entity is a
// function, variable, or data member and a prvalue otherwise.
// In C, functions are not lvalues.
// In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an
// lvalue unless it's a reference type (C++ [temp.param]p6), so we need to
// special-case this.
if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
return Cl::CL_MemberFunction;
bool islvalue;
if (const NonTypeTemplateParmDecl *NTTParm =
dyn_cast<NonTypeTemplateParmDecl>(D))
islvalue = NTTParm->getType()->isReferenceType();
else
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
(Ctx.getLangOpts().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)));
return islvalue ? Cl::CL_LValue : Cl::CL_PRValue;
}
/// ClassifyUnnamed - Return the classification of an expression yielding an
/// unnamed value of the given type. This applies in particular to function
/// calls and casts.
static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) {
// In C, function calls are always rvalues.
if (!Ctx.getLangOpts().CPlusPlus) return Cl::CL_PRValue;
// C++ [expr.call]p10: A function call is an lvalue if the result type is an
// lvalue reference type or an rvalue reference to function type, an xvalue
// if the result type is an rvalue reference to object type, and a prvalue
// otherwise.
if (T->isLValueReferenceType())
return Cl::CL_LValue;
const RValueReferenceType *RV = T->getAs<RValueReferenceType>();
if (!RV) // Could still be a class temporary, though.
return ClassifyTemporary(T);
return RV->getPointeeType()->isFunctionType() ? Cl::CL_LValue : Cl::CL_XValue;
}
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
if (E->getType() == Ctx.UnknownAnyTy)
return (isa<FunctionDecl>(E->getMemberDecl())
? Cl::CL_PRValue : Cl::CL_LValue);
// Handle C first, it's easier.
if (!Ctx.getLangOpts().CPlusPlus) {
// C99 6.5.2.3p3
// For dot access, the expression is an lvalue if the first part is. For
// arrow access, it always is an lvalue.
if (E->isArrow())
return Cl::CL_LValue;
// ObjC property accesses are not lvalues, but get special treatment.
Expr *Base = E->getBase()->IgnoreParens();
if (isa<ObjCPropertyRefExpr>(Base))
return Cl::CL_SubObjCPropertySetting;
return ClassifyInternal(Ctx, Base);
}
NamedDecl *Member = E->getMemberDecl();
// C++ [expr.ref]p3: E1->E2 is converted to the equivalent form (*(E1)).E2.
// C++ [expr.ref]p4: If E2 is declared to have type "reference to T", then
// E1.E2 is an lvalue.
if (ValueDecl *Value = dyn_cast<ValueDecl>(Member))
if (Value->getType()->isReferenceType())
return Cl::CL_LValue;
// Otherwise, one of the following rules applies.
// -- If E2 is a static member [...] then E1.E2 is an lvalue.
if (isa<VarDecl>(Member) && Member->getDeclContext()->isRecord())
return Cl::CL_LValue;
// -- If E2 is a non-static data member [...]. If E1 is an lvalue, then
// E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue;
// otherwise, it is a prvalue.
if (isa<FieldDecl>(Member)) {
// *E1 is an lvalue
if (E->isArrow())
return Cl::CL_LValue;
Expr *Base = E->getBase()->IgnoreParenImpCasts();
if (isa<ObjCPropertyRefExpr>(Base))
return Cl::CL_SubObjCPropertySetting;
return ClassifyInternal(Ctx, E->getBase());
}
// -- If E2 is a [...] member function, [...]
// -- If it refers to a static member function [...], then E1.E2 is an
// lvalue; [...]
// -- Otherwise [...] E1.E2 is a prvalue.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member))
return Method->isStatic() ? Cl::CL_LValue : Cl::CL_MemberFunction;
// -- If E2 is a member enumerator [...], the expression E1.E2 is a prvalue.
// So is everything else we haven't handled yet.
return Cl::CL_PRValue;
}
static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand.
// Except we override this for writes to ObjC properties.
if (E->isAssignmentOp())
return (E->getLHS()->getObjectKind() == OK_ObjCProperty
? Cl::CL_PRValue : Cl::CL_LValue);
// C++ [expr.comma]p1: the result is of the same value category as its right
// operand, [...].
if (E->getOpcode() == BO_Comma)
return ClassifyInternal(Ctx, E->getRHS());
// C++ [expr.mptr.oper]p6: The result of a .* expression whose second operand
// is a pointer to a data member is of the same value category as its first
// operand.
if (E->getOpcode() == BO_PtrMemD)
return (E->getType()->isFunctionType() ||
E->hasPlaceholderType(BuiltinType::BoundMember))
? Cl::CL_MemberFunction
: ClassifyInternal(Ctx, E->getLHS());
// C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its
// second operand is a pointer to data member and a prvalue otherwise.
if (E->getOpcode() == BO_PtrMemI)
return (E->getType()->isFunctionType() ||
E->hasPlaceholderType(BuiltinType::BoundMember))
? Cl::CL_MemberFunction
: Cl::CL_LValue;
// All other binary operations are prvalues.
return Cl::CL_PRValue;
}
static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
const Expr *False) {
assert(Ctx.getLangOpts().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.cond]p2
// If either the second or the third operand has type (cv) void, [...]
// the result [...] is a prvalue.
if (True->getType()->isVoidType() || False->getType()->isVoidType())
return Cl::CL_PRValue;
// Note that at this point, we have already performed all conversions
// according to [expr.cond]p3.
// C++ [expr.cond]p4: If the second and third operands are glvalues of the
// same value category [...], the result is of that [...] value category.
// C++ [expr.cond]p5: Otherwise, the result is a prvalue.
Cl::Kinds LCl = ClassifyInternal(Ctx, True),
RCl = ClassifyInternal(Ctx, False);
return LCl == RCl ? LCl : Cl::CL_PRValue;
}
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
Cl::Kinds Kind, SourceLocation &Loc) {
// As a general rule, we only care about lvalues. But there are some rvalues
// for which we want to generate special results.
if (Kind == Cl::CL_PRValue) {
// For the sake of better diagnostics, we want to specifically recognize
// use of the GCC cast-as-lvalue extension.
if (const ExplicitCastExpr *CE =
dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) {
if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) {
Loc = CE->getExprLoc();
return Cl::CM_LValueCast;
}
}
}
if (Kind != Cl::CL_LValue)
return Cl::CM_RValue;
// This is the lvalue case.
// Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6)
if (Ctx.getLangOpts().CPlusPlus && E->getType()->isFunctionType())
return Cl::CM_Function;
// Assignment to a property in ObjC is an implicit setter access. But a
// setter might not exist.
if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) {
if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0)
return Cl::CM_NoSetterProperty;
}
CanQualType CT = Ctx.getCanonicalType(E->getType());
// Const stuff is obviously not modifiable.
if (CT.isConstQualified())
return Cl::CM_ConstQualified;
// Arrays are not modifiable, only their elements are.
if (CT->isArrayType())
return Cl::CM_ArrayType;
// Incomplete types are not modifiable.
if (CT->isIncompleteType())
return Cl::CM_IncompleteType;
// Records with any const fields (recursively) are not modifiable.
if (const RecordType *R = CT->getAs<RecordType>()) {
assert((E->getObjectKind() == OK_ObjCProperty ||
!Ctx.getLangOpts().CPlusPlus) &&
"C++ struct assignment should be resolved by the "
"copy assignment operator.");
if (R->hasConstFields())
return Cl::CM_ConstQualified;
}
return Cl::CM_Modifiable;
}
Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const {
Classification VC = Classify(Ctx);
switch (VC.getKind()) {
case Cl::CL_LValue: return LV_Valid;
case Cl::CL_XValue: return LV_InvalidExpression;
case Cl::CL_Function: return LV_NotObjectType;
case Cl::CL_Void: return LV_InvalidExpression;
case Cl::CL_AddressableVoid: return LV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return LV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return LV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return LV_ClassTemporary;
case Cl::CL_ArrayTemporary: return LV_ArrayTemporary;
case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression;
case Cl::CL_PRValue: return LV_InvalidExpression;
}
llvm_unreachable("Unhandled kind");
}
Expr::isModifiableLvalueResult
Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
SourceLocation dummy;
Classification VC = ClassifyModifiable(Ctx, Loc ? *Loc : dummy);
switch (VC.getKind()) {
case Cl::CL_LValue: break;
case Cl::CL_XValue: return MLV_InvalidExpression;
case Cl::CL_Function: return MLV_NotObjectType;
case Cl::CL_Void: return MLV_InvalidExpression;
case Cl::CL_AddressableVoid: return MLV_IncompleteVoidType;
case Cl::CL_DuplicateVectorComponents: return MLV_DuplicateVectorComponents;
case Cl::CL_MemberFunction: return MLV_MemberFunction;
case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting;
case Cl::CL_ClassTemporary: return MLV_ClassTemporary;
case Cl::CL_ArrayTemporary: return MLV_ArrayTemporary;
case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression;
case Cl::CL_PRValue:
return VC.getModifiable() == Cl::CM_LValueCast ?
MLV_LValueCast : MLV_InvalidExpression;
}
assert(VC.getKind() == Cl::CL_LValue && "Unhandled kind");
switch (VC.getModifiable()) {
case Cl::CM_Untested: llvm_unreachable("Did not test modifiability");
case Cl::CM_Modifiable: return MLV_Valid;
case Cl::CM_RValue: llvm_unreachable("CM_RValue and CL_LValue don't match");
case Cl::CM_Function: return MLV_NotObjectType;
case Cl::CM_LValueCast:
llvm_unreachable("CM_LValueCast and CL_LValue don't match");
case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty;
case Cl::CM_ConstQualified: return MLV_ConstQualified;
case Cl::CM_ArrayType: return MLV_ArrayType;
case Cl::CM_IncompleteType: return MLV_IncompleteType;
}
llvm_unreachable("Unhandled modifiable type");
}
|