clang 20.0.0 (based on r547379) from build 12806354. Bug: http://b/379133546 Test: N/A Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
388 lines
13 KiB
C++
388 lines
13 KiB
C++
//===- 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;
|
|
enum class TemplateDeductionResult;
|
|
|
|
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;
|
|
|
|
// C++20 [over.match.class.deduct]p5.2:
|
|
// During template argument deduction for the aggregate deduction
|
|
// candidate, the number of elements in a trailing parameter pack is only
|
|
// deduced from the number of remaining function arguments if it is not
|
|
// otherwise deduced.
|
|
bool AggregateDeductionCandidateHasMismatchedArity = false;
|
|
|
|
/// 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();
|
|
|
|
TemplateDeductionResult getResult() const {
|
|
return static_cast<TemplateDeductionResult>(Result);
|
|
}
|
|
};
|
|
|
|
/// 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
|