forked from OSchip/llvm-project
DR616, and part of P0135R1: member access (or pointer-to-member access) on a
temporary produces an xvalue, not a prvalue. Support this by materializing the temporary prior to performing the member access. llvm-svn: 288563
This commit is contained in:
parent
05049bed02
commit
4baaa5ab52
|
@ -839,6 +839,11 @@ public:
|
|||
const Expr *skipRValueSubobjectAdjustments(
|
||||
SmallVectorImpl<const Expr *> &CommaLHS,
|
||||
SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
|
||||
const Expr *skipRValueSubobjectAdjustments() const {
|
||||
SmallVector<const Expr *, 8> CommaLHSs;
|
||||
SmallVector<SubobjectAdjustment, 8> Adjustments;
|
||||
return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() >= firstExprConstant &&
|
||||
|
|
|
@ -8715,6 +8715,11 @@ public:
|
|||
// argument, and arguments that have type float are promoted to double.
|
||||
ExprResult DefaultArgumentPromotion(Expr *E);
|
||||
|
||||
/// If \p E is a prvalue denoting an unmaterialized temporary, materialize
|
||||
/// it as an xvalue. In C++98, the result will still be a prvalue, because
|
||||
/// we don't have xvalues there.
|
||||
ExprResult TemporaryMaterializationConversion(Expr *E);
|
||||
|
||||
// Used for emitting the right warning by DefaultVariadicArgumentPromotion
|
||||
enum VariadicCallType {
|
||||
VariadicFunction,
|
||||
|
|
|
@ -1583,7 +1583,7 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr *Exp,
|
|||
/// a pointer marked with pt_guarded_by.
|
||||
void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK,
|
||||
ProtectedOperationKind POK) {
|
||||
Exp = Exp->IgnoreParenCasts();
|
||||
Exp = Exp->IgnoreImplicit()->IgnoreParenCasts();
|
||||
|
||||
SourceLocation Loc = Exp->getExprLoc();
|
||||
|
||||
|
|
|
@ -233,6 +233,9 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
|
|||
return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
|
||||
case Stmt::MaterializeTemporaryExprClass:
|
||||
return translate(cast<MaterializeTemporaryExpr>(S)->GetTemporaryExpr(),
|
||||
Ctx);
|
||||
|
||||
// Collect all literals
|
||||
case Stmt::CharacterLiteralClass:
|
||||
|
|
|
@ -9810,8 +9810,8 @@ static bool IsReadonlyMessage(Expr *E, Sema &S) {
|
|||
const MemberExpr *ME = dyn_cast<MemberExpr>(E);
|
||||
if (!ME) return false;
|
||||
if (!isa<FieldDecl>(ME->getMemberDecl())) return false;
|
||||
ObjCMessageExpr *Base =
|
||||
dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts());
|
||||
ObjCMessageExpr *Base = dyn_cast<ObjCMessageExpr>(
|
||||
ME->getBase()->IgnoreImplicit()->IgnoreParenImpCasts());
|
||||
if (!Base) return false;
|
||||
return Base->getMethodDecl() != nullptr;
|
||||
}
|
||||
|
@ -9894,7 +9894,7 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
|
|||
while (true) {
|
||||
IsDereference = NextIsDereference;
|
||||
|
||||
E = E->IgnoreParenImpCasts();
|
||||
E = E->IgnoreImplicit()->IgnoreParenImpCasts();
|
||||
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
||||
NextIsDereference = ME->isArrow();
|
||||
const ValueDecl *VD = ME->getMemberDecl();
|
||||
|
|
|
@ -4984,11 +4984,14 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
|
|||
!RHS.get()->getType()->isPlaceholderType() &&
|
||||
"placeholders should have been weeded out by now");
|
||||
|
||||
// The LHS undergoes lvalue conversions if this is ->*.
|
||||
if (isIndirect) {
|
||||
// The LHS undergoes lvalue conversions if this is ->*, and undergoes the
|
||||
// temporary materialization conversion otherwise.
|
||||
if (isIndirect)
|
||||
LHS = DefaultLvalueConversion(LHS.get());
|
||||
if (LHS.isInvalid()) return QualType();
|
||||
}
|
||||
else if (LHS.get()->isRValue())
|
||||
LHS = TemporaryMaterializationConversion(LHS.get());
|
||||
if (LHS.isInvalid())
|
||||
return QualType();
|
||||
|
||||
// The RHS always undergoes lvalue conversions.
|
||||
RHS = DefaultLvalueConversion(RHS.get());
|
||||
|
|
|
@ -969,6 +969,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
|
|||
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
|
||||
}
|
||||
R.setBaseObjectType(BaseType);
|
||||
|
||||
// C++1z [expr.ref]p2:
|
||||
// For the first option (dot) the first expression shall be a glvalue [...]
|
||||
if (!IsArrow && BaseExpr->isRValue()) {
|
||||
ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
|
||||
if (Converted.isInvalid())
|
||||
return ExprError();
|
||||
BaseExpr = Converted.get();
|
||||
}
|
||||
|
||||
LambdaScopeInfo *const CurLSI = getCurLambda();
|
||||
// If this is an implicit member reference and the overloaded
|
||||
|
|
|
@ -5963,10 +5963,7 @@ performReferenceExtension(Expr *Init,
|
|||
|
||||
// Step over any subobject adjustments; we may have a materialized
|
||||
// temporary inside them.
|
||||
SmallVector<const Expr *, 2> CommaLHSs;
|
||||
SmallVector<SubobjectAdjustment, 2> Adjustments;
|
||||
Init = const_cast<Expr *>(
|
||||
Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
|
||||
Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
|
||||
|
||||
// Per current approach for DR1376, look through casts to reference type
|
||||
// when performing lifetime extension.
|
||||
|
@ -5996,10 +5993,7 @@ performReferenceExtension(Expr *Init,
|
|||
static void performLifetimeExtension(Expr *Init,
|
||||
const InitializedEntity *ExtendingEntity) {
|
||||
// Dig out the expression which constructs the extended temporary.
|
||||
SmallVector<const Expr *, 2> CommaLHSs;
|
||||
SmallVector<SubobjectAdjustment, 2> Adjustments;
|
||||
Init = const_cast<Expr *>(
|
||||
Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
|
||||
Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments());
|
||||
|
||||
if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init))
|
||||
Init = BTE->getSubExpr();
|
||||
|
@ -6218,6 +6212,22 @@ Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
|
|||
return MTE;
|
||||
}
|
||||
|
||||
ExprResult Sema::TemporaryMaterializationConversion(Expr *E) {
|
||||
// In C++98, we don't want to implicitly create an xvalue.
|
||||
// FIXME: This means that AST consumers need to deal with "prvalues" that
|
||||
// denote materialized temporaries. Maybe we should add another ValueKind
|
||||
// for "xvalue pretending to be a prvalue" for C++98 support.
|
||||
if (!E->isRValue() || !getLangOpts().CPlusPlus11)
|
||||
return E;
|
||||
|
||||
// C++1z [conv.rval]/1: T shall be a complete type.
|
||||
QualType T = E->getType();
|
||||
if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type))
|
||||
return ExprError();
|
||||
|
||||
return CreateMaterializeTemporaryExpr(E->getType(), E, false);
|
||||
}
|
||||
|
||||
ExprResult
|
||||
InitializationSequence::Perform(Sema &S,
|
||||
const InitializedEntity &Entity,
|
||||
|
@ -6316,7 +6326,9 @@ InitializationSequence::Perform(Sema &S,
|
|||
if (Args.size() == 1 && Args[0]->getType()->isArrayType() &&
|
||||
Entity.getType()->isPointerType() &&
|
||||
InitializedEntityOutlivesFullExpression(Entity)) {
|
||||
Expr *Init = Args[0];
|
||||
const Expr *Init = Args[0]->skipRValueSubobjectAdjustments();
|
||||
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init))
|
||||
Init = MTE->GetTemporaryExpr();
|
||||
Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context);
|
||||
if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary)
|
||||
S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay)
|
||||
|
|
|
@ -1093,9 +1093,9 @@ int testConsistencyNestedNormalReturn(bool value) {
|
|||
// CHECK: 1: int a;
|
||||
// CHECK: 2: NoReturn() (CXXConstructExpr, class NoReturn)
|
||||
// CHECK: 3: [B2.2] (BindTemporary)
|
||||
// CHECK: 4: [B2.3].f
|
||||
// CHECK: 5: [B2.4]()
|
||||
// CHECK: 6: ~NoReturn() (Temporary object destructor)
|
||||
// CHECK: [[MEMBER:[45]]]: [B2.{{[34]}}].f
|
||||
// CHECK: {{[56]}}: [B2.[[MEMBER]]]()
|
||||
// CHECK: {{[67]}}: ~NoReturn() (Temporary object destructor)
|
||||
// CHECK: Preds (1): B3
|
||||
// CHECK: Succs (1): B0
|
||||
// CHECK: [B0 (EXIT)]
|
||||
|
|
|
@ -327,7 +327,7 @@ namespace dr420 { // dr420: yes
|
|||
|
||||
namespace dr421 { // dr421: yes
|
||||
struct X { X(); int n; int &r; };
|
||||
int *p = &X().n; // expected-error {{taking the address of a temporary}}
|
||||
int *p = &X().n; // expected-error-re {{{{taking the address of a temporary|cannot take the address of an rvalue}}}}
|
||||
int *q = &X().r;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,15 +142,21 @@ namespace dr615 { // dr615: yes
|
|||
static int n = f();
|
||||
}
|
||||
|
||||
namespace dr616 { // dr616: no
|
||||
namespace dr616 { // dr616: 4.0
|
||||
#if __cplusplus >= 201103L
|
||||
struct S { int n; } s;
|
||||
// FIXME: These should all be 'int &&'
|
||||
using T = decltype(S().n);
|
||||
using T = decltype(static_cast<S&&>(s).n);
|
||||
using T = decltype(S().*&S::n); // expected-note 2{{previous}}
|
||||
using T = decltype(static_cast<S&&>(s).*&S::n); // expected-error {{different type}}
|
||||
using T = int&&; // expected-error {{different type}}
|
||||
S f();
|
||||
using T = decltype((S().n));
|
||||
using T = decltype((static_cast<S&&>(s).n));
|
||||
using T = decltype((f().n));
|
||||
using T = decltype(S().*&S::n);
|
||||
using T = decltype(static_cast<S&&>(s).*&S::n);
|
||||
using T = decltype(f().*&S::n);
|
||||
using T = int&&;
|
||||
|
||||
using U = decltype(S().n);
|
||||
using U = decltype(static_cast<S&&>(s).n);
|
||||
using U = int;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@ struct NonConstexpr3 {
|
|||
int m : NonConstexpr2().n; // expected-error {{constant expression}} expected-note {{undefined constructor 'NonConstexpr2'}}
|
||||
};
|
||||
struct NonConstexpr4 {
|
||||
NonConstexpr4(); // expected-note {{declared here}}
|
||||
NonConstexpr4();
|
||||
int n;
|
||||
};
|
||||
struct NonConstexpr5 {
|
||||
int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4' cannot be used in a constant expression}}
|
||||
int n : NonConstexpr4().n; // expected-error {{constant expression}} expected-note {{non-literal type 'NonConstexpr4' cannot be used in a constant expression}}
|
||||
};
|
||||
|
||||
// - an invocation of an undefined constexpr function or an undefined
|
||||
|
@ -321,7 +321,7 @@ namespace LValueToRValue {
|
|||
// temporary object whose lifetime has not ended, initialized with a
|
||||
// constant expression;
|
||||
constexpr volatile S f() { return S(); }
|
||||
static_assert(f().i, ""); // ok! there's no lvalue-to-rvalue conversion here!
|
||||
static_assert(f().i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
|
||||
static_assert(((volatile const S&&)(S)0).i, ""); // expected-error {{constant expression}} expected-note {{read of volatile-qualified type}}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,23 +38,33 @@ int g() {
|
|||
return v[0];
|
||||
}
|
||||
|
||||
// GCC's compound-literals-in-C++ extension lifetime-extends a compound literal
|
||||
// (or a C++11 list-initialized temporary!) if:
|
||||
// - it is at global scope
|
||||
// - it has array type
|
||||
// - it has a constant initializer
|
||||
|
||||
struct Z { int i[3]; };
|
||||
int *p = (Z){ {1, 2, 3} }.i;
|
||||
// CHECK: define {{.*}}__cxx_global_var_init()
|
||||
// CHECK: store i32* getelementptr inbounds (%struct.Z, %struct.Z* @.compoundliteral, i32 0, i32 0, i32 0), i32** @p
|
||||
// CHECK: alloca %struct.Z
|
||||
// CHECK: store i32* %{{.*}}, i32** @p
|
||||
|
||||
int *q = (int [5]){1, 2, 3, 4, 5};
|
||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.1()
|
||||
// CHECK: store i32* getelementptr inbounds ([5 x i32], [5 x i32]* @.compoundliteral, i32 0, i32 0), i32** @q
|
||||
|
||||
int *PR21912_1 = (int []){};
|
||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.1()
|
||||
// CHECK: store i32* getelementptr inbounds ([0 x i32], [0 x i32]* @.compoundliteral.2, i32 0, i32 0), i32** @PR21912_1
|
||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.2()
|
||||
// CHECK: store i32* getelementptr inbounds ([0 x i32], [0 x i32]* @.compoundliteral.3, i32 0, i32 0), i32** @PR21912_1
|
||||
|
||||
union PR21912Ty {
|
||||
long long l;
|
||||
double d;
|
||||
};
|
||||
union PR21912Ty *PR21912_2 = (union PR21912Ty[]){{.d = 2.0}, {.l = 3}};
|
||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.3()
|
||||
// CHECK: store %union.PR21912Ty* getelementptr inbounds ([2 x %union.PR21912Ty], [2 x %union.PR21912Ty]* bitcast (<{ { double }, %union.PR21912Ty }>* @.compoundliteral.4 to [2 x %union.PR21912Ty]*), i32 0, i32 0), %union.PR21912Ty** @PR21912_2
|
||||
// CHECK-LABEL: define {{.*}}__cxx_global_var_init.4()
|
||||
// CHECK: store %union.PR21912Ty* getelementptr inbounds ([2 x %union.PR21912Ty], [2 x %union.PR21912Ty]* bitcast (<{ { double }, %union.PR21912Ty }>* @.compoundliteral.5 to [2 x %union.PR21912Ty]*), i32 0, i32 0), %union.PR21912Ty** @PR21912_2
|
||||
|
||||
// This compound literal should have local scope.
|
||||
int computed_with_lambda = [] {
|
||||
|
|
|
@ -34,7 +34,7 @@ struct V : virtual C {};
|
|||
template<typename T> struct Z : T {
|
||||
constexpr Z() : V() {}
|
||||
};
|
||||
constexpr int n = Z<V>().c; // expected-error {{constant expression}} expected-note {{virtual base class}}
|
||||
constexpr int n = Z<V>().c; // expected-error {{constant expression}} expected-note {{non-literal type 'Z<V>'}}
|
||||
|
||||
struct E {
|
||||
A a[2];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -fcxx-exceptions %s
|
||||
// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify -fcxx-exceptions %s
|
||||
|
||||
//
|
||||
// Tests for "expression traits" intrinsics such as __is_lvalue_expr.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -std=c++98 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -std=c++11 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// rdar://9005189
|
||||
|
||||
@interface Foo
|
||||
|
@ -19,6 +20,6 @@ struct Bar {
|
|||
|
||||
- (void)baz {
|
||||
bar.x = 0;
|
||||
[self bar].x = 10; // expected-error {{assigning to 'readonly' return result of an Objective-C message not allowed}}
|
||||
[self bar].x = 10; // expected-error-re {{{{assigning to 'readonly' return result of an Objective-C message not allowed|expression is not assignable}}}}
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -594,7 +594,7 @@ TEST(MaterializeTemporaryExpr, MatchesTemporary) {
|
|||
materializeTemporaryExpr()));
|
||||
|
||||
EXPECT_TRUE(
|
||||
notMatches(ClassString +
|
||||
matches(ClassString +
|
||||
"string GetStringByValue();"
|
||||
"void run() { int k = GetStringByValue().length(); }",
|
||||
materializeTemporaryExpr()));
|
||||
|
|
|
@ -813,7 +813,7 @@
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#129">129</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Stability of uninitialized auto variables</td>
|
||||
<td class="none" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
<td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
</tr>
|
||||
<tr id="130">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#130">130</a></td>
|
||||
|
@ -1480,7 +1480,7 @@ accessible?</td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#240">240</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Uninitialized values and undefined behavior</td>
|
||||
<td class="none" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
<td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
</tr>
|
||||
<tr id="241">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#241">241</a></td>
|
||||
|
@ -1913,7 +1913,7 @@ of class templates</td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#312">312</a></td>
|
||||
<td>CD3</td>
|
||||
<td>“use” of invalid pointer value not defined</td>
|
||||
<td class="none" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
<td class="svn" align="center">Duplicate of <a href="#616">616</a></td>
|
||||
</tr>
|
||||
<tr id="313">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#313">313</a></td>
|
||||
|
@ -3739,7 +3739,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#616">616</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Definition of “indeterminate value”</td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr class="open" id="617">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#617">617</a></td>
|
||||
|
|
Loading…
Reference in New Issue