diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1580,6 +1580,8 @@ QualType getTypeOfExprType(Expr *e) const; QualType getTypeOfType(QualType t) const; + QualType getDecltypeForParenthesizedExpr(const Expr *e) const; + /// C++11 decltype. QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2293,7 +2293,6 @@ const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); - QualType getDecltypeForParenthesizedExpr(Expr *E); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5429,6 +5429,29 @@ return QualType(tot, 0); } +/// getDecltypeForParenthesizedExpr - Given an expr, will return the type for +/// that expression, as in [dcl.type.simple]p4 but without taking id-expressions +/// and class member access into account. +QualType ASTContext::getDecltypeForParenthesizedExpr(const Expr *e) const { + // C++11 [dcl.type.simple]p4: + // [...] + QualType T = e->getType(); + switch (e->getValueKind()) { + // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the + // type of e; + case VK_XValue: + return getRValueReferenceType(T); + // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the + // type of e; + case VK_LValue: + return getLValueReferenceType(T); + // - otherwise, decltype(e) is the type of e. + case VK_RValue: + return T; + } + llvm_unreachable("Unknown value kind"); +} + /// Unlike many "get" functions, we don't unique DecltypeType /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3731,8 +3731,7 @@ const ObjCPropertyRefExpr *Expr::getObjCProperty() const { const Expr *E = this; while (true) { - assert((E->getValueKind() == VK_LValue && - E->getObjectKind() == OK_ObjCProperty) && + assert((E->isLValue() && E->getObjectKind() == OK_ObjCProperty) && "expression is not a property reference"); E = E->IgnoreParenCasts(); if (const BinaryOperator *BO = dyn_cast(E)) { @@ -3771,7 +3770,7 @@ while (ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_LValueToRValue || - (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp)) + (!ICE->isRValue() && ICE->getCastKind() == CK_NoOp)) E = ICE->getSubExpr()->IgnoreParens(); else break; @@ -3818,8 +3817,7 @@ const Expr *E = this->IgnoreParens(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->getValueKind() != VK_RValue && - ICE->getCastKind() == CK_NoOp) + if (!ICE->isRValue() && ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr()->IgnoreParens(); else break; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -53,8 +53,12 @@ // 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_LValue: + assert(isLValue()); + break; + case Cl::CL_XValue: + assert(isXValue()); + break; case Cl::CL_Function: case Cl::CL_Void: case Cl::CL_AddressableVoid: @@ -64,7 +68,9 @@ case Cl::CL_ClassTemporary: case Cl::CL_ArrayTemporary: case Cl::CL_ObjCMessageRValue: - case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; + case Cl::CL_PRValue: + assert(isRValue()); + break; } Cl::ModifiableType modifiable = Cl::CM_Untested; diff --git a/clang/lib/AST/ExprObjC.cpp b/clang/lib/AST/ExprObjC.cpp --- a/clang/lib/AST/ExprObjC.cpp +++ b/clang/lib/AST/ExprObjC.cpp @@ -275,16 +275,7 @@ // Expression type might be different from an expected call return type, // as expression type would never be a reference even if call returns a // reference. Reconstruct the original expression type. - QualType QT = getType(); - switch (getValueKind()) { - case VK_LValue: - return Ctx.getLValueReferenceType(QT); - case VK_XValue: - return Ctx.getRValueReferenceType(QT); - case VK_RValue: - return QT; - } - llvm_unreachable("Unsupported ExprValueKind"); + return Ctx.getDecltypeForParenthesizedExpr(this); } SourceRange ObjCMessageExpr::getReceiverRange() const { diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -708,10 +708,10 @@ } // If it was an l-value, use objc_copyWeak. - if (srcExpr->getValueKind() == VK_LValue) { + if (srcExpr->isLValue()) { CGF.EmitARCCopyWeak(destLV.getAddress(CGF), srcAddr); } else { - assert(srcExpr->getValueKind() == VK_XValue); + assert(srcExpr->isXValue()); CGF.EmitARCMoveWeak(destLV.getAddress(CGF), srcAddr); } return true; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1947,7 +1947,7 @@ if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { // And that glvalue casts are never null. - if (ICE->getValueKind() != VK_RValue) + if (!ICE->isRValue()) return false; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -614,7 +614,7 @@ // C++1z [conv.array]: The temporary materialization conversion is applied. // We also use this to fuel C++ DR1213, which applies to C++11 onwards. if (Kind == CK_ArrayToPointerDecay && getLangOpts().CPlusPlus && - E->getValueKind() == VK_RValue) { + E->isRValue()) { // The temporary is an lvalue in C++98 and an xvalue otherwise. ExprResult Materialized = CreateMaterializeTemporaryExpr( E->getType(), E, !getLangOpts().CPlusPlus11); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -445,7 +445,7 @@ Expr *e = Req->getExpr(); S.Diag(e->getBeginLoc(), diag::note_expr_requirement_constraints_not_satisfied_simple) - << (int)First << S.getDecltypeForParenthesizedExpr(e) + << (int)First << S.Context.getDecltypeForParenthesizedExpr(e) << ConstraintExpr->getNamedConcept(); } else { S.Diag(ConstraintExpr->getBeginLoc(), diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -897,7 +897,7 @@ // If the expression is a temporary, materialize it as an lvalue so that we // can use it multiple times. - if (E->getValueKind() == VK_RValue) + if (E->isRValue()) E = CreateMaterializeTemporaryExpr(E->getType(), E, true); // The location of the `co_await` token cannot be used when constructing @@ -957,7 +957,7 @@ // If the expression is a temporary, materialize it as an lvalue so that we // can use it multiple times. - if (E->getValueKind() == VK_RValue) + if (E->isRValue()) E = CreateMaterializeTemporaryExpr(E->getType(), E, true); // Build the await_ready, await_suspend, await_resume calls. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5513,7 +5513,7 @@ BaseExpr = LHSExp; // vectors: V[123] IndexExpr = RHSExp; // We apply C++ DR1213 to vector subscripting too. - if (getLangOpts().CPlusPlus11 && LHSExp->getValueKind() == VK_RValue) { + if (getLangOpts().CPlusPlus11 && LHSExp->isRValue()) { ExprResult Materialized = TemporaryMaterializationConversion(LHSExp); if (Materialized.isInvalid()) return ExprError(); @@ -10093,7 +10093,7 @@ RHSType, DiagID)) return RHSType; } else { - if (LHS.get()->getValueKind() == VK_LValue || + if (LHS.get()->isLValue() || !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) return RHSType; } @@ -14816,7 +14816,7 @@ // complex l-values to ordinary l-values and all other values to r-values. if (Input.isInvalid()) return ExprError(); if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) { - if (Input.get()->getValueKind() != VK_RValue && + if (!Input.get()->isRValue() && Input.get()->getObjectKind() == OK_Ordinary) VK = Input.get()->getValueKind(); } else if (!getLangOpts().CPlusPlus) { @@ -18985,7 +18985,7 @@ Expr *SubExpr = SubResult.get(); E->setSubExpr(SubExpr); E->setType(S.Context.getPointerType(SubExpr->getType())); - assert(E->getValueKind() == VK_RValue); + assert(E->isRValue()); assert(E->getObjectKind() == OK_Ordinary); return E; } @@ -18995,7 +18995,7 @@ E->setType(VD->getType()); - assert(E->getValueKind() == VK_RValue); + assert(E->isRValue()); if (S.getLangOpts().CPlusPlus && !(isa(VD) && cast(VD)->isInstance())) @@ -19086,7 +19086,7 @@ return ExprError(); } - assert(E->getValueKind() == VK_RValue); + assert(E->isRValue()); assert(E->getObjectKind() == OK_Ordinary); E->setType(DestType); @@ -19180,14 +19180,8 @@ if (ParamTypes.empty() && Proto->isVariadic()) { // the special case ArgTypes.reserve(E->getNumArgs()); for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { - Expr *Arg = E->getArg(i); - QualType ArgType = Arg->getType(); - if (E->isLValue()) { - ArgType = S.Context.getLValueReferenceType(ArgType); - } else if (E->isXValue()) { - ArgType = S.Context.getRValueReferenceType(ArgType); - } - ArgTypes.push_back(ArgType); + ArgTypes.push_back( + S.Context.getDecltypeForParenthesizedExpr(E->getArg(i))); } ParamTypes = ArgTypes; } @@ -19246,7 +19240,7 @@ ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *E) { // The only case we should ever see here is a function-to-pointer decay. if (E->getCastKind() == CK_FunctionToPointerDecay) { - assert(E->getValueKind() == VK_RValue); + assert(E->isRValue()); assert(E->getObjectKind() == OK_Ordinary); E->setType(DestType); @@ -19260,7 +19254,7 @@ E->setSubExpr(Result.get()); return E; } else if (E->getCastKind() == CK_LValueToRValue) { - assert(E->getValueKind() == VK_RValue); + assert(E->isRValue()); assert(E->getObjectKind() == OK_Ordinary); assert(isa(E->getType())); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5841,10 +5841,8 @@ // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. - if (To->isLValue() || To->isXValue()) { - QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) - : Self.Context.getRValueReferenceType(ToType); - + if (!To->isRValue()) { + QualType T = Self.Context.getDecltypeForParenthesizedExpr(To); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); @@ -8663,7 +8661,7 @@ TemplateParameterList *TPL = ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); QualType MatchedType = - getDecltypeForParenthesizedExpr(E).getCanonicalType(); + Context.getDecltypeForParenthesizedExpr(E).getCanonicalType(); llvm::SmallVector Args; Args.push_back(TemplateArgument(MatchedType)); TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5830,7 +5830,7 @@ Entity.getType()) && canPerformArrayCopy(Entity)) { // If source is a prvalue, use it directly. - if (Initializer->getValueKind() == VK_RValue) { + if (Initializer->isRValue()) { AddArrayInitStep(DestType, /*IsGNUExtension*/false); return; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8830,29 +8830,6 @@ return Context.getTypeOfExprType(E); } -/// getDecltypeForParenthesizedExpr - Given an expr, will return the type for -/// that expression, as in [dcl.type.simple]p4 but without taking id-expressions -/// and class member access into account. -QualType Sema::getDecltypeForParenthesizedExpr(Expr *E) { - // C++11 [dcl.type.simple]p4: - // [...] - QualType T = E->getType(); - switch (E->getValueKind()) { - // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the - // type of e; - case VK_XValue: - return Context.getRValueReferenceType(T); - // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the - // type of e; - case VK_LValue: - return Context.getLValueReferenceType(T); - // - otherwise, decltype(e) is the type of e. - case VK_RValue: - return T; - } - llvm_unreachable("Unknown value kind"); -} - /// getDecltypeForExpr - Given an expr, will return the decltype for /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. @@ -8917,7 +8894,7 @@ } } - return S.getDecltypeForParenthesizedExpr(E); + return S.Context.getDecltypeForParenthesizedExpr(E); } QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -70,28 +70,7 @@ QualType CallEvent::getResultType() const { ASTContext &Ctx = getState()->getStateManager().getContext(); const Expr *E = getOriginExpr(); - if (!E) - return Ctx.VoidTy; - assert(E); - - QualType ResultTy = E->getType(); - - // A function that returns a reference to 'int' will have a result type - // of simply 'int'. Check the origin expr's value kind to recover the - // proper type. - switch (E->getValueKind()) { - case VK_LValue: - ResultTy = Ctx.getLValueReferenceType(ResultTy); - break; - case VK_XValue: - ResultTy = Ctx.getRValueReferenceType(ResultTy); - break; - case VK_RValue: - // No adjustment is necessary. - break; - } - - return ResultTy; + return E ? Ctx.getDecltypeForParenthesizedExpr(E) : Ctx.VoidTy; } static bool isCallback(QualType T) {