Skip to content

Commit af0ee61

Browse files
Sirraideerichkeane
andauthored
[Clang] Support MSPropertyRefExpr as placement arg to new-expression (#75883)
It seems we were forgetting to call `checkArgsForPlaceholders` on the placement arguments of new-expressions in Sema. I don't think that was intended—at least doing so doesn't seem to break anything—so this pr adds that. This also fixes #65053 --------- Co-authored-by: Erich Keane <[email protected]>
1 parent 04a69a1 commit af0ee61

14 files changed

+375
-42
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,30 @@ Improvements to Clang's diagnostics
572572
enclosing template must be a definition.
573573
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
574574

575+
- Clang now emits more descriptive diagnostics for 'unusual' expressions (e.g. incomplete index
576+
expressions on matrix types or builtin functions without an argument list) as placement-args
577+
to new-expressions.
578+
579+
Before:
580+
581+
.. code-block:: text
582+
583+
error: no matching function for call to 'operator new'
584+
13 | new (__builtin_memset) S {};
585+
| ^ ~~~~~~~~~~~~~~~~~~
586+
587+
note: candidate function not viable: no known conversion from '<builtin fn type>' to 'int' for 2nd argument
588+
5 | void* operator new(__SIZE_TYPE__, int);
589+
| ^
590+
591+
After:
592+
593+
.. code-block:: text
594+
595+
error: builtin functions must be directly called
596+
13 | new (__builtin_memset) S {};
597+
| ^
598+
575599
576600
Improvements to Clang's time-trace
577601
----------------------------------
@@ -774,6 +798,12 @@ Bug Fixes in This Version
774798
- Fix assertion failure when call noreturn-attribute function with musttail
775799
attribute.
776800
Fixes (`#76631 <https://github.com/llvm/llvm-project/issues/76631>`_)
801+
- The MS ``__noop`` builtin without an argument list is now accepted
802+
in the placement-args of new-expressions, matching MSVC's behaviour.
803+
- Fix an issue that caused MS ``__decspec(property)`` accesses as well as
804+
Objective-C++ property accesses to not be converted to a function call
805+
to the getter in the placement-args of new-expressions.
806+
Fixes (`#65053 <https://github.com/llvm/llvm-project/issues/65053>`_)
777807

778808
Bug Fixes to Compiler Builtins
779809
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,10 @@ class Sema final {
21122112

21132113
bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
21142114

2115+
/// Check an argument list for placeholders that we won't try to
2116+
/// handle later.
2117+
bool CheckArgsForPlaceholders(MultiExprArg args);
2118+
21152119
/// Build a function type.
21162120
///
21172121
/// This routine checks the function type according to C++ rules and

clang/lib/Sema/SemaExpr.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5058,8 +5058,6 @@ static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
50585058
return Result->isDependentType() ? Result : Ctx.DependentTy;
50595059
}
50605060

5061-
static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args);
5062-
50635061
ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
50645062
SourceLocation lbLoc,
50655063
MultiExprArg ArgExprs,
@@ -5163,7 +5161,7 @@ ExprResult Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base,
51635161
return ExprError();
51645162
ArgExprs[0] = result.get();
51655163
} else {
5166-
if (checkArgsForPlaceholders(*this, ArgExprs))
5164+
if (CheckArgsForPlaceholders(ArgExprs))
51675165
return ExprError();
51685166
}
51695167

@@ -6912,15 +6910,13 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
69126910
llvm_unreachable("bad builtin type kind");
69136911
}
69146912

