Skip to content

Commit 1b3476d

Browse files
committed
[Clang][Sema] Earlier type checking for builtin unary operators
1 parent 5d9889a commit 1b3476d

File tree

9 files changed

+36
-29
lines changed

9 files changed

+36
-29
lines changed

clang/include/clang/AST/Type.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8044,7 +8044,10 @@ inline bool Type::isUndeducedType() const {
80448044
/// Determines whether this is a type for which one can define
80458045
/// an overloaded operator.
80468046
inline bool Type::isOverloadableType() const {
8047-
return isDependentType() || isRecordType() || isEnumeralType();
8047+
if (!CanonicalType->isDependentType())
8048+
return isRecordType() || isEnumeralType();
8049+
return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
8050+
!isMemberPointerType();
80488051
}
80498052

80508053
/// Determines whether this type is written as a typedef-name.

clang/lib/Sema/SemaExpr.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -671,12 +671,12 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
671671

672672
// We don't want to throw lvalue-to-rvalue casts on top of
673673
// expressions of certain types in C++.
674-
if (getLangOpts().CPlusPlus &&
675-
(E->getType() == Context.OverloadTy ||
676-
// FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
677-
// to pointer types even if the pointee type is dependent.
678-
(T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
679-
return E;
674+
if (getLangOpts().CPlusPlus) {
675+
if (T == Context.OverloadTy || T->isRecordType() ||
676+
(T->isDependentType() && !T->isAnyPointerType() &&
677+
!T->isMemberPointerType()))
678+
return E;
679+
}
680680

681681
// The C standard is actually really unclear on this point, and
682682
// DR106 tells us what the result should be but not why. It's
@@ -11116,7 +11116,7 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
1111611116
if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>())
1111711117
ResType = ResAtomicType->getValueType();
1111811118

11119-
assert(ResType->isAnyPointerType() && !ResType->isDependentType());
11119+
assert(ResType->isAnyPointerType());
1112011120
QualType PointeeTy = ResType->getPointeeType();
1112111121
return S.RequireCompleteSizedType(
1112211122
Loc, PointeeTy,
@@ -14287,7 +14287,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
1428714287
ExprObjectKind &OK,
1428814288
SourceLocation OpLoc,
1428914289
bool IsInc, bool IsPrefix) {
14290-
if (Op->isTypeDependent())
14290+
if (Op->isTypeDependent() &&
14291+
(Op->hasPlaceholderType() ||
14292+
Op->getType()->isSpecificBuiltinType(BuiltinType::Dependent)))
1429114293
return S.Context.DependentTy;
1429214294

1429314295
QualType ResType = Op->getType();
@@ -14725,7 +14727,9 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
1472514727
static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
1472614728
SourceLocation OpLoc,
1472714729
bool IsAfterAmp = false) {
14728-
if (Op->isTypeDependent())
14730+
if (Op->isTypeDependent() &&
14731+
(Op->hasPlaceholderType() ||
14732+
Op->getType()->isSpecificBuiltinType(BuiltinType::Dependent)))
1472914733
return S.Context.DependentTy;
1473014734

1473114735
ExprResult ConvResult = S.UsualUnaryConversions(Op);

clang/test/AST/ast-dump-expr-json.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,9 +4261,9 @@ void TestNonADLCall3() {
42614261
// CHECK-NEXT: }
42624262
// CHECK-NEXT: },
42634263
// CHECK-NEXT: "type": {
4264-
// CHECK-NEXT: "qualType": "<dependent type>"
4264+
// CHECK-NEXT: "qualType": "V"
42654265
// CHECK-NEXT: },
4266-
// CHECK-NEXT: "valueCategory": "prvalue",
4266+
// CHECK-NEXT: "valueCategory": "lvalue",
42674267
// CHECK-NEXT: "isPostfix": false,
42684268
// CHECK-NEXT: "opcode": "*",
42694269
// CHECK-NEXT: "canOverflow": false,

clang/test/AST/ast-dump-expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ void PrimaryExpressions(Ts... a) {
282282
// CHECK-NEXT: CompoundStmt
283283
// CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V'
284284
// CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:8> 'NULL TYPE'
285-
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> '<dependent type>' prefix '*' cannot overflow
285+
// CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> 'V' lvalue prefix '*' cannot overflow
286286
// CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this
287287
}
288288
};

clang/test/AST/ast-dump-lambda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ template <typename... Ts> void test(Ts... a) {
8181
// CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:15, col:16>
8282
// CHECK-NEXT: | | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V'
8383
// CHECK-NEXT: | |-ParenListExpr {{.*}} <col:8> 'NULL TYPE'
84-
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> '<dependent type>' prefix '*' cannot overflow
84+
// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> 'V' lvalue prefix '*' cannot overflow
8585
// CHECK-NEXT: | | `-CXXThisExpr {{.*}} <col:8> 'V *' this
8686
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:15, col:16>
8787
// CHECK-NEXT: |-DeclStmt {{.*}} <line:22:3, col:11>

clang/test/CXX/over/over.built/ast.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ struct A{};
44

55
template <typename T, typename U>
66
auto Test(T* pt, U* pu) {
7-
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*'
7+
// CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*'
8+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
89
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
910
(void)*pt;
1011

11-
// CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++'
12+
// CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '++'
1213
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
1314
(void)(++pt);
1415

15-
// CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+'
16+
// CHECK: UnaryOperator {{.*}} 'T *' prefix '+'
17+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue>
1618
// CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *'
1719
(void)(+pt);
1820

clang/test/Frontend/noderef_templates.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#define NODEREF __attribute__((noderef))
44

55
template <typename T>
6-
int func(T NODEREF *a) { // expected-note 2 {{a declared here}}
7-
return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}}
6+
int func(T NODEREF *a) { // expected-note 3 {{a declared here}}
7+
return *a + 1; // expected-warning 3 {{dereferencing a; was declared with a 'noderef' type}}
88
}
99

1010
void func() {

clang/test/SemaCXX/cxx2b-deducing-this.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct S {
1919
// new and delete are implicitly static
2020
void *operator new(this unsigned long); // expected-error{{an explicit object parameter cannot appear in a static function}}
2121
void operator delete(this void*); // expected-error{{an explicit object parameter cannot appear in a static function}}
22-
22+
2323
void g(this auto) const; // expected-error{{explicit object member function cannot have 'const' qualifier}}
2424
void h(this auto) &; // expected-error{{explicit object member function cannot have '&' qualifier}}
2525
void i(this auto) &&; // expected-error{{explicit object member function cannot have '&&' qualifier}}
@@ -198,9 +198,7 @@ void func(int i) {
198198
void TestMutationInLambda() {
199199
[i = 0](this auto &&){ i++; }();
200200
[i = 0](this auto){ i++; }();
201-
[i = 0](this const auto&){ i++; }();
202-
// expected-error@-1 {{cannot assign to a variable captured by copy in a non-mutable lambda}}
203-
// expected-note@-2 {{in instantiation of}}
201+
[i = 0](this const auto&){ i++; }(); // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}
204202

205203
int x;
206204
const auto l1 = [x](this auto&) { x = 42; }; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}}

clang/test/SemaTemplate/class-template-spec.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ int test_specs(A<float, float> *a1, A<float, int> *a2) {
1818
return a1->x + a2->y;
1919
}
2020

21-
int test_incomplete_specs(A<double, double> *a1,
21+
int test_incomplete_specs(A<double, double> *a1,
2222
A<double> *a2)
2323
{
2424
(void)a1->x; // expected-error{{member access into incomplete type}}
@@ -39,7 +39,7 @@ template <> struct X<int, int> { int foo(); }; // #1
3939
template <> struct X<float> { int bar(); }; // #2
4040

4141
typedef int int_type;
42-
void testme(X<int_type> *x1, X<float, int> *x2) {
42+
void testme(X<int_type> *x1, X<float, int> *x2) {
4343
(void)x1->foo(); // okay: refers to #1
4444
(void)x2->bar(); // okay: refers to #2
4545
}
@@ -53,7 +53,7 @@ struct A<char> {
5353
A<char>::A() { }
5454

5555
// Make sure we can see specializations defined before the primary template.
56-
namespace N{
56+
namespace N{
5757
template<typename T> struct A0;
5858
}
5959

@@ -97,7 +97,7 @@ namespace M {
9797
template<> struct ::A<long double>; // expected-error{{must occur at global scope}}
9898
}
9999

100-
template<> struct N::B<char> {
100+
template<> struct N::B<char> {
101101
int testf(int x) { return f(x); }
102102
};
103103

@@ -138,9 +138,9 @@ namespace PR18009 {
138138

139139
template <typename T> struct C {
140140
template <int N, int M> struct S;
141-
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}}
141+
template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // ok
142142
};
143-
C<int> c; // expected-note {{in instantiation of}}
143+
C<int> c;
144144

145145
template<int A> struct outer {
146146
template<int B, int C> struct inner {};

0 commit comments

Comments
 (0)