Skip to content

Commit 493ee8c

Browse files
committed
Allow implicit conversion for class/struct types with conversion operators. Explicit conversion must be done for all other types.
1 parent d930092 commit 493ee8c

File tree

4 files changed

+96
-50
lines changed

4 files changed

+96
-50
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ Non-comprehensive list of changes in this release
328328
- Added ``__builtin_stdc_rotate_left`` and ``__builtin_stdc_rotate_right``
329329
for bit rotation of unsigned integers including ``_BitInt`` types. Rotation
330330
counts are normalized modulo the bit-width and support negative values.
331-
Usable in constant expressions.
331+
Usable in constant expressions. Implicit conversion is supported for
332+
class/struct types with conversion operators.
332333

333334
New Compiler Flags
334335
------------------

clang/lib/Sema/SemaChecking.cpp

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,62 +2322,100 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) {
23222322
return false;
23232323
}
23242324

2325+
class RotateIntegerConverter : public Sema::ContextualImplicitConverter {
2326+
unsigned ArgIndex;
2327+
bool OnlyUnsigned;
2328+
2329+
Sema::SemaDiagnosticBuilder emitError(Sema &S, SourceLocation Loc,
2330+
QualType T) {
2331+
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
2332+
<< ArgIndex << /*scalar*/ 1
2333+
<< (OnlyUnsigned ? /*unsigned integer*/ 3 : /*integer*/ 1)
2334+
<< /*no fp*/ 0 << T;
2335+
}
2336+
2337+
public:
2338+
RotateIntegerConverter(unsigned ArgIndex, bool OnlyUnsigned)
2339+
: ContextualImplicitConverter(/*Suppress=*/false,
2340+
/*SuppressConversion=*/true),
2341+
ArgIndex(ArgIndex), OnlyUnsigned(OnlyUnsigned) {}
2342+
2343+
bool match(QualType T) override {
2344+
return OnlyUnsigned ? T->isUnsignedIntegerType() : T->isIntegerType();
2345+
}
2346+
2347+
Sema::SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
2348+
QualType T) override {
2349+
return emitError(S, Loc, T);
2350+
}
2351+
2352+
Sema::SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
2353+
QualType T) override {
2354+
return emitError(S, Loc, T);
2355+
}
2356+
2357+
Sema::SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
2358+
QualType T,
2359+
QualType ConvTy) override {
2360+
return emitError(S, Loc, T);
2361+
}
2362+
2363+
Sema::SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
2364+
QualType ConvTy) override {
2365+
return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
2366+
}
2367+
2368+
Sema::SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
2369+
QualType T) override {
2370+
return emitError(S, Loc, T);
2371+
}
2372+
2373+
Sema::SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
2374+
QualType ConvTy) override {
2375+
return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
2376+
}
2377+
2378+
Sema::SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
2379+
QualType T,
2380+
QualType ConvTy) override {
2381+
llvm_unreachable("conversion functions are permitted");
2382+
}
2383+
};
2384+
23252385
/// Checks that __builtin_stdc_rotate_{left,right} was called with two
23262386
/// arguments, that the first argument is an unsigned integer type, and that
23272387
/// the second argument is an integer type.
23282388
static bool BuiltinRotateGeneric(Sema &S, CallExpr *TheCall) {
23292389
if (S.checkArgCount(TheCall, 2))
23302390
return true;
23312391

2332-
ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0));
2392+
// First argument (value to rotate) must be unsigned integer type.
2393+
RotateIntegerConverter Arg0Converter(1, /*OnlyUnsigned=*/true);
2394+
ExprResult Arg0Res = S.PerformContextualImplicitConversion(
2395+
TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(0), Arg0Converter);
23332396
if (Arg0Res.isInvalid())
23342397
return true;
23352398

23362399
Expr *Arg0 = Arg0Res.get();
23372400
TheCall->setArg(0, Arg0);
23382401

23392402
QualType Arg0Ty = Arg0->getType();
2340-
if (!Arg0Ty->isUnsignedIntegerType()) {
2341-
ExprResult ConvArg0Res = S.PerformImplicitConversion(
2342-
TheCall->getArg(0), S.Context.UnsignedIntTy, AssignmentAction::Passing);
2343-
if (ConvArg0Res.isUsable()) {
2344-
Arg0 = ConvArg0Res.get();
2345-
Arg0Ty = Arg0->getType();
2346-
TheCall->setArg(0, Arg0);
2347-
}
2348-
}
2349-
2350-
if (!Arg0Ty->isUnsignedIntegerType()) {
2351-
S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2352-
<< 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
2353-
<< Arg0Ty;
2403+
if (!Arg0Ty->isUnsignedIntegerType())
23542404
return true;
2355-
}
23562405

2357-
ExprResult Arg1Res = S.DefaultLvalueConversion(TheCall->getArg(1));
2406+
// Second argument (rotation count) must be integer type.
2407+
RotateIntegerConverter Arg1Converter(2, /*OnlyUnsigned=*/false);
2408+
ExprResult Arg1Res = S.PerformContextualImplicitConversion(
2409+
TheCall->getArg(1)->getBeginLoc(), TheCall->getArg(1), Arg1Converter);
23582410
if (Arg1Res.isInvalid())
23592411
return true;
23602412

23612413
Expr *Arg1 = Arg1Res.get();
23622414
TheCall->setArg(1, Arg1);
23632415

