@@ -1003,15 +1003,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
10031003 : !isDependentScopeSpecifier (SS) || computeDeclContext (SS)) &&
10041004 " dependent lookup context that isn't the current instantiation?" );
10051005
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-
10151006 const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo ();
10161007 DeclarationName MemberName = MemberNameInfo.getName ();
10171008 SourceLocation MemberLoc = MemberNameInfo.getLoc ();
@@ -1128,26 +1119,68 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11281119 BaseExpr = BuildCXXThisExpr (Loc, BaseExprType, /* IsImplicit=*/ true );
11291120 }
11301121
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+
11311149 // Check the use of this member.
11321150 if (DiagnoseUseOfDecl (MemberDecl, MemberLoc))
11331151 return ExprError ();
11341152
1135- if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
1153+ if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
1154+ if (ConvertBaseExprToGLValue ())
1155+ return ExprError ();
11361156 return BuildFieldReferenceExpr (BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
11371157 MemberNameInfo);
1158+ }
11381159
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.
11401166 return BuildMSPropertyRefExpr (*this , BaseExpr, IsArrow, SS, PD,
11411167 MemberNameInfo);
1168+ }
11421169
1143- if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl))
1170+ if (IndirectFieldDecl *FD = dyn_cast<IndirectFieldDecl>(MemberDecl)) {
1171+ if (ConvertBaseExprToGLValue ())
1172+ return ExprError ();
11441173 // We may have found a field within an anonymous union or struct
11451174 // (C++ [class.union]).
11461175 return BuildAnonymousStructUnionMemberReference (SS, MemberLoc, FD,
11471176 FoundDecl, BaseExpr,
11481177 OpLoc);
1178+ }
11491179
1180+ // Static data member
11501181 if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
1182+ if (ConvertBaseExprToDiscardedValue ())
1183+ return ExprError ();
11511184 return BuildMemberExpr (BaseExpr, IsArrow, OpLoc,
11521185 SS.getWithLocInContext (Context), TemplateKWLoc, Var,
11531186 FoundDecl, /* HadMultipleCandidates=*/ false ,
@@ -1161,7 +1194,13 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11611194 if (MemberFn->isInstance ()) {
11621195 valueKind = VK_PRValue;
11631196 type = Context.BoundMemberTy ;
1197+ if (MemberFn->isImplicitObjectMemberFunction () &&
1198+ ConvertBaseExprToGLValue ())
1199+ return ExprError ();
11641200 } else {
1201+ // Static member function
1202+ if (ConvertBaseExprToDiscardedValue ())
1203+ return ExprError ();
11651204 valueKind = VK_LValue;
11661205 type = MemberFn->getType ();
11671206 }
@@ -1174,13 +1213,17 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11741213 assert (!isa<FunctionDecl>(MemberDecl) && " member function not C++ method?" );
11751214
11761215 if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
1216+ if (ConvertBaseExprToDiscardedValue ())
1217+ return ExprError ();
11771218 return BuildMemberExpr (
11781219 BaseExpr, IsArrow, OpLoc, SS.getWithLocInContext (Context),
11791220 TemplateKWLoc, Enum, FoundDecl, /* HadMultipleCandidates=*/ false ,
11801221 MemberNameInfo, Enum->getType (), VK_PRValue, OK_Ordinary);
11811222 }
11821223
11831224 if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
1225+ if (ConvertBaseExprToDiscardedValue ())
1226+ return ExprError ();
11841227 if (!TemplateArgs) {
11851228 diagnoseMissingTemplateArguments (
11861229 SS, /* TemplateKeyword=*/ TemplateKWLoc.isValid (), VarTempl, MemberLoc);
0 commit comments