diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14605,7 +14605,8 @@ UnaryOperatorKind Opc = UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); - return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, First); + // Invoke BuildUnaryOp to check for PseudoObject inc/dec + return getSema().BuildUnaryOp(/*Scope=*/nullptr, OpLoc, Opc, First); } } else { if (!First->getType()->isOverloadableType() && @@ -14613,8 +14614,9 @@ // Neither of the arguments is an overloadable type, so try to // create a built-in binary operation. BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); - ExprResult Result - = SemaRef.CreateBuiltinBinOp(OpLoc, Opc, First, Second); + // Invoke BuildBinOp to check for PseudoObject assignment + ExprResult Result = + SemaRef.BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, First, Second); if (Result.isInvalid()) return ExprError(); diff --git a/clang/test/SemaCXX/PR51855.cpp b/clang/test/SemaCXX/PR51855.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/PR51855.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -S -triple %itanium_abi_triple -fms-extensions -emit-llvm %s -o - | FileCheck %s + +struct F {}; + +F operator*=(F &lhs, int rhs); + +F operator++(F &lhs); + +struct S { + short _m; + S(short _m) : _m(_m) {} + + void putM(short rhs) { _m = rhs; } + short getM() { return _m; } + + __declspec(property(get = getM, put = putM)) short theData; +}; + +int test1a(int i) { + S tmp(i); + tmp.theData *= 2; + return tmp.theData; +} + +// CHECK-LABEL: define {{.*}} i32 @_Z6test1ai(i32 %i) +// CHECK: call void @_ZN1SC1Es +// CHECK: call signext i16 @_ZN1S4getMEv +// CHECK: call void @_ZN1S4putMEs +// CHECK: call signext i16 @_ZN1S4getMEv + +template +int test1b(int i) { + T tmp(i); + tmp.theData *= 2; + return tmp.theData; +} + +template int test1b(int); + +// CHECK-LABEL: define {{.*}} i32 @_Z6test1bI1SEii(i32 %i) +// CHECK: call void @_ZN1SC1Es +// CHECK: call signext i16 @_ZN1S4getMEv +// CHECK: call void @_ZN1S4putMEs +// CHECK: call signext i16 @_ZN1S4getMEv + +int test2a(int i) { + S tmp(i); + ++tmp.theData; + return tmp.theData; +} + +// CHECK-LABEL: define {{.*}} i32 @_Z6test2ai(i32 %i) +// CHECK: call void @_ZN1SC1Es +// CHECK: call signext i16 @_ZN1S4getMEv +// CHECK: call void @_ZN1S4putMEs +// CHECK: call signext i16 @_ZN1S4getMEv + +template +int test2b(int i) { + T tmp(i); + ++tmp.theData; + return tmp.theData; +} + +template int test2b(int); + +// CHECK-LABEL: define {{.*}} i32 @_Z6test2bI1SEii(i32 %i) +// CHECK: call void @_ZN1SC1Es +// CHECK: call signext i16 @_ZN1S4getMEv +// CHECK: call void @_ZN1S4putMEs +// CHECK: call signext i16 @_ZN1S4getMEv