23642416
QualType Arg1Ty = Arg1->getType();
2365-
2366-
if (!Arg1Ty->isIntegerType()) {
2367-
ExprResult ConvArg1Res = S.PerformImplicitConversion(
2368-
TheCall->getArg(1), S.Context.IntTy, AssignmentAction::Passing);
2369-
if (ConvArg1Res.isUsable()) {
2370-
Arg1 = ConvArg1Res.get();
2371-
Arg1Ty = Arg1->getType();
2372-
TheCall->setArg(1, Arg1);
2373-
}
2374-
}
2375-
2376-
if (!Arg1Ty->isIntegerType()) {
2377-
S.Diag(Arg1->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2378-
<< 2 << /* scalar */ 1 << /* integer ty */ 2 << /* no fp */ 0 << Arg1Ty;
2417+
if (!Arg1Ty->isIntegerType())
23792418
return true;
2380-
}
23812419

23822420
TheCall->setType(Arg0Ty);
23832421
return false;

clang/test/Sema/builtin-stdc-rotate.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,22 +105,28 @@ void test_errors(int si, float f) {
105105
__builtin_stdc_rotate_left(ui, 1, 2); // expected-error {{too many arguments to function call}}
106106
}
107107

108-
void test_implicit_conversions(_Bool b, float f, int si) {
108+
void test_valid_conversions(_Bool b, int si) {
109109
unsigned int ui = 5;
110110

111-
// Test implicit conversions for second argument
111+
// Valid: bool converts to int for second argument
112112
(void)__builtin_stdc_rotate_left(ui, b);
113-
(void)__builtin_stdc_rotate_left(ui, f);
114-
(void)__builtin_stdc_rotate_left(ui, 1.5); // expected-warning {{implicit conversion from 'double' to 'int' changes value from 1.5 to 1}}
115113
(void)__builtin_stdc_rotate_right(ui, b);
116-
(void)__builtin_stdc_rotate_right(ui, f);
117114

118-
// Test implicit conversions for first argument
119-
(void)__builtin_stdc_rotate_left(si, 1);
120-
(void)__builtin_stdc_rotate_left(-5, 1);
121-
(void)__builtin_stdc_rotate_right(3.0, 1.5); // expected-warning {{implicit conversion from 'double' to 'int' changes value from 1.5 to 1}}
115+
// Valid: signed int is an integer type for second argument
116+
(void)__builtin_stdc_rotate_left(ui, si);
117+
(void)__builtin_stdc_rotate_right(ui, si);
118+
}
119+
120+
void test_invalid_types(float f, int si) {
121+
unsigned int ui = 5;
122+
123+
// Invalid: float is not an integer type for second argument
124+
(void)__builtin_stdc_rotate_left(ui, f); // expected-error {{2nd argument must be a scalar integer type (was 'float')}}
125+
(void)__builtin_stdc_rotate_left(ui, 1.5); // expected-error {{2nd argument must be a scalar integer type (was 'double')}}
126+
(void)__builtin_stdc_rotate_right(ui, f); // expected-error {{2nd argument must be a scalar integer type (was 'float')}}
122127

123-
// Test narrowing conversion in assignment
124-
unsigned _BitInt(17) rotated_odd = __builtin_stdc_rotate_left(0x1ABCD, 5); // expected-warning {{implicit conversion from 'unsigned int' to 'unsigned _BitInt(17)' changes value from 3504544 to 96672}}
125-
(void)rotated_odd;
128+
// Invalid: signed int is not unsigned for first argument
129+
(void)__builtin_stdc_rotate_left(si, 1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
130+
(void)__builtin_stdc_rotate_left(-5, 1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'int')}}
131+
(void)__builtin_stdc_rotate_right(3.0, 1); // expected-error {{1st argument must be a scalar unsigned integer type (was 'double')}}
126132
}

clang/test/SemaCXX/constexpr-builtin-stdc-rotate.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,16 @@ void test_implicit_conversions() {
185185
auto result4 = __builtin_stdc_rotate_right(uw, RotateAmount::ROTATE_BY_4);
186186

187187
bool b = true;
188-
float f = 3.7f;
189188
auto result5 = __builtin_stdc_rotate_left(10U, b);
190-
auto result6 = __builtin_stdc_rotate_left(10U, f);
191-
auto result7 = __builtin_stdc_rotate_right(10U, 2.9f); // expected-warning {{implicit conversion from 'float' to 'int' changes value from 2.9000001 to 2}}
192189
}
193190

194-
void test_no_conversions() {
191+
void test_invalid_types() {
192+
float f = 3.7f;
193+
auto result6 = __builtin_stdc_rotate_left(10U, f); // expected-error {{2nd argument must be a scalar integer type (was 'float')}}
194+
auto result7 = __builtin_stdc_rotate_right(10U, 2.9f); // expected-error {{2nd argument must be a scalar integer type (was 'float')}}
195+
195196
NoConversion nc;
196-
auto result1 = __builtin_stdc_rotate_left(5U, nc); // expected-error {{passing 'NoConversion' to parameter of incompatible type 'int'}} expected-error {{2nd argument must be a scalar signed integer type (was 'NoConversion')}}
197+
auto result1 = __builtin_stdc_rotate_left(5U, nc); // expected-error {{2nd argument must be a scalar integer type (was 'NoConversion')}}
197198
}
198199

199200
} // namespace test_conversions

0 commit comments

Comments
 (0)