summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-06-13 19:00:16 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-06-13 19:00:16 +0000
commit17965d42f420a0ca6d7bd5b9a0d7d472dfc5689d (patch)
treed4b3f16ca1e33d6a0f70eab45704213457617e5c /clang/lib/Sema/SemaExpr.cpp
parent4244dd5e3f9e423db39dc8d1d235f67edf9b1875 (diff)
downloadbcm5719-llvm-17965d42f420a0ca6d7bd5b9a0d7d472dfc5689d.tar.gz
bcm5719-llvm-17965d42f420a0ca6d7bd5b9a0d7d472dfc5689d.zip
C++ DR712 and others: handle non-odr-use resulting from an lvalue-to-rvalue conversion applied to a member access or similar not-quite-trivial lvalue expression.
Summary: When a variable is named in a context where we can't directly emit a reference to it (because we don't know for sure that it's going to be defined, or it's from an enclosing function and not captured, or the reference might not "work" for some reason), we emit a copy of the variable as a global and use that for the known-to-be-read-only access. Reviewers: rjmccall Subscribers: jdoerfert, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D63157 llvm-svn: 363295
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r--clang/lib/Sema/SemaExpr.cpp153
1 files changed, 127 insertions, 26 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d444a35be86..bd54681b7e0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -15806,6 +15806,32 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
return DeclRefType;
}
+namespace {
+// Helper to copy the template arguments from a DeclRefExpr or MemberExpr.
+// The produced TemplateArgumentListInfo* points to data stored within this
+// object, so should only be used in contexts where the pointer will not be
+// used after the CopiedTemplateArgs object is destroyed.
+class CopiedTemplateArgs {
+ bool HasArgs;
+ TemplateArgumentListInfo TemplateArgStorage;
+public:
+ template<typename RefExpr>
+ CopiedTemplateArgs(RefExpr *E) : HasArgs(E->hasExplicitTemplateArgs()) {
+ if (HasArgs)
+ E->copyTemplateArgumentsInto(TemplateArgStorage);
+ }
+ operator TemplateArgumentListInfo*()
+#ifdef __has_cpp_attribute
+#if __has_cpp_attribute(clang::lifetimebound)
+ [[clang::lifetimebound]]
+#endif
+#endif
+ {
+ return HasArgs ? &TemplateArgStorage : nullptr;
+ }
+};
+}
+
/// Walk the set of potential results of an expression and mark them all as
/// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason.
///
@@ -15897,16 +15923,11 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// Rebuild as a non-odr-use DeclRefExpr.
MarkNotOdrUsed();
- TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
- if (DRE->hasExplicitTemplateArgs()) {
- DRE->copyTemplateArgumentsInto(TemplateArgStorage);
- TemplateArgs = &TemplateArgStorage;
- }
return DeclRefExpr::Create(
S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),
DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),
DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),
- DRE->getFoundDecl(), TemplateArgs, NOUR);
+ DRE->getFoundDecl(), CopiedTemplateArgs(DRE), NOUR);
}
case Expr::FunctionParmPackExprClass: {
@@ -15924,52 +15945,107 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
break;
}
- // FIXME: Implement these.
// -- If e is a subscripting operation with an array operand...
- // -- If e is a class member access expression [...] naming a non-static
- // data member...
+ case Expr::ArraySubscriptExprClass: {
+ auto *ASE = cast<ArraySubscriptExpr>(E);
+ Expr *OldBase = ASE->getBase()->IgnoreImplicit();
+ if (!OldBase->getType()->isArrayType())
+ break;
+ ExprResult Base = Rebuild(OldBase);
+ if (!Base.isUsable())
+ return Base;
+ Expr *LHS = ASE->getBase() == ASE->getLHS() ? Base.get() : ASE->getLHS();
+ Expr *RHS = ASE->getBase() == ASE->getRHS() ? Base.get() : ASE->getRHS();
+ SourceLocation LBracketLoc = ASE->getBeginLoc(); // FIXME: Not stored.
+ return S.ActOnArraySubscriptExpr(nullptr, LHS, LBracketLoc, RHS,
+ ASE->getRBracketLoc());
+ }
- // -- If e is a class member access expression naming a static data member,
- // ...
case Expr::MemberExprClass: {
auto *ME = cast<MemberExpr>(E);
+ // -- If e is a class member access expression [...] naming a non-static
+ // data member...
+ if (isa<FieldDecl>(ME->getMemberDecl())) {
+ ExprResult Base = Rebuild(ME->getBase());
+ if (!Base.isUsable())
+ return Base;
+ return MemberExpr::Create(
+ S.Context, Base.get(), ME->isArrow(), ME->getOperatorLoc(),
+ ME->getQualifierLoc(), ME->getTemplateKeywordLoc(),
+ ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(),
+ CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(),
+ ME->getObjectKind(), ME->isNonOdrUse());
+ }
+
if (ME->getMemberDecl()->isCXXInstanceMember())
- // FIXME: Recurse to the left-hand side.
break;
+ // -- If e is a class member access expression naming a static data member,
+ // ...
if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl()))
break;
// Rebuild as a non-odr-use MemberExpr.
MarkNotOdrUsed();
- TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
- if (ME->hasExplicitTemplateArgs()) {
- ME->copyTemplateArgumentsInto(TemplateArgStorage);
- TemplateArgs = &TemplateArgStorage;
- }
return MemberExpr::Create(
S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),
- ME->getFoundDecl(), ME->getMemberNameInfo(), TemplateArgs,
+ ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME),
ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);
return ExprEmpty();
}
- // FIXME: Implement this.
- // -- If e is a pointer-to-member expression of the form e1 .* e2 ...
+ case Expr::BinaryOperatorClass: {
+ auto *BO = cast<BinaryOperator>(E);
+ Expr *LHS = BO->getLHS();
+ Expr *RHS = BO->getRHS();
+ // -- If e is a pointer-to-member expression of the form e1 .* e2 ...
+ if (BO->getOpcode() == BO_PtrMemD) {
+ ExprResult Sub = Rebuild(LHS);
+ if (!Sub.isUsable())
+ return Sub;
+ LHS = Sub.get();
+ // -- If e is a comma expression, ...
+ } else if (BO->getOpcode() == BO_Comma) {
+ ExprResult Sub = Rebuild(RHS);
+ if (!Sub.isUsable())
+ return Sub;
+ RHS = Sub.get();
+ } else {
+ break;
+ }
+ return S.BuildBinOp(nullptr, BO->getOperatorLoc(), BO->getOpcode(),
+ LHS, RHS);
+ }
// -- If e has the form (e1)...
case Expr::ParenExprClass: {
- auto *PE = dyn_cast<ParenExpr>(E);
+ auto *PE = cast<ParenExpr>(E);
ExprResult Sub = Rebuild(PE->getSubExpr());
if (!Sub.isUsable())
return Sub;
return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get());
}
- // FIXME: Implement these.
// -- If e is a glvalue conditional expression, ...
- // -- If e is a comma expression, ...
+ // We don't apply this to a binary conditional operator. FIXME: Should we?
+ case Expr::ConditionalOperatorClass: {
+ auto *CO = cast<ConditionalOperator>(E);
+ ExprResult LHS = Rebuild(CO->getLHS());
+ if (LHS.isInvalid())
+ return ExprError();
+ ExprResult RHS = Rebuild(CO->getRHS());
+ if (RHS.isInvalid())
+ return ExprError();
+ if (!LHS.isUsable() && !RHS.isUsable())
+ return ExprEmpty();
+ if (!LHS.isUsable())
+ LHS = CO->getLHS();
+ if (!RHS.isUsable())
+ RHS = CO->getRHS();
+ return S.ActOnConditionalOp(CO->getQuestionLoc(), CO->getColonLoc(),
+ CO->getCond(), LHS.get(), RHS.get());
+ }
// [Clang extension]
// -- If e has the form __extension__ e1...
@@ -15988,7 +16064,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// -- If e has the form _Generic(...), the set of potential results is the
// union of the sets of potential results of the associated expressions.
case Expr::GenericSelectionExprClass: {
- auto *GSE = dyn_cast<GenericSelectionExpr>(E);
+ auto *GSE = cast<GenericSelectionExpr>(E);
SmallVector<Expr *, 4> AssocExprs;
bool AnyChanged = false;
@@ -16016,7 +16092,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// results is the union of the sets of potential results of the
// second and third subexpressions.
case Expr::ChooseExprClass: {
- auto *CE = dyn_cast<ChooseExpr>(E);
+ auto *CE = cast<ChooseExpr>(E);
ExprResult LHS = Rebuild(CE->getLHS());
if (LHS.isInvalid())
@@ -16039,13 +16115,38 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// Step through non-syntactic nodes.
case Expr::ConstantExprClass: {
- auto *CE = dyn_cast<ConstantExpr>(E);
+ auto *CE = cast<ConstantExpr>(E);
ExprResult Sub = Rebuild(CE->getSubExpr());
if (!Sub.isUsable())
return Sub;
return ConstantExpr::Create(S.Context, Sub.get());
}
+ // We could mostly rely on the recursive rebuilding to rebuild implicit
+ // casts, but not at the top level, so rebuild them here.
+ case Expr::ImplicitCastExprClass: {
+ auto *ICE = cast<ImplicitCastExpr>(E);
+ // Only step through the narrow set of cast kinds we expect to encounter.
+ // Anything else suggests we've left the region in which potential results
+ // can be found.
+ switch (ICE->getCastKind()) {
+ case CK_NoOp:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ ExprResult Sub = Rebuild(ICE->getSubExpr());
+ if (!Sub.isUsable())
+ return Sub;
+ CXXCastPath Path(ICE->path());
+ return S.ImpCastExprToType(Sub.get(), ICE->getType(), ICE->getCastKind(),
+ ICE->getValueKind(), &Path);
+ }
+
+ default:
+ break;
+ }
+ break;
+ }
+
default:
break;
}
OpenPOWER on IntegriCloud