//===- TemplateDeduction.h - C++ template argument deduction ----*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
// This file provides types used with Sema's template argument deduction
 
// routines.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
 
#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
 
 
 
#include "clang/Sema/Ownership.h"
 
#include "clang/Sema/SemaConcept.h"
 
#include "clang/AST/ASTConcept.h"
 
#include "clang/AST/DeclAccessPair.h"
 
#include "clang/AST/DeclTemplate.h"
 
#include "clang/AST/TemplateBase.h"
 
#include "clang/Basic/PartialDiagnostic.h"
 
#include "clang/Basic/SourceLocation.h"
 
#include "llvm/ADT/SmallVector.h"
 
#include <cassert>
 
#include <cstddef>
 
#include <optional>
 
#include <utility>
 
 
 
namespace clang {
 
 
 
class Decl;
 
struct DeducedPack;
 
class Sema;
 
 
 
namespace sema {
 
 
 
/// Provides information about an attempted template argument
 
/// deduction, whose success or failure was described by a
 
/// TemplateDeductionResult value.
 
class TemplateDeductionInfo {
 
  /// The deduced template argument list.
 
  TemplateArgumentList *DeducedSugared = nullptr, *DeducedCanonical = nullptr;
 
 
 
  /// The source location at which template argument
 
  /// deduction is occurring.
 
  SourceLocation Loc;
 
 
 
  /// Have we suppressed an error during deduction?
 
  bool HasSFINAEDiagnostic = false;
 
 
 
  /// The template parameter depth for which we're performing deduction.
 
  unsigned DeducedDepth;
 
 
 
  /// The number of parameters with explicitly-specified template arguments,
 
  /// up to and including the partially-specified pack (if any).
 
  unsigned ExplicitArgs = 0;
 
 
 
  /// Warnings (and follow-on notes) that were suppressed due to
 
  /// SFINAE while performing template argument deduction.
 
  SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
 
 
 
public:
 
  TemplateDeductionInfo(SourceLocation Loc, unsigned DeducedDepth = 0)
 
      : Loc(Loc), DeducedDepth(DeducedDepth) {}
 
  TemplateDeductionInfo(const TemplateDeductionInfo &) = delete;
 
  TemplateDeductionInfo &operator=(const TemplateDeductionInfo &) = delete;
 
 
 
  enum ForBaseTag { ForBase };
 
  /// Create temporary template deduction info for speculatively deducing
 
  /// against a base class of an argument's type.
 
  TemplateDeductionInfo(ForBaseTag, const TemplateDeductionInfo &Info)
 
      : DeducedSugared(Info.DeducedSugared), Loc(Info.Loc),
 
        DeducedDepth(Info.DeducedDepth), ExplicitArgs(Info.ExplicitArgs) {}
 
 
 
  /// Returns the location at which template argument is
 
  /// occurring.
 
  SourceLocation getLocation() const {
 
    return Loc;
 
  }
 
 
 
  /// The depth of template parameters for which deduction is being
 
  /// performed.
 
  unsigned getDeducedDepth() const {
 
    return DeducedDepth;
 
  }
 
 
 
  /// Get the number of explicitly-specified arguments.
 
  unsigned getNumExplicitArgs() const {
 
    return ExplicitArgs;
 
  }
 
 
 
  /// Take ownership of the deduced template argument lists.
 
  TemplateArgumentList *takeSugared() {
 
    TemplateArgumentList *Result = DeducedSugared;
 
    DeducedSugared = nullptr;
 
    return Result;
 
  }
 
  TemplateArgumentList *takeCanonical() {
 
    TemplateArgumentList *Result = DeducedCanonical;
 
    DeducedCanonical = nullptr;
 
    return Result;
 
  }
 
 
 
  /// Take ownership of the SFINAE diagnostic.
 
  void takeSFINAEDiagnostic(PartialDiagnosticAt &PD) {
 
    assert(HasSFINAEDiagnostic);
 
    PD.first = SuppressedDiagnostics.front().first;
 
    PD.second.swap(SuppressedDiagnostics.front().second);
 
    clearSFINAEDiagnostic();
 
  }
 
 
 
  /// Discard any SFINAE diagnostics.
 
  void clearSFINAEDiagnostic() {
 
    SuppressedDiagnostics.clear();
 
    HasSFINAEDiagnostic = false;
 
  }
 
 
 
  /// Peek at the SFINAE diagnostic.
 
  const PartialDiagnosticAt &peekSFINAEDiagnostic() const {
 
    assert(HasSFINAEDiagnostic);
 
    return SuppressedDiagnostics.front();
 
  }
 
 
 
  /// Provide an initial template argument list that contains the
 
  /// explicitly-specified arguments.
 
  void setExplicitArgs(TemplateArgumentList *NewDeducedSugared,
 
                       TemplateArgumentList *NewDeducedCanonical) {
 
    assert(NewDeducedSugared->size() == NewDeducedCanonical->size());
 
    DeducedSugared = NewDeducedSugared;
 
    DeducedCanonical = NewDeducedCanonical;
 
    ExplicitArgs = DeducedSugared->size();
 
  }
 
 
 
