================================================================================
Concept definition
================================================================================

template <class T, class U>
concept Derived = std::is_base_of<U, T>::value;
--------------------------------------------------------------------------------

(translation_unit
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier))
      (type_parameter_declaration
        (type_identifier)))
    (concept_definition
      (identifier)
      (qualified_identifier
        (namespace_identifier)
        (qualified_identifier
          (template_type
            (type_identifier)
            (template_argument_list
              (type_descriptor
                (type_identifier))
              (type_descriptor
                (type_identifier))))
          (identifier))))))

================================================================================
Concept definition with requires expression
================================================================================

template<typename T>
concept Hashable = requires(T a) {
    { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
--------------------------------------------------------------------------------

(translation_unit
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (concept_definition
      (identifier)
      (requires_expression
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier)))
        (requirement_seq
          (compound_requirement
            (call_expression
              (compound_literal_expression
                (qualified_identifier
                  (namespace_identifier)
                  (template_type
                    (type_identifier)
                    (template_argument_list
                      (type_descriptor
                        (type_identifier)))))
                (initializer_list))
              (argument_list
                (identifier)))
            (trailing_return_type
              (type_descriptor
                (qualified_identifier
                  (namespace_identifier)
                  (template_type
                    (type_identifier)
                    (template_argument_list
                      (type_descriptor
                        (qualified_identifier
                          (namespace_identifier)
                          (type_identifier))))))))))))))

================================================================================
Requires clauses and expressions
================================================================================

template<typename T>
void f(T&&) requires Eq<T>; // can appear as the last element of a function declarator

template<typename T> requires Addable<T> // or right after a template parameter list
T add(T a, T b) { return a + b; }

template<typename T>
concept Addable = requires (T x) { x + x; }; // requires-expression

template<typename T>
    requires requires (T x) { x + x; } // ad-hoc constraint, note keyword used twice
T add(T a, T b) { return a + b; }

template<typename T>
    requires (!std::is_same_v<T, bool>) // parenthesized expressions are allowed
void f(T);

template<typename T> requires Addable<T> && Subtractable<T> // conjunctions
T f(T);

template<typename T> requires Addable<T> || Subtractable<T> // disjunctions
T f(T);

template<typename T> requires false || true // boolean literals
T f(T);

template<typename... T> requires (... && Addable<T>) // fold expressions
T f(T);

--------------------------------------------------------------------------------

(translation_unit
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (declaration
      (primitive_type)
      (function_declarator
        (identifier)
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (abstract_reference_declarator)))
        (requires_clause
          (template_type
            (type_identifier)
            (template_argument_list
              (type_descriptor
                (type_identifier))))))))
  (comment)
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (requires_clause
      (template_type
        (type_identifier)
        (template_argument_list
          (type_descriptor
            (type_identifier)))))
    (comment)
    (function_definition
      (type_identifier)
      (function_declarator
        (identifier)
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier))
          (parameter_declaration
            (type_identifier)
            (identifier))))
      (compound_statement
        (return_statement
          (binary_expression
            (identifier)
            (identifier))))))
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (concept_definition
      (identifier)
      (requires_expression
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier)))
        (requirement_seq
          (simple_requirement
            (binary_expression
              (identifier)
              (identifier)))))))
  (comment)
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (requires_clause
      (requires_expression
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier)))
        (requirement_seq
          (simple_requirement
            (binary_expression
              (identifier)
              (identifier))))))
    (comment)
    (function_definition
      (type_identifier)
      (function_declarator
        (identifier)
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier))
          (parameter_declaration
            (type_identifier)
            (identifier))))
      (compound_statement
        (return_statement
          (binary_expression
            (identifier)
            (identifier))))))
      (template_declaration
        (template_parameter_list
          (type_parameter_declaration
            (type_identifier)))
        (requires_clause
          (unary_expression
            (qualified_identifier
              (namespace_identifier)
              (template_function
                (identifier)
                (template_argument_list
                  (type_descriptor
                    (type_identifier))
                  (type_descriptor
                    (primitive_type)))))))
        (comment)
        (declaration
          (primitive_type)
          (function_declarator
            (identifier)
            (parameter_list
              (parameter_declaration
                (type_identifier))))))
      (template_declaration
        (template_parameter_list
          (type_parameter_declaration
            (type_identifier)))
        (requires_clause
          (constraint_conjunction
            (template_type
              (type_identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier))))
            (template_type
              (type_identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier))))))
        (comment)
        (declaration
          (type_identifier)
          (function_declarator
            (identifier)
            (parameter_list
              (parameter_declaration
                (type_identifier))))))
      (template_declaration
        (template_parameter_list
          (type_parameter_declaration
            (type_identifier)))
        (requires_clause
          (constraint_disjunction
            (template_type
              (type_identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier))))
            (template_type
              (type_identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier))))))
        (comment)
        (declaration
          (type_identifier)
          (function_declarator
            (identifier)
            (parameter_list
              (parameter_declaration
                (type_identifier))))))
      (template_declaration
        (template_parameter_list
          (type_parameter_declaration
            (type_identifier)))
        (requires_clause
          (constraint_disjunction
            (false)
            (true)))
        (comment)
        (declaration
          (type_identifier)
          (function_declarator
            (identifier)
            (parameter_list
              (parameter_declaration
                (type_identifier))))))
      (template_declaration
        (template_parameter_list
          (variadic_type_parameter_declaration
            (type_identifier)))
        (requires_clause
          (fold_expression
            (template_function
              (identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier))))))
        (comment)
        (declaration
          (type_identifier)
          (function_declarator
            (identifier)
            (parameter_list
              (parameter_declaration
                (type_identifier)))))))

