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 @@ -14630,18 +14630,37 @@ Expr *Callee = OrigCallee->IgnoreParenCasts(); bool isPostIncDec = Second && (Op == OO_PlusPlus || Op == OO_MinusMinus); - if (First->getObjectKind() == OK_ObjCProperty) { - BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); - if (BinaryOperator::isAssignmentOp(Opc)) - return SemaRef.checkPseudoObjectAssignment(/*Scope=*/nullptr, OpLoc, Opc, - First, Second); + if (const BuiltinType *pty = First->getType()->getAsPlaceholderType()) { + if (Second && !isPostIncDec) { + BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(Op); + if (pty->getKind() == BuiltinType::PseudoObject && + BinaryOperator::isAssignmentOp(Opc)) + return SemaRef.checkPseudoObjectAssignment(/*Scope=*/nullptr, OpLoc, + Opc, First, Second); + } else { + UnaryOperatorKind Opc = + UnaryOperator::getOverloadedOpcode(Op, isPostIncDec); + if (pty->getKind() == BuiltinType::PseudoObject && + UnaryOperator::isIncrementDecrementOp(Opc)) + return SemaRef.checkPseudoObjectIncDec(/*Scope=*/nullptr, OpLoc, Opc, + First); + + // & gets special logic for several kinds of placeholder, which may + // only appear after resolving a DependentScopeDeclRef, copying from + // Sema::BuildUnaryOp + if (Opc == UO_AddrOf && (pty->getKind() == BuiltinType::Overload || + pty->getKind() == BuiltinType::UnknownAny || + pty->getKind() == BuiltinType::BoundMember)) + return getSema().CreateBuiltinUnaryOp(OpLoc, Opc, First); + } + ExprResult Result = SemaRef.CheckPlaceholderExpr(First); if (Result.isInvalid()) return ExprError(); First = Result.get(); } - if (Second && Second->getObjectKind() == OK_ObjCProperty) { + if (Second && Second->getType()->isPlaceholderType()) { ExprResult Result = SemaRef.CheckPlaceholderExpr(Second); if (Result.isInvalid()) return ExprError(); diff --git a/clang/test/SemaCXX/D111639.cpp b/clang/test/SemaCXX/D111639.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/D111639.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +// Test case for an issue that appeared while developing D111639: +// +// An earlier version of the diff unexpectedly caused compilation of +// llvm/Support/AllocatorBase.h and llvm/Support/Allocator.h to fail in +// multistage buildbots. This is a reduced version of the construct that +// caused the problem. + +using size_t = __SIZE_TYPE__; + +struct X { + int i; +}; + +X operator&(X, X); // binary operator& needed to fill (non-member) overload set of unary operator& + +template +class Base { +public: + void *Alloc(size_t Size) { + static_assert( + static_cast(&Base::Alloc) != static_cast(&Derived::Alloc), + "must override"); + return static_cast(this)->Alloc(Size); + } + template + T *Alloc() { + return static_cast(Alloc(sizeof(T))); + } +}; + +class Sub : public Base { +public: + void *Alloc(int); + void *Alloc(size_t Size) { + return Alloc((int)Size); + } + using Base::Alloc; +}; + +Sub s; + +void *test() { + return s.Alloc((size_t)123); +} + +char *test2() { + return s.Alloc(); +} 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 {{.*}} @_Z6test1ai( +// CHECK: call {{.*}} @_ZN1SC1Es( +// CHECK: call {{.*}} @_ZN1S4getMEv( +// CHECK: call {{.*}} @_ZN1S4putMEs( +// CHECK: call {{.*}} @_ZN1S4getMEv( + +template +int test1b(int i) { + T tmp(i); + tmp.theData *= 2; + return tmp.theData; +} + +template int test1b(int); + +// CHECK-LABEL: define {{.*}} @_Z6test1bI1SEii( +// CHECK: call {{.*}} @_ZN1SC1Es( +// CHECK: call {{.*}} @_ZN1S4getMEv( +// CHECK: call {{.*}} @_ZN1S4putMEs( +// CHECK: call {{.*}} @_ZN1S4getMEv( + +int test2a(int i) { + S tmp(i); + ++tmp.theData; + return tmp.theData; +} + +// CHECK-LABEL: define {{.*}} i32 @_Z6test2ai( +// CHECK: call {{.*}} @_ZN1SC1Es( +// CHECK: call {{.*}} @_ZN1S4getMEv( +// CHECK: call {{.*}} @_ZN1S4putMEs( +// CHECK: call {{.*}} @_ZN1S4getMEv( + +template +int test2b(int i) { + T tmp(i); + ++tmp.theData; + return tmp.theData; +} + +template int test2b(int); + +// CHECK-LABEL: define {{.*}} i32 @_Z6test2bI1SEii( +// CHECK: call {{.*}} @_ZN1SC1Es( +// CHECK: call {{.*}} @_ZN1S4getMEv( +// CHECK: call {{.*}} @_ZN1S4putMEs( +// CHECK: call {{.*}} @_ZN1S4getMEv( diff --git a/clang/test/SemaObjCXX/instantiate-property-access.mm b/clang/test/SemaObjCXX/instantiate-property-access.mm --- a/clang/test/SemaObjCXX/instantiate-property-access.mm +++ b/clang/test/SemaObjCXX/instantiate-property-access.mm @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -DDEPENDENT -verify %s // expected-no-diagnostics class C {}; @@ -9,6 +10,10 @@ C operator += (C c1, C c2); +C operator++(C c1); + +bool operator!(C c1); + enum TextureType { TextureType3D }; @interface Texture @@ -16,9 +21,13 @@ @property C c; @end -template class Framebuffer { +template class Framebuffer { public: - Texture **color_attachment; +#ifdef DEPENDENT + T **color_attachment; +#else + Texture **color_attachment; +#endif Framebuffer(); }; @@ -28,8 +37,15 @@ (void)(color_attachment[0].c == color_attachment[0].c); (void)(color_attachment[0].c == 1); (void)(1 == color_attachment[0].c); + (void)(!color_attachment[0].textureType); + ++color_attachment[0].textureType; + (void)(!color_attachment[0].c); } void foo() { +#ifdef DEPENDENT + Framebuffer(); +#else Framebuffer(); +#endif }