  /// Provide a new template argument list that contains the
 
  /// results of template argument deduction.
 
  void reset(TemplateArgumentList *NewDeducedSugared,
 
             TemplateArgumentList *NewDeducedCanonical) {
 
    DeducedSugared = NewDeducedSugared;
 
    DeducedCanonical = NewDeducedCanonical;
 
  }
 
 
 
  /// Is a SFINAE diagnostic available?
 
  bool hasSFINAEDiagnostic() const {
 
    return HasSFINAEDiagnostic;
 
  }
 
 
 
  /// Set the diagnostic which caused the SFINAE failure.
 
  void addSFINAEDiagnostic(SourceLocation Loc, PartialDiagnostic PD) {
 
    // Only collect the first diagnostic.
 
    if (HasSFINAEDiagnostic)
 
      return;
 
    SuppressedDiagnostics.clear();
 
    SuppressedDiagnostics.emplace_back(Loc, std::move(PD));
 
    HasSFINAEDiagnostic = true;
 
  }
 
 
 
  /// Add a new diagnostic to the set of diagnostics
 
  void addSuppressedDiagnostic(SourceLocation Loc,
 
                               PartialDiagnostic PD) {
 
    if (HasSFINAEDiagnostic)
 
      return;
 
    SuppressedDiagnostics.emplace_back(Loc, std::move(PD));
 
  }
 
 
 
  /// Iterator over the set of suppressed diagnostics.
 
  using diag_iterator = SmallVectorImpl<PartialDiagnosticAt>::const_iterator;
 
 
 
  /// Returns an iterator at the beginning of the sequence of suppressed
 
  /// diagnostics.
 
  diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); }
 
 
 
  /// Returns an iterator at the end of the sequence of suppressed
 
  /// diagnostics.
 
  diag_iterator diag_end() const { return SuppressedDiagnostics.end(); }
 
 
 
  /// The template parameter to which a template argument
 
  /// deduction failure refers.
 
  ///
 
  /// Depending on the result of template argument deduction, this
 
  /// template parameter may have different meanings:
 
  ///
 
  ///   TDK_Incomplete: this is the first template parameter whose
 
  ///   corresponding template argument was not deduced.
 
  ///
 
  ///   TDK_IncompletePack: this is the expanded parameter pack for
 
  ///   which we deduced too few arguments.
 
  ///
 
  ///   TDK_Inconsistent: this is the template parameter for which
 
  ///   two different template argument values were deduced.
 
  TemplateParameter Param;
 
 
 
  /// The first template argument to which the template
 
  /// argument deduction failure refers.
 
  ///
 
  /// Depending on the result of the template argument deduction,
 
  /// this template argument may have different meanings:
 
  ///
 
  ///   TDK_IncompletePack: this is the number of arguments we deduced
 
  ///   for the pack.
 
  ///
 
  ///   TDK_Inconsistent: this argument is the first value deduced
 
  ///   for the corresponding template parameter.
 
  ///
 
  ///   TDK_SubstitutionFailure: this argument is the template
 
  ///   argument we were instantiating when we encountered an error.
 
  ///
 
  ///   TDK_DeducedMismatch: this is the parameter type, after substituting
 
  ///   deduced arguments.
 
  ///
 
  ///   TDK_NonDeducedMismatch: this is the component of the 'parameter'
 
  ///   of the deduction, directly provided in the source code.
 
  TemplateArgument FirstArg;
 
 
 
  /// The second template argument to which the template
 
  /// argument deduction failure refers.
 
  ///
 
  ///   TDK_Inconsistent: this argument is the second value deduced
 
  ///   for the corresponding template parameter.
 
  ///
 
  ///   TDK_DeducedMismatch: this is the (adjusted) call argument type.
 
  ///
 
  ///   TDK_NonDeducedMismatch: this is the mismatching component of the
 
  ///   'argument' of the deduction, from which we are deducing arguments.
 
  ///
 
  /// FIXME: Finish documenting this.
 
  TemplateArgument SecondArg;
 
 
 
  /// The index of the function argument that caused a deduction
 
  /// failure.
 
  ///
 
  ///   TDK_DeducedMismatch: this is the index of the argument that had a
 
  ///   different argument type from its substituted parameter type.
 
  unsigned CallArgIndex = 0;
 
 
 
  /// Information on packs that we're currently expanding.
 
  ///
 
  /// FIXME: This should be kept internal to SemaTemplateDeduction.
 
  SmallVector<DeducedPack *, 8> PendingDeducedPacks;
 
 
 
  /// \brief The constraint satisfaction details resulting from the associated
 
  /// constraints satisfaction tests.
 
  ConstraintSatisfaction AssociatedConstraintsSatisfaction;
 
};
 
 
 
} // namespace sema
 
 
 
/// A structure used to record information about a failed
 
/// template argument deduction, for diagnosis.
 
struct DeductionFailureInfo {
 
