[c++20] Don't consider string literal operator templates for numeric
authorRichard Smith <richard@metafoo.co.uk>
Mon, 11 Jan 2021 21:12:43 +0000 (13:12 -0800)
committerRichard Smith <richard@metafoo.co.uk>
Mon, 11 Jan 2021 21:19:00 +0000 (13:19 -0800)
literals.

A literal interpretation of the standard wording allows this, but it was
never intended that string literal operator templates would be used for
anything other than user-defined string literals.

clang/lib/Sema/SemaLookup.cpp
clang/test/SemaCXX/cxx2a-user-defined-literals.cpp

index 16dd8f5..29038ab 100644 (file)
@@ -3384,6 +3384,13 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
       TemplateParameterList *Params = FD->getTemplateParameters();
       if (Params->size() == 1) {
         IsTemplate = true;
+        if (!Params->getParam(0)->isTemplateParameterPack() && !StringLit) {
+          // Implied but not stated: user-defined integer and floating literals
+          // only ever use numeric literal operator templates, not templates
+          // taking a parameter of class type.
+          F.erase();
+          continue;
+        }
 
         // A string literal template is only considered if the string literal
         // is a well-formed template argument for the template parameter.
index d730eba..12f672f 100644 (file)
@@ -24,4 +24,33 @@ chrono::day bin_d = 0b011d;
 // expected-note@9{{candidate constructor (the implicit move constructor)}}
 chrono::day hex_d = 0x44d;
 chrono::year y  = 10y;
+
+namespace ignore_class_udl_for_numeric_literals {
+  struct A { constexpr A(const char*) {} };
+  struct B { constexpr B(char); };
+  struct C { constexpr C(int); };
+  template<A> void operator""_a();
+  template<B> void operator""_b();
+  template<C> void operator""_c();
+  void test_class_udl_1() {
+    1_a; // expected-error {{no matching}}
+    1_b; // expected-error {{no matching}}
+    1_c; // expected-error {{no matching}}
+    "1"_a;
+    "1"_b; // expected-error {{no matching}}
+    "1"_c; // expected-error {{no matching}}
+  }
+  template<char...> void operator""_a();
+  template<char...> void operator""_b();
+  template<char...> void operator""_c();
+  void test_class_udl_2() {
+    1_a;
+    // FIXME: The standard appears to say these two are ambiguous!
+    1_b;
+    1_c;
+    "1"_a;
+    "1"_b; // expected-error {{no matching}}
+    "1"_c; // expected-error {{no matching}}
+  }
+}
 #endif