aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema/SemaExprMember.cpp
diff options
context:
space:
mode:
authorcor3ntin <corentinjabot@gmail.com>2024-12-18 10:44:42 +0100
committerGitHub <noreply@github.com>2024-12-18 10:44:42 +0100
commitdb93ef14aef9c572e02bc842762bc4d0278148f9 (patch)
tree079fa17b0bc8869f1e0613d179dbbef94e58edd7 /clang/lib/Sema/SemaExprMember.cpp
parent66bdbfbaa08fa3d8e64a7fe136a8fb717f5cdbb7 (diff)
downloadllvm-db93ef14aef9c572e02bc842762bc4d0278148f9.zip
llvm-db93ef14aef9c572e02bc842762bc4d0278148f9.tar.gz
llvm-db93ef14aef9c572e02bc842762bc4d0278148f9.tar.bz2
[Clang] Implement CWG2813: Class member access with prvalues (#120223)
This is a rebase of #95112 with my own feedback apply as @MitalAshok has been inactive for a while. It's fairly important this makes clang 20 as it is a blocker for #107451 --- [CWG2813](https://cplusplus.github.io/CWG/issues/2813.html) prvalue.member_fn(expression-list) now will not materialize a temporary for prvalue if member_fn is an explicit object member function, and prvalue will bind directly to the object parameter. The E1 in E1.static_member is now a discarded-value expression, so if E1 was a call to a [[nodiscard]] function, there will now be a warning. This also affects C++98 with [[gnu::warn_unused_result]] functions. This should not affect C where TemporaryMaterializationConversion is a no-op. Closes #100314 Fixes #100341 --------- Co-authored-by: Mital Ashok <mital@mitalashok.co.uk>
Diffstat (limited to 'clang/lib/Sema/SemaExprMember.cpp')
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp67
1 files changed, 55 insertions, 12 deletions
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 85d5dfcb..bcc1b92 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1003,15 +1003,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
: !isDependentScopeSpecifier(SS) || computeDeclContext(SS)) &&
"dependent lookup context that isn't the current instantiation?");
- // C++1z [expr.ref]p2:
- // For the first option (dot) the first expression shall be a glvalue [...]
- if (!IsArrow && BaseExpr && BaseExpr->isPRValue()) {
- ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
- if (Converted.isInvalid())
- return ExprError();
- BaseExpr = Converted.get();
- }
-
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo();
DeclarationName MemberName = MemberNameInfo.getName();
SourceLocation MemberLoc = MemberNameInfo.getLoc();
@@ -1128,26 +1119,68 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
BaseExpr = BuildCXXThisExpr(Loc, BaseExprType, /*IsImplicit=*/true);
}
+ // C++17 [expr.ref]p2, per CWG2813:
+ // For the first option (dot), if the id-expression names a static member or
+ // an enumerator, the first expression is a discarded-value expression; if
+ // the id-expression names a non-static data member, the first expression
+ // shall be a glvalue.
+ auto ConvertBaseExprToDiscardedValue = [&] {
+ assert(getLangOpts().CPlusPlus &&
+ "Static member / member enumerator outside of C++");
+ if (IsArrow)
+ return false;
+ ExprResult Converted = IgnoredValueConversions(BaseExpr);
+ if (Converted.isInvalid())
+ return true;
+ BaseExpr = Converted.get();
+ DiagnoseDiscardedExprMarkedNodiscard(BaseExpr);
+ return false;
+ };
+ auto ConvertBaseExprToGLValue = [&] {
+ if (IsArrow || !BaseExpr->isPRValue())
+ return false;
+ ExprResult Converted = TemporaryMaterializationConversion(BaseExpr);
+ if (Converted.isInvalid())
+ return true;
+ BaseExpr = Converted.get();
+ return false;
+ };
+
// Check the use of this member.
if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
return ExprError();
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
+ if (ConvertBaseExprToGLValue())
+ return ExprError();
return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
MemberNameInfo);
+ }
- if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
+ if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) {
+ // No temporaries are materialized for property references yet.
+ // They might be materialized when this is transformed into a member call.
+ // Note that this is slightly different behaviour from MSVC which doesn't
+ // implement CWG2813 yet: MSVC might materialize an extra temporary if the
+ // getter or setter function is an explicit object member function.
return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
MemberNameInfo);
+ }
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) {
+ if (ConvertBaseExprToGLValue())
+ return ExprError();
// We may have found a field within an anonymous union or struct
// (C++ [class.union]).
return BuildAnonymousStructUnionMemberReference(SS, MemberLoc, FD,
FoundDecl, BaseExpr,
OpLoc);
+ }
+ // Static data member
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+ if (ConvertBaseExprToDiscardedValue())
+ return ExprError();
return BuildMemberExpr(BaseExpr, IsArrow, OpLoc,
SS.getWithLocInContext(Context), TemplateKWLoc, Var,
FoundDecl, /*HadMultipleCandidates=*/false,
@@ -1161,7 +1194,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
if (MemberFn->isInstance()) {
valueKind = VK_PRValue;
type = Context.BoundMemberTy;
+ if (MemberFn->isImplicitObjectMemberFunction() &&
+ ConvertBaseExprToGLValue())
+ return ExprError();
} else {
+ // Static member function
+ if (ConvertBaseExprToDiscardedValue())
+ return ExprError();
valueKind = VK_LValue;
type = MemberFn->getType();
}
@@ -1174,6 +1213,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?");
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+ if (ConvertBaseExprToDiscardedValue())
+ return ExprError();
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext(Context),
TemplateKWLoc, Enum, FoundDecl, /*HadMultipleCandidates=*/false,
@@ -1181,6 +1222,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
+ if (ConvertBaseExprToDiscardedValue())
+ return ExprError();
if (!TemplateArgs) {
diagnoseMissingTemplateArguments(
SS, /*TemplateKeyword=*/TemplateKWLoc.isValid(), VarTempl, MemberLoc);