  /// A Sema::TemplateDeductionResult.
 
  unsigned Result : 8;
 
 
 
  /// Indicates whether a diagnostic is stored in Diagnostic.
 
  unsigned HasDiagnostic : 1;
 
 
 
  /// Opaque pointer containing additional data about
 
  /// this deduction failure.
 
  void *Data;
 
 
 
  /// A diagnostic indicating why deduction failed.
 
  alignas(PartialDiagnosticAt) char Diagnostic[sizeof(PartialDiagnosticAt)];
 
 
 
  /// Retrieve the diagnostic which caused this deduction failure,
 
  /// if any.
 
  PartialDiagnosticAt *getSFINAEDiagnostic();
 
 
 
  /// Retrieve the template parameter this deduction failure
 
  /// refers to, if any.
 
  TemplateParameter getTemplateParameter();
 
 
 
  /// Retrieve the template argument list associated with this
 
  /// deduction failure, if any.
 
  TemplateArgumentList *getTemplateArgumentList();
 
 
 
  /// Return the first template argument this deduction failure
 
  /// refers to, if any.
 
  const TemplateArgument *getFirstArg();
 
 
 
  /// Return the second template argument this deduction failure
 
  /// refers to, if any.
 
  const TemplateArgument *getSecondArg();
 
 
 
  /// Return the index of the call argument that this deduction
 
  /// failure refers to, if any.
 
  std::optional<unsigned> getCallArgIndex();
 
 
 
  /// Free any memory associated with this deduction failure.
 
  void Destroy();
 
};
 
 
 
/// TemplateSpecCandidate - This is a generalization of OverloadCandidate
 
/// which keeps track of template argument deduction failure info, when
 
/// handling explicit specializations (and instantiations) of templates
 
/// beyond function overloading.
 
/// For now, assume that the candidates are non-matching specializations.
 
/// TODO: In the future, we may need to unify/generalize this with
 
/// OverloadCandidate.
 
struct TemplateSpecCandidate {
 
  /// The declaration that was looked up, together with its access.
 
  /// Might be a UsingShadowDecl, but usually a FunctionTemplateDecl.
 
  DeclAccessPair FoundDecl;
 
 
 
  /// Specialization - The actual specialization that this candidate
 
  /// represents. When NULL, this may be a built-in candidate.
 
  Decl *Specialization;
 
 
 
  /// Template argument deduction info
 
  DeductionFailureInfo DeductionFailure;
 
 
 
  void set(DeclAccessPair Found, Decl *Spec, DeductionFailureInfo Info) {
 
    FoundDecl = Found;
 
    Specialization = Spec;
 
    DeductionFailure = Info;
 
  }
 
 
 
  /// Diagnose a template argument deduction failure.
 
  void NoteDeductionFailure(Sema &S, bool ForTakingAddress);
 
};
 
 
 
/// TemplateSpecCandidateSet - A set of generalized overload candidates,
 
/// used in template specializations.
 
/// TODO: In the future, we may need to unify/generalize this with
 
/// OverloadCandidateSet.
 
class TemplateSpecCandidateSet {
 
  SmallVector<TemplateSpecCandidate, 16> Candidates;
 
  SourceLocation Loc;
 
 
 
  // Stores whether we're taking the address of these candidates. This helps us
 
  // produce better error messages when dealing with the pass_object_size
 
  // attribute on parameters.
 
  bool ForTakingAddress;
 
 
 
  void destroyCandidates();
 
 
 
public:
 
  TemplateSpecCandidateSet(SourceLocation Loc, bool ForTakingAddress = false)
 
      : Loc(Loc), ForTakingAddress(ForTakingAddress) {}
 
  TemplateSpecCandidateSet(const TemplateSpecCandidateSet &) = delete;
 
  TemplateSpecCandidateSet &
 
  operator=(const TemplateSpecCandidateSet &) = delete;
 
  ~TemplateSpecCandidateSet() { destroyCandidates(); }
 
 
 
  SourceLocation getLocation() const { return Loc; }
 
 
 
  /// Clear out all of the candidates.
 
  /// TODO: This may be unnecessary.
 
  void clear();
 
 
 
  using iterator = SmallVector<TemplateSpecCandidate, 16>::iterator;
 
 
 
  iterator begin() { return Candidates.begin(); }
 
  iterator end() { return Candidates.end(); }
 
 
 
  size_t size() const { return Candidates.size(); }
 
  bool empty() const { return Candidates.empty(); }
 
 
 
  /// Add a new candidate with NumConversions conversion sequence slots
 
  /// to the overload set.
 
  TemplateSpecCandidate &addCandidate() {
 
    Candidates.emplace_back();
 
    return Candidates.back();
 
  }
 
 
 
  void NoteCandidates(Sema &S, SourceLocation Loc);
 
 
 
  void NoteCandidates(Sema &S, SourceLocation Loc) const {
 
    const_cast<TemplateSpecCandidateSet *>(this)->NoteCandidates(S, Loc);
 
  }
 
};
 
 
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H