llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.85k stars 11.47k forks source link

Unhelpful diagnostic when decomposing type that doesn't implement all tuple-like operations #99572

Open Michael137 opened 1 month ago

Michael137 commented 1 month ago

Take this contrived example:

struct B {                              
  int w;                                
  int z;                                
};                                      

namespace std {                         
template<typename T> struct tuple_size {
};                                      
template<>                              
struct tuple_size<B> {                  
    static constexpr int value = 2;     
};                                      
}                                       

int main() {                            
    auto [x, y] = B{1, 2};              
    return 0;                           
}                                       

We get:

decomp.cpp:16:11: error: use of undeclared identifier 'get'
   16 |     auto [x, y] = B{1, 2};
      |           ^
decomp.cpp:16:11: note: in implicit initialization of binding declaration 'x'
1 error generated.

Compare this to the more helpful error message we get when we do actually implement the get operation:

struct B {                                                  
  int w;                                                    
  int z;                                                    
  template<int> int get();                                  
  template<> int get<0>() { return w; }                     
  template<> int get<1>() { return z; }                     
};                                                          

$ g++ decomp.cpp -std=c++2a
decomp.cpp:19:11: error: cannot decompose this type; 'std::tuple_element<0UL, B>::type' does not name a type
   19 |     auto [x, y] = B{1, 2};
      |           ^
decomp.cpp:19:11: note: in implicit initialization of binding declaration 'x'
1 error generated.

I found the second diagnostic to be better at nudging me in the write direction as to what's missing.

Not sure how actionable this is. I just ran into this when trying to write a test for a tuple-like decomposition of a custom type without including the tuple header.

llvmbot commented 1 month ago

@llvm/issue-subscribers-clang-frontend

Author: Michael Buch (Michael137)

Take this contrived example: ``` struct B { int w; int z; }; namespace std { template<typename T> struct tuple_size { }; template<> struct tuple_size<B> { static constexpr int value = 2; }; } int main() { auto [x, y] = B{1, 2}; return 0; } ``` We get: ``` decomp.cpp:16:11: error: use of undeclared identifier 'get' 16 | auto [x, y] = B{1, 2}; | ^ decomp.cpp:16:11: note: in implicit initialization of binding declaration 'x' 1 error generated. ``` Compare this to the more helpful error message we get when we do actually implement the `get` operation: ``` struct B { int w; int z; template<int> int get(); template<> int get<0>() { return w; } template<> int get<1>() { return z; } }; $ g++ decomp.cpp -std=c++2a decomp.cpp:19:11: error: cannot decompose this type; 'std::tuple_element<0UL, B>::type' does not name a type 19 | auto [x, y] = B{1, 2}; | ^ decomp.cpp:19:11: note: in implicit initialization of binding declaration 'x' 1 error generated. ``` I found the second diagnostic to be better at nudging me in the write direction as to what's missing. Not sure how actionable this is. I just ran into this when trying to write a test for a tuple-like decomposition of a custom type without including the `tuple` header.