]> granicus.if.org Git - clang/commitdiff
[c++20] Disallow template argument deduction from a braced-init-list
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 31 Aug 2019 00:05:50 +0000 (00:05 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 31 Aug 2019 00:05:50 +0000 (00:05 +0000)
containing designators. The C++20 wording doesn't actually say what
happens in this case, but treating this as a non-deduced context seems
like the most natural behavior.

(We might want to consider deducing through array designators as an
extension in the future, but will need to be careful to deduce the array
bound properly if we do so. That's not permitted herein.)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@370555 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateDeduction.cpp
test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
test/SemaTemplate/deduction.cpp

index a75af62bf355b0073f3dd459cb6ae6e7eb942fa8..db50830a15da0731cd451193ce90f340e7169891 100644 (file)
@@ -3702,6 +3702,12 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
     return Sema::TDK_Success;
   }
 
+  // Resolving a core issue: a braced-init-list containing any designators is
+  // a non-deduced context.
+  for (Expr *E : ILE->inits())
+    if (isa<DesignatedInitExpr>(E))
+      return Sema::TDK_Success;
+
   // Deduction only needs to be done for dependent types.
   if (ElTy->isDependentType()) {
     for (Expr *E : ILE->inits()) {
@@ -4509,6 +4515,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
     if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
       return DAR_Failed;
 
+    // Resolving a core issue: a braced-init-list containing any designators is
+    // a non-deduced context.
+    for (Expr *E : InitList->inits())
+      if (isa<DesignatedInitExpr>(E))
+        return DAR_Failed;
+
     SourceRange DeducedFromInitRange;
     for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
       Expr *Init = InitList->getInit(i);
index 9a82ec4a7bd902c2cdced0fe14022c1c2d68e546..b5d6bd68f1fba4c655b272e278d2ac7c6fbc60cc 100644 (file)
@@ -29,9 +29,9 @@ namespace std {
     typedef const _E* iterator;
     typedef const _E* const_iterator;
 
-    initializer_list() : __begin_(nullptr), __size_(0) {}
+    constexpr initializer_list() : __begin_(nullptr), __size_(0) {}
 
-    size_t    size()  const {return __size_;}
+    constexpr size_t    size()  const {return __size_;}
     const _E* begin() const {return __begin_;}
     const _E* end()   const {return __begin_ + __size_;}
   };
@@ -354,3 +354,14 @@ namespace no_conversion_after_auto_list_deduction {
   struct Y { using T = std::initializer_list<Y>(*)(); operator T(); };
   auto (*y)() = { Y() }; // expected-error {{from initializer list}}
 }
+
+namespace designated_init {
+  constexpr auto a = {.a = 1, .b = 2}; // expected-error {{cannot deduce}}
+  constexpr auto b = {[0] = 1, [4] = 2}; // expected-error {{cannot deduce}} expected-warning {{C99}}
+  constexpr auto c = {1, [4] = 2}; // expected-error {{cannot deduce}} expected-warning 2{{C99}} expected-note {{here}}
+  constexpr auto d = {1, [0] = 2}; // expected-error {{cannot deduce}} expected-warning 2{{C99}} expected-note {{here}}
+
+  // If we ever start accepting the above, these assertions should pass.
+  static_assert(c.size() == 5, "");
+  static_assert(d.size() == 1, "");
+}
index be86f18729dc26b238d6a8e126d0278e5b063340..64fef8e5f522caf40c50a9df6f88cd4d2a15316a 100644 (file)
@@ -539,3 +539,10 @@ namespace dependent_list_deduction {
 #endif
   }
 }
+
+namespace designators {
+  template<typename T, int N> constexpr int f(T (&&)[N]) { return N; } // expected-note 2{{couldn't infer template argument 'T'}}
+  static_assert(f({1, 2, [20] = 3}) == 3, ""); // expected-error {{no matching function}} expected-warning 2{{C99}} expected-note {{}}
+
+  static_assert(f({.a = 1, .b = 2}) == 3, ""); // expected-error {{no matching function}}
+}