================================================================================
Compound requirements
================================================================================

template<typename T> concept C2 =
requires(T x) {
    {*x} -> std::convertible_to<typename T::inner>; // the expression *x must be valid
                                                    // AND the type T::inner must be valid
                                                    // AND the result of *x must be convertible to T::inner
    {x + 1} -> std::same_as<int>; // the expression x + 1 must be valid 
                               // AND std::same_as<decltype((x + 1)), int> must be satisfied
                               // i.e., (x + 1) must be a prvalue of type int
    {x * 1} -> std::convertible_to<T>; // the expression x * 1 must be valid
                                       // AND its result must be convertible to T
};

--------------------------------------------------------------------------------

(translation_unit
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (concept_definition
      (identifier)
      (requires_expression
        (parameter_list
          (parameter_declaration
            (type_identifier)
            (identifier)))
        (requirement_seq
          (compound_requirement
            (pointer_expression
              (identifier))
            (trailing_return_type
              (type_descriptor
                (qualified_identifier
                  (namespace_identifier)
                  (template_type
                    (type_identifier)
                    (template_argument_list
                      (type_descriptor
                        (dependent_type
                          (qualified_identifier
                            (namespace_identifier)
                            (type_identifier))))))))))
          (comment)
          (comment)
          (comment)
          (compound_requirement
            (binary_expression
              (identifier)
              (number_literal))
            (trailing_return_type
              (type_descriptor
                (qualified_identifier
                  (namespace_identifier)
                  (template_type
                    (type_identifier)
                    (template_argument_list
                      (type_descriptor
                        (primitive_type))))))))
          (comment)
          (comment)
          (comment)
          (compound_requirement
            (binary_expression
              (identifier)
              (number_literal))
            (trailing_return_type
              (type_descriptor
                (qualified_identifier
                  (namespace_identifier)
                  (template_type
                    (type_identifier)
                    (template_argument_list
                      (type_descriptor
                        (type_identifier))))))))
          (comment)
          (comment))))))

================================================================================
Nested requirements
================================================================================

template <class T>
concept Semiregular = DefaultConstructible<T> &&
    CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
requires(T a, size_t n) {  
    requires Same<T*, decltype(&a)>;  // nested: "Same<...> evaluates to true"
    { a.~T() } noexcept;  // compound: "a.~T()" is a valid expression that doesn't throw
    requires Same<T*, decltype(new T)>; // nested: "Same<...> evaluates to true"
    requires Same<T*, decltype(new T[n])>; // nested
    { delete new T };  // compound
    { delete new T[n] }; // compound
};
--------------------------------------------------------------------------------

