Skip to content

Commit c4c35d9

Browse files
authored
[Clang] [Sema] Handle this in __restrict-qualified member functions properly (#83187)
When resolving the type of `this` inside a member function, we were attaching all qualifiers present on the member function to the class type and then making it a pointer; however, `__restrict`, unlike `const` and `volatile`, needs to be attached to the pointer type rather than the pointee type. This fixes #82941, #42411, and #18121.
1 parent 3fda50d commit c4c35d9

File tree

4 files changed

+88
-3
lines changed

4 files changed

+88
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,11 @@ Bug Fixes to C++ Support
293293
lookup searches the bases of an incomplete class.
294294
- Fix a crash when an unresolved overload set is encountered on the RHS of a ``.*`` operator.
295295
(`#53815 <https://github.com/llvm/llvm-project/issues/53815>`_)
296+
- In ``__restrict``-qualified member functions, attach ``__restrict`` to the pointer type of
297+
``this`` rather than the pointee type.
298+
Fixes (`#82941 <https://github.com/llvm/llvm-project/issues/82941>`_),
299+
(`#42411 <https://github.com/llvm/llvm-project/issues/42411>`_), and
300+
(`#18121 <https://github.com/llvm/llvm-project/issues/18121>`_).
296301

297302
Bug Fixes to AST Handling
298303
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/DeclCXX.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,8 +2543,19 @@ QualType CXXMethodDecl::getThisType(const FunctionProtoType *FPT,
25432543
const CXXRecordDecl *Decl) {
25442544
ASTContext &C = Decl->getASTContext();
25452545
QualType ObjectTy = ::getThisObjectType(C, FPT, Decl);
2546-
return C.getLangOpts().HLSL ? C.getLValueReferenceType(ObjectTy)
2547-
: C.getPointerType(ObjectTy);
2546+
2547+
// Unlike 'const' and 'volatile', a '__restrict' qualifier must be
2548+
// attached to the pointer type, not the pointee.
2549+
bool Restrict = FPT->getMethodQuals().hasRestrict();
2550+
if (Restrict)
2551+
ObjectTy.removeLocalRestrict();
2552+
2553+
ObjectTy = C.getLangOpts().HLSL ? C.getLValueReferenceType(ObjectTy)
2554+
: C.getPointerType(ObjectTy);
2555+
2556+
if (Restrict)
2557+
ObjectTy.addRestrict();
2558+
return ObjectTy;
25482559
}
25492560

25502561
QualType CXXMethodDecl::getThisType() const {

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1220,7 +1220,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda(
12201220
: nullptr;
12211221
}
12221222
}
1223-
return ASTCtx.getPointerType(ClassType);
1223+
return ThisTy;
12241224
}
12251225

12261226
QualType Sema::getCurrentThisType() {

clang/test/SemaCXX/restrict-this.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %clang_cc1 -verify -fsyntax-only %s
2+
// expected-no-diagnostics
3+
4+
struct C {
5+
void f() __restrict {
6+
static_assert(__is_same(decltype(this), C *__restrict));
7+
(void) [this]() {
8+
static_assert(__is_same(decltype(this), C *__restrict));
9+
(void) [this]() { static_assert(__is_same(decltype(this), C *__restrict)); };
10+
11+
// By-value capture means 'this' is now a different object; do not
12+
// make it __restrict.
13+
(void) [*this]() { static_assert(__is_same(decltype(this), const C *)); };
14+
(void) [*this]() mutable { static_assert(__is_same(decltype(this), C *)); };
15+
};
16+
}
17+
};
18+
19+
template <typename T> struct TC {
20+
void f() __restrict {
21+
static_assert(__is_same(decltype(this), TC<int> *__restrict));
22+
(void) [this]() {
23+
static_assert(__is_same(decltype(this), TC<int> *__restrict));
24+
(void) [this]() { static_assert(__is_same(decltype(this), TC<int> *__restrict)); };
25+
26+
// By-value capture means 'this' is now a different object; do not
27+
// make it __restrict.
28+
(void) [*this]() { static_assert(__is_same(decltype(this), const TC<int> *)); };
29+
(void) [*this]() mutable { static_assert(__is_same(decltype(this), TC<int> *)); };
30+
};
31+
}
32+
};
33+
34+
void f() {
35+
TC<int>{}.f();
36+
}
37+
38+
namespace gh18121 {
39+
struct Foo {
40+
void member() __restrict {
41+
Foo *__restrict This = this;
42+
}
43+
};
44+
}
45+
46+
namespace gh42411 {
47+
struct foo {
48+
int v;
49+
void f() const __restrict {
50+
static_assert(__is_same(decltype((v)), const int&));
51+
(void) [this]() { static_assert(__is_same(decltype((v)), const int&)); };
52+
}
53+
};
54+
}
55+
56+
namespace gh82941 {
57+
void f(int& x) {
58+
(void)x;
59+
}
60+
61+
class C {
62+
int x;
63+
void g() __restrict;
64+
};
65+
66+
void C::g() __restrict {
67+
f(this->x);
68+
}
69+
}

0 commit comments

Comments
 (0)