@@ -384,4 +384,298 @@ void test_compound_assignments() {
384384 l2 >>= 1 ; // COMPLIANT - compound assignment, rule does not apply
385385 l4 += l1; // COMPLIANT - compound assignment, rule does not apply
386386 l4 -= s32; // COMPLIANT - compound assignment, rule does not apply
387+ }
388+
389+ // Test user-defined operators - always non-extensible
390+ struct UserDefinedOperators {
391+ UserDefinedOperators (std::int32_t l1) {}
392+
393+ // Binary operators
394+ UserDefinedOperators operator +(std::int32_t l1) const {
395+ return UserDefinedOperators{0 };
396+ }
397+ UserDefinedOperators operator -(std::int32_t l1) const {
398+ return UserDefinedOperators{0 };
399+ }
400+ UserDefinedOperators operator *(std::int32_t l1) const {
401+ return UserDefinedOperators{0 };
402+ }
403+ UserDefinedOperators operator /(std::int32_t l1) const {
404+ return UserDefinedOperators{0 };
405+ }
406+ UserDefinedOperators operator %(std::int32_t l1) const {
407+ return UserDefinedOperators{0 };
408+ }
409+ UserDefinedOperators operator &(std::int32_t l1) const {
410+ return UserDefinedOperators{0 };
411+ }
412+ UserDefinedOperators operator |(std::int32_t l1) const {
413+ return UserDefinedOperators{0 };
414+ }
415+ UserDefinedOperators operator ^(std::int32_t l1) const {
416+ return UserDefinedOperators{0 };
417+ }
418+ UserDefinedOperators operator <<(std::int32_t l1) const {
419+ return UserDefinedOperators{0 };
420+ }
421+ UserDefinedOperators operator >>(std::int32_t l1) const {
422+ return UserDefinedOperators{0 };
423+ }
424+
425+ // Comparison operators
426+ bool operator ==(std::int32_t l1) const { return true ; }
427+ bool operator !=(std::int32_t l1) const { return false ; }
428+ bool operator <(std::int32_t l1) const { return false ; }
429+ bool operator <=(std::int32_t l1) const { return false ; }
430+ bool operator >(std::int32_t l1) const { return false ; }
431+ bool operator >=(std::int32_t l1) const { return false ; }
432+
433+ // Subscript operator
434+ std::int32_t operator [](std::int32_t l1) const { return 0 ; }
435+
436+ // Function call operator
437+ std::int32_t operator ()(std::int32_t l1) const { return 0 ; }
438+ std::int32_t operator ()(std::int32_t l1, std::int32_t l2) const { return 0 ; }
439+
440+ // Assignment operators
441+ UserDefinedOperators &operator =(std::int32_t l1) { return *this ; }
442+ UserDefinedOperators &operator +=(std::int32_t l1) { return *this ; }
443+ UserDefinedOperators &operator -=(std::int32_t l1) { return *this ; }
444+ UserDefinedOperators &operator *=(std::int32_t l1) { return *this ; }
445+ UserDefinedOperators &operator /=(std::int32_t l1) { return *this ; }
446+ UserDefinedOperators &operator %=(std::int32_t l1) { return *this ; }
447+ UserDefinedOperators &operator &=(std::int32_t l1) { return *this ; }
448+ UserDefinedOperators &operator |=(std::int32_t l1) { return *this ; }
449+ UserDefinedOperators &operator ^=(std::int32_t l1) { return *this ; }
450+ UserDefinedOperators &operator <<=(std::int32_t l1) { return *this ; }
451+ UserDefinedOperators &operator >>=(std::int32_t l1) { return *this ; }
452+
453+ // Increment/decrement operators
454+ UserDefinedOperators &operator ++() { return *this ; }
455+ UserDefinedOperators operator ++(int ) { return UserDefinedOperators{0 }; }
456+ UserDefinedOperators &operator --() { return *this ; }
457+ UserDefinedOperators operator --(int ) { return UserDefinedOperators{0 }; }
458+ };
459+
460+ // Global user-defined operators
461+ UserDefinedOperators operator +(std::int32_t l1,
462+ const UserDefinedOperators &l2) {
463+ return UserDefinedOperators{0 };
464+ }
465+
466+ UserDefinedOperators operator -(std::int32_t l1,
467+ const UserDefinedOperators &l2) {
468+ return UserDefinedOperators{0 };
469+ }
470+
471+ bool operator ==(std::int32_t l1, const UserDefinedOperators &l2) {
472+ return true ;
473+ }
474+
475+ void test_user_defined_operators () {
476+ UserDefinedOperators l1{42 };
477+ std::int32_t l2 = 10 ;
478+ std::int16_t l3 = 5 ;
479+ std::int64_t l4 = 100 ;
480+ std::uint32_t l5 = 20 ;
481+
482+ // Member operators - non-extensible, exact type match required
483+ l1 + l2; // COMPLIANT - exact type match
484+ l1 + l3; // COMPLIANT - widening conversion is allowed
485+ l1 + l4; // NON_COMPLIANT - different type
486+ l1 + l5; // NON_COMPLIANT - different signedness
487+
488+ l1 - l2; // COMPLIANT - exact type match
489+ l1 - l3; // COMPLIANT - widening conversion is allowed
490+ l1 - l4; // NON_COMPLIANT - different type
491+ l1 - l5; // NON_COMPLIANT - different signedness
492+
493+ l1 *l2; // COMPLIANT - exact type match
494+ l1 *l3; // COMPLIANT - widening conversion is allowed
495+ l1 *l4; // NON_COMPLIANT - different type
496+ l1 *l5; // NON_COMPLIANT - different signedness
497+
498+ l1 / l2; // COMPLIANT - exact type match
499+ l1 / l3; // COMPLIANT - widening conversion is allowed
500+ l1 / l4; // NON_COMPLIANT - different type
501+ l1 / l5; // NON_COMPLIANT - different signedness
502+
503+ l1 % l2; // COMPLIANT - exact type match
504+ l1 % l3; // COMPLIANT - widening conversion is allowed
505+ l1 % l4; // NON_COMPLIANT - different type
506+ l1 % l5; // NON_COMPLIANT - different signedness
507+
508+ l1 & l2; // COMPLIANT - exact type match
509+ l1 & l3; // COMPLIANT - widening conversion is allowed
510+ l1 & l4; // NON_COMPLIANT - different type
511+ l1 & l5; // NON_COMPLIANT - different signedness
512+
513+ l1 | l2; // COMPLIANT - exact type match
514+ l1 | l3; // COMPLIANT - widening conversion is allowed
515+ l1 | l4; // NON_COMPLIANT - different type
516+ l1 | l5; // NON_COMPLIANT - different signedness
517+
518+ l1 ^ l2; // COMPLIANT - exact type match
519+ l1 ^ l3; // COMPLIANT - widening conversion is allowed
520+ l1 ^ l4; // NON_COMPLIANT - different type
521+ l1 ^ l5; // NON_COMPLIANT - different signedness
522+
523+ l1 << l2; // COMPLIANT - exact type match
524+ l1 << l3; // COMPLIANT - widening conversion is allowed
525+ l1 << l4; // NON_COMPLIANT - different type
526+ l1 << l5; // NON_COMPLIANT - different signedness
527+
528+ l1 >> l2; // COMPLIANT - exact type match
529+ l1 >> l3; // COMPLIANT - widening conversion is allowed
530+ l1 >> l4; // NON_COMPLIANT - different type
531+ l1 >> l5; // NON_COMPLIANT - different signedness
532+
533+ // Comparison operators
534+ l1 == l2; // COMPLIANT - exact type match
535+ l1 == l3; // COMPLIANT - widening conversion is allowed
536+ l1 == l4; // NON_COMPLIANT - different type
537+ l1 == l5; // NON_COMPLIANT - different signedness
538+
539+ l1 != l2; // COMPLIANT - exact type match
540+ l1 != l3; // COMPLIANT - widening conversion is allowed
541+ l1 != l4; // NON_COMPLIANT - different type
542+ l1 != l5; // NON_COMPLIANT - different signedness
543+
544+ l1 < l2; // COMPLIANT - exact type match
545+ l1 < l3; // COMPLIANT - widening conversion is allowed
546+ l1 < l4; // NON_COMPLIANT - different type
547+ l1 < l5; // NON_COMPLIANT - different signedness
548+
549+ l1 <= l2; // COMPLIANT - exact type match
550+ l1 <= l3; // COMPLIANT - widening conversion is allowed
551+ l1 <= l4; // NON_COMPLIANT - different type
552+ l1 <= l5; // NON_COMPLIANT
553+
554+ l1 > l2; // COMPLIANT - exact type match
555+ l1 > l3; // COMPLIANT - widening conversion is allowed
556+ l1 > l4; // NON_COMPLIANT
557+ l1 > l5; // NON_COMPLIANT - different signedness
558+
559+ l1 >= l2; // COMPLIANT - exact type match
560+ l1 >= l3; // COMPLIANT - widening conversion is allowed
561+ l1 >= l4; // NON_COMPLIANT
562+ l1 >= l5; // NON_COMPLIANT - different signedness
563+
564+ // Subscript operator
565+ l1[l2]; // COMPLIANT - exact type match
566+ l1[l3]; // COMPLIANT - widening conversion is allowed
567+ l1[l4]; // NON_COMPLIANT - different type
568+ l1[l5]; // NON_COMPLIANT - different signedness
569+
570+ // Function call operator
571+ l1 (l2); // COMPLIANT - exact type match
572+ l1 (l3); // COMPLIANT - widening conversion is allowed
573+ l1 (l4); // NON_COMPLIANT - different type
574+ l1 (l5); // NON_COMPLIANT - different signedness
575+ l1 (l2, l2); // COMPLIANT - both exact type match
576+ l1 (l2, l4); // NON_COMPLIANT - second parameter different type
577+ l1 (l4, l2); // NON_COMPLIANT - first parameter different type
578+ l1 (l4, l5); // NON_COMPLIANT - both parameters different type
579+
580+ // The presence of a default copy constructor for UserDefinedOperators means
581+ // that assignments through operator= must be exact type matches.
582+ l1 = l2; // COMPLIANT - exact type match
583+ l1 = l3; // NON_COMPLIANT
584+ l1 = l4; // NON_COMPLIANT
585+ l1 = l5; // NON_COMPLIANT
586+
587+ l1 += l2; // COMPLIANT - exact type match
588+ l1 += l3; // COMPLIANT - widening conversion is allowed
589+ l1 += l4; // NON_COMPLIANT - different type
590+ l1 += l5; // NON_COMPLIANT - different signedness
591+
592+ l1 -= l2; // COMPLIANT - exact type match
593+ l1 -= l3; // COMPLIANT - widening conversion is allowed
594+ l1 -= l4; // NON_COMPLIANT - different type
595+ l1 -= l5; // NON_COMPLIANT - different signedness
596+
597+ l1 *= l2; // COMPLIANT - exact type match
598+ l1 *= l3; // COMPLIANT - widening conversion is allowed
599+ l1 *= l4; // NON_COMPLIANT - different type
600+ l1 *= l5; // NON_COMPLIANT - different signedness
601+
602+ l1 /= l2; // COMPLIANT - exact type match
603+ l1 /= l3; // COMPLIANT - widening conversion is allowed
604+ l1 /= l4; // NON_COMPLIANT - different type
605+ l1 /= l5; // NON_COMPLIANT - different signedness
606+
607+ l1 %= l2; // COMPLIANT - exact type match
608+ l1 %= l3; // COMPLIANT - widening conversion is allowed
609+ l1 %= l4; // NON_COMPLIANT - different type
610+ l1 %= l5; // NON_COMPLIANT - different signedness
611+
612+ l1 &= l2; // COMPLIANT - exact type match
613+ l1 &= l3; // COMPLIANT - widening conversion is allowed
614+ l1 &= l4; // NON_COMPLIANT - different type
615+ l1 &= l5; // NON_COMPLIANT - different signedness
616+
617+ l1 |= l2; // COMPLIANT - exact type match
618+ l1 |= l3; // COMPLIANT - widening conversion is allowed
619+ l1 |= l4; // NON_COMPLIANT - different type
620+ l1 |= l5; // NON_COMPLIANT - different signedness
621+
622+ l1 ^= l2; // COMPLIANT - exact type match
623+ l1 ^= l3; // COMPLIANT - widening conversion is allowed
624+ l1 ^= l4; // NON_COMPLIANT - different type
625+ l1 ^= l5; // NON_COMPLIANT - different signedness
626+
627+ l1 <<= l2; // COMPLIANT - exact type match
628+ l1 <<= l3; // COMPLIANT - widening conversion is allowed
629+ l1 <<= l4; // NON_COMPLIANT - different type
630+ l1 <<= l5; // NON_COMPLIANT - different signedness
631+
632+ l1 >>= l2; // COMPLIANT - exact type match
633+ l1 >>= l3; // COMPLIANT - widening conversion is allowed
634+ l1 >>= l4; // NON_COMPLIANT - different type
635+ l1 >>= l5; // NON_COMPLIANT - different signedness
636+
637+ // Global operators
638+ l2 + l1; // COMPLIANT - exact type match
639+ l3 + l1; // COMPLIANT - widening conversion is allowed
640+ l4 + l1; // NON_COMPLIANT - different type
641+ l5 + l1; // NON_COMPLIANT - different signedness
642+
643+ l2 - l1; // COMPLIANT - exact type match
644+ l3 - l1; // COMPLIANT - widening conversion is allowed
645+ l4 - l1; // NON_COMPLIANT - different type
646+ l5 - l1; // NON_COMPLIANT - different signedness
647+
648+ l2 == l1; // COMPLIANT - exact type match
649+ l3 == l1; // COMPLIANT - widening conversion is allowed
650+ l4 == l1; // NON_COMPLIANT - different type
651+ l5 == l1; // NON_COMPLIANT - different signedness
652+ }
653+
654+ // Test user-defined operators with constants
655+ void test_user_defined_operators_constants () {
656+ UserDefinedOperators l1{42 };
657+
658+ // Constants with exact type match
659+ l1 + 42 ; // COMPLIANT
660+ l1 + 42L ; // COMPLIANT
661+ l1 + 42LL ; // COMPLIANT
662+ l1 + 42U ; // COMPLIANT
663+ l1 + 42 .0f ; // NON_COMPLIANT - float constant
664+
665+ l1 == 42 ; // COMPLIANT - integer constant is int/int32_t
666+ l1 == 42L ; // COMPLIANT - long constant
667+ l1 == 42LL ; // COMPLIANT - long long constant
668+ l1 == 42U ; // COMPLIANT - unsigned constant
669+
670+ l1[42 ]; // COMPLIANT - integer constant is int/int32_t
671+ l1[42L ]; // COMPLIANT - long constant
672+ l1[42LL ]; // COMPLIANT - long long constant
673+ l1[42U ]; // COMPLIANT - unsigned constant
674+
675+ // The presence of a default copy constructor for UserDefinedOperators means
676+ // that assignments through operator= must be exact type matches.
677+ l1 = 42 ; // COMPLIANT - integer constant is int/int32_t
678+ l1 = 42L ; // NON_COMPLIANT
679+ l1 = 42LL ; // NON_COMPLIANT
680+ l1 = 42U ; // NON_COMPLIANT
387681}
0 commit comments