(translation_unit
  (template_declaration
    (template_parameter_list
      (type_parameter_declaration
        (type_identifier)))
    (concept_definition
      (identifier)
      (binary_expression
        (binary_expression
          (binary_expression
            (binary_expression
              (template_function
                (identifier)
                (template_argument_list
                  (type_descriptor
                    (type_identifier))))
              (template_function
                (identifier)
                (template_argument_list
                  (type_descriptor
                    (type_identifier)))))
            (template_function
              (identifier)
              (template_argument_list
                (type_descriptor
                  (type_identifier)))))
          (template_function
            (identifier)
            (template_argument_list
              (type_descriptor
                (type_identifier)))))
        (requires_expression
          (parameter_list
            (parameter_declaration
              (type_identifier)
              (identifier))
            (parameter_declaration
              (primitive_type)
              (identifier)))
          (requirement_seq
            (simple_requirement
              (requires_clause
                (template_type
                  (type_identifier)
                  (template_argument_list
                    (type_descriptor
                      (type_identifier)
                      (abstract_pointer_declarator))
                    (type_descriptor
                      (decltype
                        (pointer_expression
                          (identifier))))))))
            (comment)
            (compound_requirement
              (call_expression
                (field_expression
                  (identifier)
                  (destructor_name
                    (identifier)))
                (argument_list)))
            (comment)
            (simple_requirement
              (requires_clause
                (template_type
                  (type_identifier)
                  (template_argument_list
                    (type_descriptor
                      (type_identifier)
                      (abstract_pointer_declarator))
                    (type_descriptor
                      (decltype
                        (new_expression
                          (type_identifier))))))))
            (comment)
            (simple_requirement
              (requires_clause
                (template_type
                  (type_identifier)
                  (template_argument_list
                    (type_descriptor
                      (type_identifier)
                      (abstract_pointer_declarator))
                    (type_descriptor
                      (decltype
                        (new_expression
                          (type_identifier)
                          (new_declarator
                            (identifier)))))))))
            (comment)
            (compound_requirement
              (delete_expression
                (new_expression
                  (type_identifier))))
            (comment)
            (compound_requirement
              (delete_expression
                (new_expression
                  (type_identifier)
                  (new_declarator
                    (identifier)))))
            (comment)))))))

================================================================================
Constraints
================================================================================

template <EqualityComparable T>
void f(const T&); // constrained function template declaration

void f(const EqualityComparable auto&); // constrained function template declaration

Sortable auto foo = f();
Sortable<T> auto bar = g();
NS::Concept<T> auto baz = h();

Sortable decltype(auto) foo = i();

---

(translation_unit
  (template_declaration
    (template_parameter_list
      (parameter_declaration
        (type_identifier)
        (identifier)))
    (declaration
      (primitive_type)
      (function_declarator
        (identifier)
        (parameter_list
          (parameter_declaration
            (type_qualifier)
            (type_identifier)
            (abstract_reference_declarator))))))
  (comment)
  (declaration
    (primitive_type)
    (function_declarator
      (identifier)
      (parameter_list
        (parameter_declaration
          (type_qualifier)
          (placeholder_type_specifier
            (type_identifier)
            (auto))
          (abstract_reference_declarator)))))
  (comment)
  (declaration
    (placeholder_type_specifier
      (type_identifier)
      (auto))
    (init_declarator
      (identifier)
      (call_expression
        (identifier)
        (argument_list))))
  (declaration
    (placeholder_type_specifier
      (template_type
        (type_identifier)
        (template_argument_list
          (type_descriptor
            (type_identifier))))
      (auto))
    (init_declarator
      (identifier)
      (call_expression
        (identifier)
        (argument_list))))
  (declaration
    (placeholder_type_specifier
      (qualified_identifier
        (namespace_identifier)
        (template_type
          (type_identifier)
          (template_argument_list
            (type_descriptor
              (type_identifier)))))
      (auto))
    (init_declarator
      (identifier)
      (call_expression
        (identifier)
        (argument_list))))
  (declaration
    (placeholder_type_specifier
      (type_identifier)
      (decltype
        (auto)))
    (init_declarator
      (identifier)
      (call_expression
        (identifier)
        (argument_list)))))