6915-
/// Check an argument list for placeholders that we won't try to
6916-
/// handle later.
6917-
static bool checkArgsForPlaceholders(Sema &S, MultiExprArg args) {
6913+
bool Sema::CheckArgsForPlaceholders(MultiExprArg args) {
69186914
// Apply this processing to all the arguments at once instead of
69196915
// dying at the first failure.
69206916
bool hasInvalid = false;
69216917
for (size_t i = 0, e = args.size(); i != e; i++) {
69226918
if (isPlaceholderToRemoveAsArg(args[i]->getType())) {
6923-
ExprResult result = S.CheckPlaceholderExpr(args[i]);
6919+
ExprResult result = CheckPlaceholderExpr(args[i]);
69246920
if (result.isInvalid()) hasInvalid = true;
69256921
else args[i] = result.get();
69266922
}
@@ -7194,7 +7190,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
71947190
if (Result.isInvalid()) return ExprError();
71957191
Fn = Result.get();
71967192

7197-
if (checkArgsForPlaceholders(*this, ArgExprs))
7193+
if (CheckArgsForPlaceholders(ArgExprs))
71987194
return ExprError();
71997195

72007196
if (getLangOpts().CPlusPlus) {

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,6 +2286,9 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
22862286
bool PassAlignment = getLangOpts().AlignedAllocation &&
22872287
Alignment > NewAlignment;
22882288

2289+
if (CheckArgsForPlaceholders(PlacementArgs))
2290+
return ExprError();
2291+
22892292
AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
22902293
if (!AllocType->isDependentType() &&
22912294
!Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s
2+
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s
3+
// RUN: %clang_cc1 -emit-llvm -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -o - | FileCheck %s
4+
// expected-no-diagnostics
5+
6+
#ifndef HEADER
7+
#define HEADER
8+
9+
struct S {
10+
int GetX() { return 42; }
11+
__declspec(property(get=GetX)) int x;
12+
13+
int GetY(int i, int j) { return i+j; }
14+
__declspec(property(get=GetY)) int y[];
15+
16+
void* operator new(__SIZE_TYPE__, int);
17+
};
18+
19+
template <typename T>
20+
struct TS {
21+
T GetT() { return T(); }
22+
__declspec(property(get=GetT)) T t;
23+
24+
T GetR(T i, T j) { return i+j; }
25+
__declspec(property(get=GetR)) T r[];
26+
};
27+
28+
// CHECK-LABEL: main
29+
int main(int argc, char **argv) {
30+
S *s;
31+
TS<double> *ts;
32+
33+
// CHECK: [[X:%.+]] = call noundef i32 @"?GetX@S@@QEAAHXZ"(ptr {{[^,]*}} %{{.+}})
34+
// CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH@Z"(i64 noundef 1, i32 noundef [[X]])
35+
new (s->x) S;
36+
37+
// CHECK: [[Y:%.+]] = call noundef i32 @"?GetY@S@@QEAAHHH@Z"(ptr {{[^,]*}} %{{.+}}, i32 noundef 1, i32 noundef 2)
38+
// CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH@Z"(i64 noundef 1, i32 noundef [[Y]])
39+
new ((s->y)[1][2]) S;
40+
41+
// CHECK: [[T:%.+]] = call noundef double @"?GetT@?$TS@N@@QEAANXZ"(ptr {{[^,]*}} %{{.+}})
42+
// CHECK-NEXT: [[TI:%.+]] = fptosi double [[T]] to i32
43+
// CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH@Z"(i64 noundef 1, i32 noundef [[TI]])
44+
new (ts->t) S;
45+
46+
// CHECK: [[R:%.+]] = call noundef double @"?GetR@?$TS@N@@QEAANNN@Z"(ptr {{[^,]*}} %{{.+}}, double {{[^,]*}}, double {{[^,]*}})
47+
// CHECK-NEXT: [[RI:%.+]] = fptosi double [[R]] to i32
48+
// CHECK-NEXT: call noundef ptr @"??2S@@SAPEAX_KH@Z"(i64 noundef 1, i32 noundef [[RI]])
49+
new ((ts->r)[1][2]) S;
50+
}
51+
52+
#endif
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -std=c++11 -emit-llvm -o - %s | FileCheck %s
2+
3+
struct S {
4+
void* operator new(__SIZE_TYPE__, int);
5+
};
6+
7+
int main() {
8+
// CHECK: call {{.*}} ptr @"??2S@@SAPEAX_KH@Z"(i64 {{.*}} 1, i32 {{.*}} 0)
9+
// CHECK: call {{.*}} ptr @"??2S@@SAPEAX_KH@Z"(i64 {{.*}} 1, i32 {{.*}} 0)
10+
new (__noop) S;
11+
new ((__noop)) S;
12+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %clang_cc1 -x objective-c++ -std=c++11 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
2+
3+
// CHECK: [[NAME:@.*]] = private unnamed_addr constant [9 x i8] c"position\00"
4+
// CHECK: [[SEL:@.*]] = internal externally_initialized global ptr [[NAME]]
5+
6+
@interface I {
7+
int position;
8+
}
9+
@property(nonatomic) int position;
10+
@end
11+
12+
struct S {
13+
void *operator new(__SIZE_TYPE__, int);
14+
};
15+
16+
template <typename T>
17+
struct TS {
18+
void *operator new(__SIZE_TYPE__, T);
19+
};
20+
21+
I *GetI();
22+
23+
int main() {
24+
@autoreleasepool {
25+
// CHECK: [[I:%.+]] = alloca ptr
26+
auto* i = GetI();
27+
i.position = 42;
28+
29+
// This is so we can find the next line more easily.
30+
// CHECK: store double
31+
double d = 42.0;
32+
33+
// CHECK: [[I1:%.+]] = load ptr, ptr [[I]]
34+
// CHECK-NEXT: [[SEL1:%.+]] = load ptr, ptr [[SEL]]
35+
// CHECK-NEXT: [[POS1:%.+]] = call {{.*}} i32 @objc_msgSend(ptr {{.*}} [[I1]], ptr {{.*}} [[SEL1]])
36+
// CHECK-NEXT: call {{.*}} ptr @_ZN1SnwEmi(i64 {{.*}} 1, i32 {{.*}} [[POS1]])
37+
new (i.position) S;
38+
39+
// CHECK: [[I2:%.+]] = load ptr, ptr [[I]]
40+
// CHECK-NEXT: [[SEL2:%.+]] = load ptr, ptr [[SEL]]
41+
// CHECK-NEXT: [[POS2:%.+]] = call {{.*}} i32 @objc_msgSend(ptr {{.*}} [[I2]], ptr {{.*}} [[SEL2]])
42+
// CHECK-NEXT: [[DBL:%.+]] = sitofp i32 [[POS2]] to double
43+
// CHECK-NEXT: call {{.*}} ptr @_ZN2TSIdEnwEmd(i64 {{.*}} 1, double {{.*}} [[DBL]])
44+
new (i.position) TS<double>;
45+
}
46+
}

clang/test/SemaCXX/builtin-std-move.cpp

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -std=c++17 -verify %s
2-
// RUN: %clang_cc1 -std=c++17 -verify %s -DNO_CONSTEXPR
3-
// RUN: %clang_cc1 -std=c++20 -verify %s
1+
// RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s
2+
// RUN: %clang_cc1 -std=c++17 -verify=cxx17,expected %s -DNO_CONSTEXPR
3+
// RUN: %clang_cc1 -std=c++20 -verify=cxx20,expected %s
44

55
namespace std {
66
#ifndef NO_CONSTEXPR
@@ -12,6 +12,7 @@ namespace std {
1212
template<typename T> CONSTEXPR T &&move(T &x) {
1313
static_assert(T::moveable, "instantiated move"); // expected-error {{no member named 'moveable' in 'B'}}
1414
// expected-error@-1 {{no member named 'moveable' in 'C'}}
15+
// expected-error@-2 {{no member named 'moveable' in 'D'}}
1516
return static_cast<T&&>(x);
1617
}
1718

@@ -23,6 +24,7 @@ namespace std {
2324

2425
template<typename T> CONSTEXPR auto move_if_noexcept(T &x) -> typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type {
2526
static_assert(T::moveable, "instantiated move_if_noexcept"); // expected-error {{no member named 'moveable' in 'B'}}
27+
// expected-error@-1 {{no member named 'moveable' in 'D'}}
2628
return static_cast<typename ref<T, noexcept(T(static_cast<T&&>(x)))>::type>(x);
2729
}
2830

@@ -36,6 +38,7 @@ namespace std {
3638
template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &x) {
3739
static_assert(T::moveable, "instantiated forward"); // expected-error {{no member named 'moveable' in 'B'}}
3840
// expected-error@-1 {{no member named 'moveable' in 'C'}}
41+
// expected-error@-2 {{no member named 'moveable' in 'D'}}
3942
return static_cast<T&&>(x);
4043
}
4144
template<typename T> CONSTEXPR T &&forward(typename remove_reference<T>::type &&x) {
@@ -67,21 +70,25 @@ namespace std {
6770
CONSTEXPR auto forward_like(T &&t) -> ForwardLikeRetType<U, T> {
6871
using TT = typename remove_reference<T>::type;
6972
static_assert(TT::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
73+
// expected-error@-1 {{no member named 'moveable' in 'D'}}
7074
return static_cast<ForwardLikeRetType<U, T>>(t);
7175
}
7276

7377
template<typename T> CONSTEXPR const T &as_const(T &x) {
7478
static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
79+
// expected-error@-1 {{no member named 'moveable' in 'D'}}
7580
return x;
7681
}
7782

7883
template<typename T> CONSTEXPR T *addressof(T &x) {
7984
static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
85+
// expected-error@-1 {{no member named 'moveable' in 'D'}}
8086
return __builtin_addressof(x);
8187
}
8288

8389
template<typename T> CONSTEXPR T *__addressof(T &x) {
8490
static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
91+
// expected-error@-1 {{no member named 'moveable' in 'D'}}
8592
return __builtin_addressof(x);
8693
}
8794
}
@@ -116,42 +123,20 @@ A &forward_rval_as_lval() {
116123
}
117124

118125
struct B {};
119-
B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}}
120-
B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}}
121-
B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}}
122-
B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // #4 expected-note {{instantiation of}}
123-
const B &(*pAsConst)(B&) = &std::as_const; // #5 expected-note {{instantiation of}}
124-
B *(*pAddressof)(B&) = &std::addressof; // #6 expected-note {{instantiation of}}
125-
B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #7 expected-note {{instantiation of}}
126+
B &&(*pMove)(B&) = std::move; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
127+
B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
128+
B &&(*pForward)(B&) = &std::forward<B>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
129+
B &&(*pForwardLike)(B&) = &std::forward_like<int&&, B&>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
130+
const B &(*pAsConst)(B&) = &std::as_const; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
131+
B *(*pAddressof)(B&) = &std::addressof; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
132+
B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
126133
int (*pUnrelatedMove)(B, B) = std::move;
127134

128135
struct C {};
129-
C &&(&rMove)(C&) = std::move; // #8 expected-note {{instantiation of}}
130-
C &&(&rForward)(C&) = std::forward<C>; // #9 expected-note {{instantiation of}}
136+
C &&(&rMove)(C&) = std::move; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
137+
C &&(&rForward)(C&) = std::forward<C>; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
131138
int (&rUnrelatedMove)(B, B) = std::move;
132139

133-
#if __cplusplus <= 201703L
134-
// expected-warning@#1 {{non-addressable}}
135-
// expected-warning@#2 {{non-addressable}}
136-
// expected-warning@#3 {{non-addressable}}
137-
// expected-warning@#4 {{non-addressable}}
138-
// expected-warning@#5 {{non-addressable}}
139-
// expected-warning@#6 {{non-addressable}}
140-
// expected-warning@#7 {{non-addressable}}
141-
// expected-warning@#8 {{non-addressable}}
142-
// expected-warning@#9 {{non-addressable}}
143-
#else
144-
// expected-error@#1 {{non-addressable}}
145-
// expected-error@#2 {{non-addressable}}
146-
// expected-error@#3 {{non-addressable}}
147-
// expected-error@#4 {{non-addressable}}
148-
// expected-error@#5 {{non-addressable}}
149-
// expected-error@#6 {{non-addressable}}
150-
// expected-error@#7 {{non-addressable}}
151-
// expected-error@#8 {{non-addressable}}
152-
// expected-error@#9 {{non-addressable}}
153-
#endif
154-
155140
void attribute_const() {
156141
int n;
157142
std::move(n); // expected-warning {{ignoring return value}}
@@ -163,6 +148,22 @@ void attribute_const() {
163148
std::as_const(n); // expected-warning {{ignoring return value}}
164149
}
165150

151+
struct D {
152+
void* operator new(__SIZE_TYPE__, D&&(*)(D&));
153+
void* operator new(__SIZE_TYPE__, D*(*)(D&));
154+
void* operator new(__SIZE_TYPE__, const D&(*)(D&));
155+
};
156+
157+
void placement_new() {
158+
new (std::move<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
159+
new (std::move_if_noexcept<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
160+
new (std::forward<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
161+
new (std::forward_like<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
162+
new (std::addressof<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
163+
new (std::__addressof<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
164+
new (std::as_const<D>) D; // cxx17-warning {{non-addressable}} cxx20-error {{non-addressable}} expected-note {{instantiation of}}
165+
}
166+
166167
namespace std {
167168
template<typename T> int &move(T);
168169
}

0 commit comments

Comments
 (0)