diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-03 01:14:32 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-12-03 01:14:32 +0000 |
commit | 4baaa5ab52870c3d2e1961aaa7758908ea69579e (patch) | |
tree | d0b7a59ca83d21a73fbd5a907b01941e9199da31 /clang/lib/Sema | |
parent | 05049bed027cb37ef4afcbc6b280603e767f7971 (diff) | |
download | bcm5719-llvm-4baaa5ab52870c3d2e1961aaa7758908ea69579e.tar.gz bcm5719-llvm-4baaa5ab52870c3d2e1961aaa7758908ea69579e.zip |
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
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 30 |
4 files changed, 40 insertions, 16 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 667ea6cb4e3..4415100ab45 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 79b5356d79d..28ccd607507 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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()); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index eddf0d69a22..806a3d813ee 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -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 diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f5e38b4fbdf..3937aad012d 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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) |