@@ -1003,15 +1003,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
1003
1003
: !isDependentScopeSpecifier (SS) || computeDeclContext (SS)) &&
1004
1004
" dependent lookup context that isn't the current instantiation?" );
1005
1005
1006
- // C++1z [expr.ref]p2:
1007
- // For the first option (dot) the first expression shall be a glvalue [...]
1008
- if (!IsArrow && BaseExpr && BaseExpr->isPRValue ()) {
1009
- ExprResult Converted = TemporaryMaterializationConversion (BaseExpr);
1010
- if (Converted.isInvalid ())
1011
- return ExprError ();
1012
- BaseExpr = Converted.get ();
1013
- }
1014
-
1015
1006
const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo ();
1016
1007
DeclarationName MemberName = MemberNameInfo.getName ();
1017
1008
SourceLocation MemberLoc = MemberNameInfo.getLoc ();
@@ -1128,26 +1119,68 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
1128
1119
BaseExpr = BuildCXXThisExpr (Loc, BaseExprType, /* IsImplicit=*/ true );
1129
1120
}
1130
1121
1122
+ // C++17 [expr.ref]p2, per CWG2813:
1123
+ // For the first option (dot), if the id-expression names a static member or
1124
+ // an enumerator, the first expression is a discarded-value expression; if
1125
+ // the id-expression names a non-static data member, the first expression
1126
+ // shall be a glvalue.
1127
+ auto ConvertBaseExprToDiscardedValue = [&] {
1128
+ assert (getLangOpts ().CPlusPlus &&
1129
+ " Static member / member enumerator outside of C++" );
1130
+ if (IsArrow)
1131
+ return false ;
1132
+ ExprResult Converted = IgnoredValueConversions (BaseExpr);
1133
+ if (Converted.isInvalid ())
1134
+ return true ;
1135
+ BaseExpr = Converted.get ();
1136
+ DiagnoseDiscardedExprMarkedNodiscard (BaseExpr);
1137
+ return false ;
1138
+ };
1139
+ auto ConvertBaseExprToGLValue = [&] {
1140
+ if (IsArrow || !BaseExpr->isPRValue ())
1141
+ return false ;
1142
+ ExprResult Converted = TemporaryMaterializationConversion (BaseExpr);
1143
+ if (Converted.isInvalid ())
1144
+ return true ;
1145
+ BaseExpr = Converted.get ();
1146
+ return false ;
1147
+ };
1148
+
1131
1149
// Check the use of this member.
1132
1150
if (DiagnoseUseOfDecl (MemberDecl, MemberLoc))
1133
1151
return ExprError ();
1134
1152
1135
- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
1153
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
1154
+ if (ConvertBaseExprToGLValue ())
1155
+ return ExprError ();
1136
1156
return BuildFieldReferenceExpr (BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
1137
1157
MemberNameInfo);
1158
+ }
1138
1159
1139
- if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
1160
+ if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) {
1161
+ // No temporaries are materialized for property references yet.
1162
+ // They might be materialized when this is transformed into a member call.
1163
+ // Note that this is slightly different behaviour from MSVC which doesn't
1164
+ // implement CWG2813 yet: MSVC might materialize an extra temporary if the
1165
+ // getter or setter function is an explicit object member function.
1140
1166
return BuildMSPropertyRefExpr (*this , BaseExpr, IsArrow, SS, PD,
1141
1167
MemberNameInfo);
1168
+ }
1142
1169
1143
- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
1170
+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) {
1171
+ if (ConvertBaseExprToGLValue ())
1172
+ return ExprError ();
1144
1173
// We may have found a field within an anonymous union or struct
1145
1174
// (C++ [class.union]).
1146
1175
return BuildAnonymousStructUnionMemberReference (SS, MemberLoc, FD,
1147
1176
FoundDecl, BaseExpr,
1148
1177
OpLoc);
1178
+ }
1149
1179
1180
+ // Static data member
1150
1181
if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
1182
+ if (ConvertBaseExprToDiscardedValue ())
1183
+ return ExprError ();
1151
1184
return BuildMemberExpr (BaseExpr, IsArrow, OpLoc,
1152
1185
SS.getWithLocInContext (Context), TemplateKWLoc, Var,
1153
1186
FoundDecl, /* HadMultipleCandidates=*/ false ,
@@ -1161,7 +1194,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
1161
1194
if (MemberFn->isInstance ()) {
1162
1195
valueKind = VK_PRValue;
1163
1196
type = Context.BoundMemberTy ;
1197
+ if (MemberFn->isImplicitObjectMemberFunction () &&
1198
+ ConvertBaseExprToGLValue ())
1199
+ return ExprError ();
1164
1200
} else {
1201
+ // Static member function
1202
+ if (ConvertBaseExprToDiscardedValue ())
1203
+ return ExprError ();
1165
1204
valueKind = VK_LValue;
1166
1205
type = MemberFn->getType ();
1167
1206
}
@@ -1174,13 +1213,17 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
1174
1213
assert (!isa<FunctionDecl>(MemberDecl) && " member function not C++ method?" );
1175
1214
1176
1215
if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
1216
+ if (ConvertBaseExprToDiscardedValue ())
1217
+ return ExprError ();
1177
1218
return BuildMemberExpr (
1178
1219
BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext (Context),
1179
1220
TemplateKWLoc, Enum, FoundDecl, /* HadMultipleCandidates=*/ false ,
1180
1221
MemberNameInfo, Enum->getType (), VK_PRValue, OK_Ordinary);
1181
1222
}
1182
1223
1183
1224
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
1225
+ if (ConvertBaseExprToDiscardedValue ())
1226
+ return ExprError ();
1184
1227
if (!TemplateArgs) {
1185
1228
diagnoseMissingTemplateArguments (
1186
1229
SS, /* TemplateKeyword=*/ TemplateKWLoc.isValid (), VarTempl, MemberLoc);
0 commit comments