2010-02-09 22:26:47 +00:00
|
|
|
//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
|
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// 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
|
2010-02-09 22:26:47 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements a diagnostic formatting hook for AST elements.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2016-02-10 19:11:58 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
#include "clang/AST/ASTDiagnostic.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2014-06-05 22:10:59 +00:00
|
|
|
#include "clang/AST/ASTLambda.h"
|
2013-12-26 18:30:57 +00:00
|
|
|
#include "clang/AST/Attr.h"
|
2010-02-09 22:26:47 +00:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2012-06-26 18:18:47 +00:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2012-12-04 09:13:33 +00:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
|
|
|
#include "clang/AST/TemplateBase.h"
|
2010-02-09 22:26:47 +00:00
|
|
|
#include "clang/AST/Type.h"
|
2021-06-11 13:19:00 +01:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2010-02-09 22:26:47 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
2010-05-13 11:37:24 +00:00
|
|
|
// Returns a desugared version of the QualType, and marks ShouldAKA as true
|
2023-06-14 09:59:30 +08:00
|
|
|
// whenever we remove significant sugar from the type. Make sure ShouldAKA
|
|
|
|
// is initialized before passing it in.
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
|
|
|
|
bool &ShouldAKA) {
|
2010-05-13 11:37:24 +00:00
|
|
|
QualifierCollector QC;
|
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
while (true) {
|
2010-05-13 11:37:24 +00:00
|
|
|
const Type *Ty = QC.strip(QT);
|
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Don't aka just because we saw an elaborated type...
|
2011-02-20 03:19:35 +00:00
|
|
|
if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) {
|
|
|
|
QT = ET->desugar();
|
2010-02-09 22:26:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-12-20 18:01:33 +01:00
|
|
|
// ... or a using type ...
|
|
|
|
if (const UsingType *UT = dyn_cast<UsingType>(Ty)) {
|
|
|
|
QT = UT->desugar();
|
|
|
|
continue;
|
|
|
|
}
|
2010-12-10 16:29:40 +00:00
|
|
|
// ... or a paren type ...
|
2011-02-20 03:19:35 +00:00
|
|
|
if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
|
|
|
|
QT = PT->desugar();
|
2010-12-10 16:29:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
2019-05-07 03:20:17 +00:00
|
|
|
// ... or a macro defined type ...
|
|
|
|
if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Ty)) {
|
|
|
|
QT = MDT->desugar();
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-20 03:19:35 +00:00
|
|
|
// ...or a substituted template type parameter ...
|
|
|
|
if (const SubstTemplateTypeParmType *ST =
|
|
|
|
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
|
|
|
|
QT = ST->desugar();
|
|
|
|
continue;
|
|
|
|
}
|
2011-03-04 04:00:19 +00:00
|
|
|
// ...or an attributed type...
|
|
|
|
if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) {
|
|
|
|
QT = AT->desugar();
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-05 01:23:43 +00:00
|
|
|
// ...or an adjusted type...
|
|
|
|
if (const AdjustedType *AT = dyn_cast<AdjustedType>(Ty)) {
|
|
|
|
QT = AT->desugar();
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-20 03:19:35 +00:00
|
|
|
// ... or an auto type.
|
|
|
|
if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
|
|
|
|
if (!AT->isSugared())
|
|
|
|
break;
|
|
|
|
QT = AT->desugar();
|
2010-02-09 22:26:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2015-07-16 01:06:17 +00:00
|
|
|
// Desugar FunctionType if return type or any parameter type should be
|
|
|
|
// desugared. Preserve nullability attribute on desugared types.
|
|
|
|
if (const FunctionType *FT = dyn_cast<FunctionType>(Ty)) {
|
|
|
|
bool DesugarReturn = false;
|
|
|
|
QualType SugarRT = FT->getReturnType();
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType RT = desugarForDiagnostic(Context, SugarRT, DesugarReturn);
|
2015-07-16 01:06:17 +00:00
|
|
|
if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) {
|
2024-10-31 04:15:22 -07:00
|
|
|
RT = Context.getAttributedType(*nullability, RT, RT);
|
2015-07-16 01:06:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DesugarArgument = false;
|
|
|
|
SmallVector<QualType, 4> Args;
|
|
|
|
const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT);
|
|
|
|
if (FPT) {
|
|
|
|
for (QualType SugarPT : FPT->param_types()) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType PT = desugarForDiagnostic(Context, SugarPT, DesugarArgument);
|
2015-07-16 01:06:17 +00:00
|
|
|
if (auto nullability =
|
|
|
|
AttributedType::stripOuterNullability(SugarPT)) {
|
2024-10-31 04:15:22 -07:00
|
|
|
PT = Context.getAttributedType(*nullability, PT, PT);
|
2015-07-16 01:06:17 +00:00
|
|
|
}
|
|
|
|
Args.push_back(PT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DesugarReturn || DesugarArgument) {
|
|
|
|
ShouldAKA = true;
|
|
|
|
QT = FPT ? Context.getFunctionType(RT, Args, FPT->getExtProtoInfo())
|
|
|
|
: Context.getFunctionNoProtoType(RT, FT->getExtInfo());
|
2011-05-05 21:57:07 +00:00
|
|
|
break;
|
2015-07-16 01:06:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Desugar template specializations if any template argument should be
|
|
|
|
// desugared.
|
|
|
|
if (const TemplateSpecializationType *TST =
|
|
|
|
dyn_cast<TemplateSpecializationType>(Ty)) {
|
|
|
|
if (!TST->isTypeAlias()) {
|
|
|
|
bool DesugarArgument = false;
|
|
|
|
SmallVector<TemplateArgument, 4> Args;
|
2022-10-24 14:18:46 +02:00
|
|
|
for (const TemplateArgument &Arg : TST->template_arguments()) {
|
2015-07-16 01:06:17 +00:00
|
|
|
if (Arg.getKind() == TemplateArgument::Type)
|
2021-12-08 12:31:00 +08:00
|
|
|
Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
|
|
|
|
DesugarArgument));
|
2015-07-16 01:06:17 +00:00
|
|
|
else
|
|
|
|
Args.push_back(Arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DesugarArgument) {
|
|
|
|
ShouldAKA = true;
|
|
|
|
QT = Context.getTemplateSpecializationType(
|
2025-04-12 14:26:30 -03:00
|
|
|
TST->getTemplateName(), Args, /*CanonicalArgs=*/std::nullopt, QT);
|
2015-07-16 01:06:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2021-12-09 20:12:48 +08:00
|
|
|
if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
|
|
|
|
QualType ElementTy =
|
|
|
|
desugarForDiagnostic(Context, AT->getElementType(), ShouldAKA);
|
|
|
|
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
|
|
|
|
QT = Context.getConstantArrayType(
|
|
|
|
ElementTy, CAT->getSize(), CAT->getSizeExpr(),
|
|
|
|
CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
|
|
|
|
else if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
|
2025-04-14 10:44:25 -03:00
|
|
|
QT = Context.getVariableArrayType(ElementTy, VAT->getSizeExpr(),
|
|
|
|
VAT->getSizeModifier(),
|
|
|
|
VAT->getIndexTypeCVRQualifiers());
|
2021-12-09 20:12:48 +08:00
|
|
|
else if (const auto *DSAT = dyn_cast<DependentSizedArrayType>(AT))
|
|
|
|
QT = Context.getDependentSizedArrayType(
|
|
|
|
ElementTy, DSAT->getSizeExpr(), DSAT->getSizeModifier(),
|
2025-04-14 10:44:25 -03:00
|
|
|
DSAT->getIndexTypeCVRQualifiers());
|
2021-12-09 20:12:48 +08:00
|
|
|
else if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT))
|
|
|
|
QT = Context.getIncompleteArrayType(ElementTy, IAT->getSizeModifier(),
|
|
|
|
IAT->getIndexTypeCVRQualifiers());
|
|
|
|
else
|
|
|
|
llvm_unreachable("Unhandled array type");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Don't desugar magic Objective-C types.
|
|
|
|
if (QualType(Ty,0) == Context.getObjCIdType() ||
|
|
|
|
QualType(Ty,0) == Context.getObjCClassType() ||
|
|
|
|
QualType(Ty,0) == Context.getObjCSelType() ||
|
|
|
|
QualType(Ty,0) == Context.getObjCProtoType())
|
|
|
|
break;
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Don't desugar va_list.
|
2015-09-17 20:55:33 +00:00
|
|
|
if (QualType(Ty, 0) == Context.getBuiltinVaListType() ||
|
|
|
|
QualType(Ty, 0) == Context.getBuiltinMSVaListType())
|
2010-02-09 22:26:47 +00:00
|
|
|
break;
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Otherwise, do a single-step desugar.
|
|
|
|
QualType Underlying;
|
|
|
|
bool IsSugar = false;
|
|
|
|
switch (Ty->getTypeClass()) {
|
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
|
|
|
#define TYPE(Class, Base) \
|
|
|
|
case Type::Class: { \
|
|
|
|
const Class##Type *CTy = cast<Class##Type>(Ty); \
|
|
|
|
if (CTy->isSugared()) { \
|
|
|
|
IsSugar = true; \
|
|
|
|
Underlying = CTy->desugar(); \
|
|
|
|
} \
|
|
|
|
break; \
|
|
|
|
}
|
2019-10-02 06:35:23 +00:00
|
|
|
#include "clang/AST/TypeNodes.inc"
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// If it wasn't sugared, we're done.
|
|
|
|
if (!IsSugar)
|
|
|
|
break;
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// If the desugared type is a vector type, we don't want to expand
|
|
|
|
// it, it will turn into an attribute mess. People want their "vec4".
|
|
|
|
if (isa<VectorType>(Underlying))
|
|
|
|
break;
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Don't desugar through the primary typedef of an anonymous type.
|
2010-09-04 23:16:01 +00:00
|
|
|
if (const TagType *UTT = Underlying->getAs<TagType>())
|
|
|
|
if (const TypedefType *QTT = dyn_cast<TypedefType>(QT))
|
2011-04-15 14:24:37 +00:00
|
|
|
if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl())
|
2010-09-04 23:16:01 +00:00
|
|
|
break;
|
2010-05-13 11:37:24 +00:00
|
|
|
|
|
|
|
// Record that we actually looked through an opaque type here.
|
|
|
|
ShouldAKA = true;
|
2010-02-09 22:26:47 +00:00
|
|
|
QT = Underlying;
|
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
|
|
|
// If we have a pointer-like type, desugar the pointee as well.
|
|
|
|
// FIXME: Handle other pointer-like types.
|
|
|
|
if (const PointerType *Ty = QT->getAs<PointerType>()) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QT = Context.getPointerType(
|
|
|
|
desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
|
2015-07-07 03:57:35 +00:00
|
|
|
} else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QT = Context.getObjCObjectPointerType(
|
|
|
|
desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
|
2010-05-13 11:37:24 +00:00
|
|
|
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QT = Context.getLValueReferenceType(
|
|
|
|
desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
|
2011-01-20 16:08:06 +00:00
|
|
|
} else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QT = Context.getRValueReferenceType(
|
|
|
|
desugarForDiagnostic(Context, Ty->getPointeeType(), ShouldAKA));
|
2015-07-07 03:57:35 +00:00
|
|
|
} else if (const auto *Ty = QT->getAs<ObjCObjectType>()) {
|
|
|
|
if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) {
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType BaseType =
|
|
|
|
desugarForDiagnostic(Context, Ty->getBaseType(), ShouldAKA);
|
|
|
|
QT = Context.getObjCObjectType(
|
|
|
|
BaseType, Ty->getTypeArgsAsWritten(),
|
2023-01-06 16:56:23 +01:00
|
|
|
llvm::ArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
|
2021-12-08 12:31:00 +08:00
|
|
|
Ty->isKindOfTypeAsWritten());
|
2015-07-07 03:57:35 +00:00
|
|
|
}
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-12-10 11:01:00 +00:00
|
|
|
return QC.apply(Context, QT);
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
|
|
|
|
2018-07-30 19:24:48 +00:00
|
|
|
/// Convert the given type to a string suitable for printing as part of
|
2010-05-13 11:37:24 +00:00
|
|
|
/// a diagnostic.
|
|
|
|
///
|
2011-07-11 17:49:21 +00:00
|
|
|
/// There are four main criteria when determining whether we should have an
|
2010-05-13 11:37:24 +00:00
|
|
|
/// a.k.a. clause when pretty-printing a type:
|
|
|
|
///
|
|
|
|
/// 1) Some types provide very minimal sugar that doesn't impede the
|
|
|
|
/// user's understanding --- for example, elaborated type
|
|
|
|
/// specifiers. If this is all the sugar we see, we don't want an
|
|
|
|
/// a.k.a. clause.
|
|
|
|
/// 2) Some types are technically sugared but are much more familiar
|
|
|
|
/// when seen in their sugared form --- for example, va_list,
|
|
|
|
/// vector types, and the magic Objective C types. We don't
|
|
|
|
/// want to desugar these, even if we do produce an a.k.a. clause.
|
|
|
|
/// 3) Some types may have already been desugared previously in this diagnostic.
|
|
|
|
/// if this is the case, doing another "aka" would just be clutter.
|
2011-07-11 17:49:21 +00:00
|
|
|
/// 4) Two different types within the same diagnostic have the same output
|
|
|
|
/// string. In this case, force an a.k.a with the desugared type when
|
|
|
|
/// doing so will provide additional information.
|
2010-02-09 22:26:47 +00:00
|
|
|
///
|
|
|
|
/// \param Context the context in which the type was allocated
|
|
|
|
/// \param Ty the type to print
|
2011-07-11 17:49:21 +00:00
|
|
|
/// \param QualTypeVals pointer values to QualTypes which are used in the
|
|
|
|
/// diagnostic message
|
2010-02-09 22:26:47 +00:00
|
|
|
static std::string
|
|
|
|
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
|
2014-06-12 05:32:27 +00:00
|
|
|
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
|
|
|
|
ArrayRef<intptr_t> QualTypeVals) {
|
2010-02-09 22:26:47 +00:00
|
|
|
// FIXME: Playing with std::string is really slow.
|
2011-07-11 17:49:21 +00:00
|
|
|
bool ForceAKA = false;
|
|
|
|
QualType CanTy = Ty.getCanonicalType();
|
2011-09-27 22:38:19 +00:00
|
|
|
std::string S = Ty.getAsString(Context.getPrintingPolicy());
|
|
|
|
std::string CanS = CanTy.getAsString(Context.getPrintingPolicy());
|
2011-07-11 17:49:21 +00:00
|
|
|
|
2022-03-29 15:24:48 +08:00
|
|
|
for (const intptr_t &QualTypeVal : QualTypeVals) {
|
2011-07-11 17:49:21 +00:00
|
|
|
QualType CompareTy =
|
2022-03-29 15:24:48 +08:00
|
|
|
QualType::getFromOpaquePtr(reinterpret_cast<void *>(QualTypeVal));
|
2012-03-09 08:00:36 +00:00
|
|
|
if (CompareTy.isNull())
|
|
|
|
continue;
|
2011-07-11 17:49:21 +00:00
|
|
|
if (CompareTy == Ty)
|
|
|
|
continue; // Same types
|
|
|
|
QualType CompareCanTy = CompareTy.getCanonicalType();
|
|
|
|
if (CompareCanTy == CanTy)
|
|
|
|
continue; // Same canonical types
|
2011-09-27 22:38:19 +00:00
|
|
|
std::string CompareS = CompareTy.getAsString(Context.getPrintingPolicy());
|
2015-07-08 18:32:26 +00:00
|
|
|
bool ShouldAKA = false;
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType CompareDesugar =
|
|
|
|
desugarForDiagnostic(Context, CompareTy, ShouldAKA);
|
2011-11-14 19:39:25 +00:00
|
|
|
std::string CompareDesugarStr =
|
|
|
|
CompareDesugar.getAsString(Context.getPrintingPolicy());
|
|
|
|
if (CompareS != S && CompareDesugarStr != S)
|
|
|
|
continue; // The type string is different than the comparison string
|
|
|
|
// and the desugared comparison string.
|
|
|
|
std::string CompareCanS =
|
|
|
|
CompareCanTy.getAsString(Context.getPrintingPolicy());
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2011-07-11 17:49:21 +00:00
|
|
|
if (CompareCanS == CanS)
|
|
|
|
continue; // No new info from canonical type
|
|
|
|
|
|
|
|
ForceAKA = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
|
|
|
// Check to see if we already desugared this type in this
|
|
|
|
// diagnostic. If so, don't do it again.
|
|
|
|
bool Repeated = false;
|
2022-03-29 15:24:48 +08:00
|
|
|
for (const auto &PrevArg : PrevArgs) {
|
2010-05-13 11:37:24 +00:00
|
|
|
// TODO: Handle ak_declcontext case.
|
2022-03-29 15:24:48 +08:00
|
|
|
if (PrevArg.first == DiagnosticsEngine::ak_qualtype) {
|
|
|
|
QualType PrevTy(
|
|
|
|
QualType::getFromOpaquePtr(reinterpret_cast<void *>(PrevArg.second)));
|
2010-05-13 11:37:24 +00:00
|
|
|
if (PrevTy == Ty) {
|
|
|
|
Repeated = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
// Consider producing an a.k.a. clause if removing all the direct
|
|
|
|
// sugar gives us something "significantly different".
|
2010-05-13 11:37:24 +00:00
|
|
|
if (!Repeated) {
|
|
|
|
bool ShouldAKA = false;
|
2021-12-08 12:31:00 +08:00
|
|
|
QualType DesugaredTy = desugarForDiagnostic(Context, Ty, ShouldAKA);
|
2011-07-11 17:49:21 +00:00
|
|
|
if (ShouldAKA || ForceAKA) {
|
|
|
|
if (DesugaredTy == Ty) {
|
|
|
|
DesugaredTy = Ty.getCanonicalType();
|
|
|
|
}
|
2011-09-27 22:38:19 +00:00
|
|
|
std::string akaStr = DesugaredTy.getAsString(Context.getPrintingPolicy());
|
2011-07-11 17:49:21 +00:00
|
|
|
if (akaStr != S) {
|
|
|
|
S = "'" + S + "' (aka '" + akaStr + "')";
|
|
|
|
return S;
|
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
}
|
2014-04-25 20:41:38 +00:00
|
|
|
|
|
|
|
// Give some additional info on vector types. These are either not desugared
|
|
|
|
// or displaying complex __attribute__ expressions so add details of the
|
|
|
|
// type and element count.
|
2020-01-13 14:54:02 +00:00
|
|
|
if (const auto *VTy = Ty->getAs<VectorType>()) {
|
2014-04-25 20:41:38 +00:00
|
|
|
std::string DecoratedString;
|
|
|
|
llvm::raw_string_ostream OS(DecoratedString);
|
|
|
|
const char *Values = VTy->getNumElements() > 1 ? "values" : "value";
|
|
|
|
OS << "'" << S << "' (vector of " << VTy->getNumElements() << " '"
|
|
|
|
<< VTy->getElementType().getAsString(Context.getPrintingPolicy())
|
|
|
|
<< "' " << Values << ")";
|
2021-12-09 14:52:30 -08:00
|
|
|
return DecoratedString;
|
2014-04-25 20:41:38 +00:00
|
|
|
}
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
2010-05-13 11:37:24 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
S = "'" + S + "'";
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
|
|
|
|
QualType ToType, bool PrintTree,
|
|
|
|
bool PrintFromType, bool ElideType,
|
2013-02-22 16:08:12 +00:00
|
|
|
bool ShowColors, raw_ostream &OS);
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2011-07-11 17:49:21 +00:00
|
|
|
void clang::FormatASTNodeDiagnosticArgument(
|
2011-09-25 23:23:43 +00:00
|
|
|
DiagnosticsEngine::ArgumentKind Kind,
|
2011-07-11 17:49:21 +00:00
|
|
|
intptr_t Val,
|
2014-06-12 05:32:35 +00:00
|
|
|
StringRef Modifier,
|
|
|
|
StringRef Argument,
|
2014-06-12 05:32:27 +00:00
|
|
|
ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
|
2011-07-23 10:55:15 +00:00
|
|
|
SmallVectorImpl<char> &Output,
|
2011-07-11 17:49:21 +00:00
|
|
|
void *Cookie,
|
2012-02-22 09:51:33 +00:00
|
|
|
ArrayRef<intptr_t> QualTypeVals) {
|
2010-02-09 22:26:47 +00:00
|
|
|
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2013-02-22 15:46:08 +00:00
|
|
|
size_t OldEnd = Output.size();
|
|
|
|
llvm::raw_svector_ostream OS(Output);
|
2010-02-09 22:26:47 +00:00
|
|
|
bool NeedQuotes = true;
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
switch (Kind) {
|
2011-09-23 05:06:16 +00:00
|
|
|
default: llvm_unreachable("unknown ArgumentKind");
|
2019-12-13 12:30:59 +00:00
|
|
|
case DiagnosticsEngine::ak_addrspace: {
|
|
|
|
assert(Modifier.empty() && Argument.empty() &&
|
2022-03-08 11:06:18 +00:00
|
|
|
"Invalid modifier for Qualifiers argument");
|
2019-12-13 12:30:59 +00:00
|
|
|
|
|
|
|
auto S = Qualifiers::getAddrSpaceAsString(static_cast<LangAS>(Val));
|
|
|
|
if (S.empty()) {
|
|
|
|
OS << (Context.getLangOpts().OpenCL ? "default" : "generic");
|
|
|
|
OS << " address space";
|
|
|
|
} else {
|
|
|
|
OS << "address space";
|
|
|
|
OS << " '" << S << "'";
|
|
|
|
}
|
|
|
|
NeedQuotes = false;
|
|
|
|
break;
|
|
|
|
}
|
2019-01-04 11:50:36 +00:00
|
|
|
case DiagnosticsEngine::ak_qual: {
|
|
|
|
assert(Modifier.empty() && Argument.empty() &&
|
2022-03-08 11:06:18 +00:00
|
|
|
"Invalid modifier for Qualifiers argument");
|
2019-01-04 11:50:36 +00:00
|
|
|
|
|
|
|
Qualifiers Q(Qualifiers::fromOpaqueValue(Val));
|
|
|
|
auto S = Q.getAsString();
|
|
|
|
if (S.empty()) {
|
|
|
|
OS << "unqualified";
|
|
|
|
NeedQuotes = false;
|
|
|
|
} else {
|
2019-12-13 12:30:59 +00:00
|
|
|
OS << S;
|
2019-01-04 11:50:36 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
case DiagnosticsEngine::ak_qualtype_pair: {
|
2012-07-10 01:46:04 +00:00
|
|
|
TemplateDiffTypes &TDT = *reinterpret_cast<TemplateDiffTypes*>(Val);
|
2012-06-26 18:18:47 +00:00
|
|
|
QualType FromType =
|
|
|
|
QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.FromType));
|
|
|
|
QualType ToType =
|
|
|
|
QualType::getFromOpaquePtr(reinterpret_cast<void*>(TDT.ToType));
|
|
|
|
|
|
|
|
if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree,
|
|
|
|
TDT.PrintFromType, TDT.ElideType,
|
2013-02-22 16:08:12 +00:00
|
|
|
TDT.ShowColors, OS)) {
|
2012-06-26 18:18:47 +00:00
|
|
|
NeedQuotes = !TDT.PrintTree;
|
2012-07-10 01:46:04 +00:00
|
|
|
TDT.TemplateDiffUsed = true;
|
2012-06-26 18:18:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't fall-back during tree printing. The caller will handle
|
|
|
|
// this case.
|
|
|
|
if (TDT.PrintTree)
|
|
|
|
return;
|
|
|
|
|
2013-02-22 15:46:08 +00:00
|
|
|
// Attempting to do a template diff on non-templates. Set the variables
|
2012-06-26 18:18:47 +00:00
|
|
|
// and continue with regular type printing of the appropriate type.
|
|
|
|
Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType;
|
2014-06-12 05:32:35 +00:00
|
|
|
Modifier = StringRef();
|
|
|
|
Argument = StringRef();
|
2012-06-26 18:18:47 +00:00
|
|
|
// Fall through
|
2022-08-08 09:12:46 -07:00
|
|
|
[[fallthrough]];
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
2011-09-25 23:23:43 +00:00
|
|
|
case DiagnosticsEngine::ak_qualtype: {
|
2014-06-12 05:32:35 +00:00
|
|
|
assert(Modifier.empty() && Argument.empty() &&
|
2010-02-09 22:26:47 +00:00
|
|
|
"Invalid modifier for QualType argument");
|
2018-07-30 19:24:48 +00:00
|
|
|
|
2010-02-09 22:26:47 +00:00
|
|
|
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
|
2014-06-12 05:32:27 +00:00
|
|
|
OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, QualTypeVals);
|
2010-02-09 22:26:47 +00:00
|
|
|
NeedQuotes = false;
|
|
|
|
break;
|
|
|
|
}
|
2011-09-25 23:23:43 +00:00
|
|
|
case DiagnosticsEngine::ak_declarationname: {
|
2014-06-12 05:32:35 +00:00
|
|
|
if (Modifier == "objcclass" && Argument.empty())
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << '+';
|
2014-06-12 05:32:35 +00:00
|
|
|
else if (Modifier == "objcinstance" && Argument.empty())
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << '-';
|
2010-02-09 22:26:47 +00:00
|
|
|
else
|
2014-06-12 05:32:35 +00:00
|
|
|
assert(Modifier.empty() && Argument.empty() &&
|
2010-02-09 22:26:47 +00:00
|
|
|
"Invalid modifier for DeclarationName argument");
|
2013-02-22 15:46:08 +00:00
|
|
|
|
2013-05-14 21:04:00 +00:00
|
|
|
OS << DeclarationName::getFromOpaqueInteger(Val);
|
2010-02-09 22:26:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-09-25 23:23:43 +00:00
|
|
|
case DiagnosticsEngine::ak_nameddecl: {
|
2010-02-09 22:26:47 +00:00
|
|
|
bool Qualified;
|
2014-06-12 05:32:35 +00:00
|
|
|
if (Modifier == "q" && Argument.empty())
|
2010-02-09 22:26:47 +00:00
|
|
|
Qualified = true;
|
|
|
|
else {
|
2014-06-12 05:32:35 +00:00
|
|
|
assert(Modifier.empty() && Argument.empty() &&
|
2010-02-09 22:26:47 +00:00
|
|
|
"Invalid modifier for NamedDecl* argument");
|
|
|
|
Qualified = false;
|
|
|
|
}
|
2011-08-31 09:01:53 +00:00
|
|
|
const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val);
|
2013-02-22 15:46:01 +00:00
|
|
|
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified);
|
2010-02-09 22:26:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-09-25 23:23:43 +00:00
|
|
|
case DiagnosticsEngine::ak_nestednamespec: {
|
2013-02-22 15:46:08 +00:00
|
|
|
NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
|
2025-03-10 09:37:38 -03:00
|
|
|
NNS->print(OS, Context.getPrintingPolicy(),
|
|
|
|
/*ResolveTemplateArguments=*/false,
|
|
|
|
/*PrintFinalScopeResOp=*/false);
|
2010-02-09 22:26:47 +00:00
|
|
|
break;
|
|
|
|
}
|
2011-09-25 23:23:43 +00:00
|
|
|
case DiagnosticsEngine::ak_declcontext: {
|
2010-02-09 22:26:47 +00:00
|
|
|
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
|
|
|
|
assert(DC && "Should never have a null declaration context");
|
2014-06-05 22:10:59 +00:00
|
|
|
NeedQuotes = false;
|
|
|
|
|
2014-08-27 03:05:19 +00:00
|
|
|
// FIXME: Get the strings for DeclContext from some localized place
|
2010-02-09 22:26:47 +00:00
|
|
|
if (DC->isTranslationUnit()) {
|
2012-03-11 07:00:24 +00:00
|
|
|
if (Context.getLangOpts().CPlusPlus)
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << "the global namespace";
|
2010-02-09 22:26:47 +00:00
|
|
|
else
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << "the global scope";
|
2014-08-27 03:05:19 +00:00
|
|
|
} else if (DC->isClosure()) {
|
|
|
|
OS << "block literal";
|
|
|
|
} else if (isLambdaCallOperator(DC)) {
|
|
|
|
OS << "lambda expression";
|
2010-02-09 22:26:47 +00:00
|
|
|
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << ConvertTypeToDiagnosticString(Context,
|
|
|
|
Context.getTypeDeclType(Type),
|
2014-06-12 05:32:27 +00:00
|
|
|
PrevArgs, QualTypeVals);
|
2010-02-09 22:26:47 +00:00
|
|
|
} else {
|
2014-08-27 03:05:19 +00:00
|
|
|
assert(isa<NamedDecl>(DC) && "Expected a NamedDecl");
|
2010-02-09 22:26:47 +00:00
|
|
|
NamedDecl *ND = cast<NamedDecl>(DC);
|
|
|
|
if (isa<NamespaceDecl>(ND))
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << "namespace ";
|
2010-02-09 22:26:47 +00:00
|
|
|
else if (isa<ObjCMethodDecl>(ND))
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << "method ";
|
2010-02-09 22:26:47 +00:00
|
|
|
else if (isa<FunctionDecl>(ND))
|
2013-02-22 15:46:08 +00:00
|
|
|
OS << "function ";
|
|
|
|
|
|
|
|
OS << '\'';
|
|
|
|
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true);
|
|
|
|
OS << '\'';
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2014-03-02 18:46:05 +00:00
|
|
|
case DiagnosticsEngine::ak_attr: {
|
|
|
|
const Attr *At = reinterpret_cast<Attr *>(Val);
|
|
|
|
assert(At && "Received null Attr object!");
|
|
|
|
OS << '\'' << At->getSpelling() << '\'';
|
|
|
|
NeedQuotes = false;
|
|
|
|
break;
|
|
|
|
}
|
2025-04-07 23:19:32 -03:00
|
|
|
case DiagnosticsEngine::ak_expr: {
|
|
|
|
const Expr *E = reinterpret_cast<Expr *>(Val);
|
|
|
|
assert(E && "Received null Expr!");
|
|
|
|
E->printPretty(OS, /*Helper=*/nullptr, Context.getPrintingPolicy());
|
|
|
|
break;
|
|
|
|
}
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
2013-02-22 15:46:08 +00:00
|
|
|
|
|
|
|
if (NeedQuotes) {
|
|
|
|
Output.insert(Output.begin()+OldEnd, '\'');
|
2010-02-09 22:26:47 +00:00
|
|
|
Output.push_back('\'');
|
2013-02-22 15:46:08 +00:00
|
|
|
}
|
2010-02-09 22:26:47 +00:00
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// TemplateDiff - A class that constructs a pretty string for a pair of
|
|
|
|
/// QualTypes. For the pair of types, a diff tree will be created containing
|
|
|
|
/// all the information about the templates and template arguments. Afterwards,
|
|
|
|
/// the tree is transformed to a string according to the options passed in.
|
|
|
|
namespace {
|
|
|
|
class TemplateDiff {
|
|
|
|
/// Context - The ASTContext which is used for comparing template arguments.
|
|
|
|
ASTContext &Context;
|
|
|
|
|
|
|
|
/// Policy - Used during expression printing.
|
|
|
|
PrintingPolicy Policy;
|
|
|
|
|
|
|
|
/// ElideType - Option to elide identical types.
|
|
|
|
bool ElideType;
|
|
|
|
|
|
|
|
/// PrintTree - Format output string as a tree.
|
|
|
|
bool PrintTree;
|
|
|
|
|
|
|
|
/// ShowColor - Diagnostics support color, so bolding will be used.
|
|
|
|
bool ShowColor;
|
|
|
|
|
2016-01-15 05:48:38 +00:00
|
|
|
/// FromTemplateType - When single type printing is selected, this is the
|
2022-11-08 07:21:23 -05:00
|
|
|
/// type to be printed. When tree printing is selected, this type will
|
2016-01-15 05:48:38 +00:00
|
|
|
/// show up first in the tree.
|
|
|
|
QualType FromTemplateType;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-15 05:48:38 +00:00
|
|
|
/// ToTemplateType - The type that FromType is compared to. Only in tree
|
|
|
|
/// printing will this type be outputed.
|
|
|
|
QualType ToTemplateType;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// OS - The stream used to construct the output strings.
|
2013-02-22 16:08:12 +00:00
|
|
|
raw_ostream &OS;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// IsBold - Keeps track of the bold formatting for the output string.
|
|
|
|
bool IsBold;
|
|
|
|
|
|
|
|
/// DiffTree - A tree representation the differences between two types.
|
|
|
|
class DiffTree {
|
2013-03-15 20:35:18 +00:00
|
|
|
public:
|
2016-01-14 22:56:39 +00:00
|
|
|
/// DiffKind - The difference in a DiffNode. Fields of
|
|
|
|
/// TemplateArgumentInfo needed by each difference can be found in the
|
|
|
|
/// Set* and Get* functions.
|
2013-03-15 20:35:18 +00:00
|
|
|
enum DiffKind {
|
|
|
|
/// Incomplete or invalid node.
|
|
|
|
Invalid,
|
2016-02-02 00:36:59 +00:00
|
|
|
/// Another level of templates
|
2013-03-15 20:35:18 +00:00
|
|
|
Template,
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Type difference, all type differences except those falling under
|
|
|
|
/// the Template difference.
|
2013-03-15 20:35:18 +00:00
|
|
|
Type,
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Expression difference, this is only when both arguments are
|
|
|
|
/// expressions. If one argument is an expression and the other is
|
|
|
|
/// Integer or Declaration, then use that diff type instead.
|
2013-03-15 20:35:18 +00:00
|
|
|
Expression,
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Template argument difference
|
2013-03-15 20:35:18 +00:00
|
|
|
TemplateTemplate,
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Integer difference
|
2013-03-15 20:35:18 +00:00
|
|
|
Integer,
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Declaration difference, nullptr arguments are included here
|
2016-01-15 05:01:53 +00:00
|
|
|
Declaration,
|
|
|
|
/// One argument being integer and the other being declaration
|
|
|
|
FromIntegerAndToDeclaration,
|
|
|
|
FromDeclarationAndToInteger
|
2013-03-15 20:35:18 +00:00
|
|
|
};
|
2016-01-14 22:56:39 +00:00
|
|
|
|
2013-03-15 20:35:18 +00:00
|
|
|
private:
|
2016-01-14 22:56:39 +00:00
|
|
|
/// TemplateArgumentInfo - All the information needed to pretty print
|
|
|
|
/// a template argument. See the Set* and Get* functions to see which
|
|
|
|
/// fields are used for each DiffKind.
|
|
|
|
struct TemplateArgumentInfo {
|
|
|
|
QualType ArgType;
|
|
|
|
Qualifiers Qual;
|
|
|
|
llvm::APSInt Val;
|
|
|
|
bool IsValidInt = false;
|
|
|
|
Expr *ArgExpr = nullptr;
|
|
|
|
TemplateDecl *TD = nullptr;
|
|
|
|
ValueDecl *VD = nullptr;
|
|
|
|
bool NeedAddressOf = false;
|
|
|
|
bool IsNullPtr = false;
|
|
|
|
bool IsDefault = false;
|
|
|
|
};
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// DiffNode - The root node stores the original type. Each child node
|
|
|
|
/// stores template arguments of their parents. For templated types, the
|
|
|
|
/// template decl is also stored.
|
|
|
|
struct DiffNode {
|
2016-01-14 22:56:39 +00:00
|
|
|
DiffKind Kind = Invalid;
|
2013-03-15 20:35:18 +00:00
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// NextNode - The index of the next sibling node or 0.
|
2016-01-14 22:56:39 +00:00
|
|
|
unsigned NextNode = 0;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// ChildNode - The index of the first child node or 0.
|
2016-01-14 22:56:39 +00:00
|
|
|
unsigned ChildNode = 0;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// ParentNode - The index of the parent node.
|
2016-01-14 22:56:39 +00:00
|
|
|
unsigned ParentNode = 0;
|
2013-02-27 01:41:53 +00:00
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
TemplateArgumentInfo FromArgInfo, ToArgInfo;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// Same - Whether the two arguments evaluate to the same value.
|
2016-01-14 22:56:39 +00:00
|
|
|
bool Same = false;
|
|
|
|
|
|
|
|
DiffNode(unsigned ParentNode = 0) : ParentNode(ParentNode) {}
|
2012-06-26 18:18:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// FlatTree - A flattened tree used to store the DiffNodes.
|
2013-01-12 19:30:44 +00:00
|
|
|
SmallVector<DiffNode, 16> FlatTree;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// CurrentNode - The index of the current node being used.
|
|
|
|
unsigned CurrentNode;
|
|
|
|
|
|
|
|
/// NextFreeNode - The index of the next unused node. Used when creating
|
|
|
|
/// child nodes.
|
|
|
|
unsigned NextFreeNode;
|
|
|
|
|
|
|
|
/// ReadNode - The index of the current node being read.
|
|
|
|
unsigned ReadNode;
|
2016-01-14 22:56:39 +00:00
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
public:
|
2020-01-13 14:55:51 +00:00
|
|
|
DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) {
|
2012-06-26 18:18:47 +00:00
|
|
|
FlatTree.push_back(DiffNode());
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
// Node writing functions, one for each valid DiffKind element.
|
|
|
|
void SetTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
|
|
|
|
Qualifiers FromQual, Qualifiers ToQual,
|
|
|
|
bool FromDefault, bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = Template;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.Qual = FromQual;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.Qual = ToQual;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetTypeDiff(QualType FromType, QualType ToType, bool FromDefault,
|
|
|
|
bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = Type;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromType;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToType;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
void SetExpressionDiff(Expr *FromExpr, Expr *ToExpr, bool FromDefault,
|
|
|
|
bool ToDefault) {
|
2016-01-14 22:56:39 +00:00
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = Expression;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetTemplateTemplateDiff(TemplateDecl *FromTD, TemplateDecl *ToTD,
|
|
|
|
bool FromDefault, bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = TemplateTemplate;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.TD = FromTD;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.TD = ToTD;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
2016-06-15 14:20:56 +00:00
|
|
|
void SetIntegerDiff(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt,
|
2016-01-14 22:56:39 +00:00
|
|
|
bool IsValidFromInt, bool IsValidToInt,
|
2016-01-15 02:55:17 +00:00
|
|
|
QualType FromIntType, QualType ToIntType,
|
2016-01-14 22:56:39 +00:00
|
|
|
Expr *FromExpr, Expr *ToExpr, bool FromDefault,
|
|
|
|
bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = Integer;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
|
2016-01-15 02:55:17 +00:00
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
|
2016-01-14 22:56:39 +00:00
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetDeclarationDiff(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
|
|
|
|
bool FromAddressOf, bool ToAddressOf,
|
2016-01-15 01:08:56 +00:00
|
|
|
bool FromNullPtr, bool ToNullPtr, Expr *FromExpr,
|
|
|
|
Expr *ToExpr, bool FromDefault, bool ToDefault) {
|
2016-01-14 22:56:39 +00:00
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = Declaration;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
|
2016-01-15 01:08:56 +00:00
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
|
2016-01-14 22:56:39 +00:00
|
|
|
SetDefault(FromDefault, ToDefault);
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 05:01:53 +00:00
|
|
|
void SetFromDeclarationAndToIntegerDiff(
|
|
|
|
ValueDecl *FromValueDecl, bool FromAddressOf, bool FromNullPtr,
|
2016-06-15 14:20:56 +00:00
|
|
|
Expr *FromExpr, const llvm::APSInt &ToInt, bool IsValidToInt,
|
2016-01-15 05:01:53 +00:00
|
|
|
QualType ToIntType, Expr *ToExpr, bool FromDefault, bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = FromDeclarationAndToInteger;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.VD = FromValueDecl;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.NeedAddressOf = FromAddressOf;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.IsNullPtr = FromNullPtr;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.Val = ToInt;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.IsValidInt = IsValidToInt;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgType = ToIntType;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetFromIntegerAndToDeclarationDiff(
|
2016-06-15 14:20:56 +00:00
|
|
|
const llvm::APSInt &FromInt, bool IsValidFromInt, QualType FromIntType,
|
2016-01-15 05:01:53 +00:00
|
|
|
Expr *FromExpr, ValueDecl *ToValueDecl, bool ToAddressOf,
|
|
|
|
bool ToNullPtr, Expr *ToExpr, bool FromDefault, bool ToDefault) {
|
|
|
|
assert(FlatTree[CurrentNode].Kind == Invalid && "Node is not empty.");
|
|
|
|
FlatTree[CurrentNode].Kind = FromIntegerAndToDeclaration;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.Val = FromInt;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.IsValidInt = IsValidFromInt;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgType = FromIntType;
|
|
|
|
FlatTree[CurrentNode].FromArgInfo.ArgExpr = FromExpr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.VD = ToValueDecl;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.NeedAddressOf = ToAddressOf;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.IsNullPtr = ToNullPtr;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.ArgExpr = ToExpr;
|
|
|
|
SetDefault(FromDefault, ToDefault);
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
/// SetDefault - Sets FromDefault and ToDefault flags of the current node.
|
|
|
|
void SetDefault(bool FromDefault, bool ToDefault) {
|
2016-01-15 05:57:41 +00:00
|
|
|
assert((!FromDefault || !ToDefault) && "Both arguments cannot be default.");
|
2016-01-14 22:56:39 +00:00
|
|
|
FlatTree[CurrentNode].FromArgInfo.IsDefault = FromDefault;
|
|
|
|
FlatTree[CurrentNode].ToArgInfo.IsDefault = ToDefault;
|
2013-02-27 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// SetSame - Sets the same flag of the current node.
|
|
|
|
void SetSame(bool Same) {
|
|
|
|
FlatTree[CurrentNode].Same = Same;
|
|
|
|
}
|
|
|
|
|
2013-03-15 20:35:18 +00:00
|
|
|
/// SetKind - Sets the current node's type.
|
|
|
|
void SetKind(DiffKind Kind) {
|
|
|
|
FlatTree[CurrentNode].Kind = Kind;
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// Up - Changes the node to the parent of the current node.
|
|
|
|
void Up() {
|
2016-01-15 05:48:38 +00:00
|
|
|
assert(FlatTree[CurrentNode].Kind != Invalid &&
|
|
|
|
"Cannot exit node before setting node information.");
|
2012-06-26 18:18:47 +00:00
|
|
|
CurrentNode = FlatTree[CurrentNode].ParentNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AddNode - Adds a child node to the current node, then sets that node
|
|
|
|
/// node as the current node.
|
|
|
|
void AddNode() {
|
2016-01-15 05:48:38 +00:00
|
|
|
assert(FlatTree[CurrentNode].Kind == Template &&
|
|
|
|
"Only Template nodes can have children nodes.");
|
2012-06-26 18:18:47 +00:00
|
|
|
FlatTree.push_back(DiffNode(CurrentNode));
|
|
|
|
DiffNode &Node = FlatTree[CurrentNode];
|
|
|
|
if (Node.ChildNode == 0) {
|
|
|
|
// If a child node doesn't exist, add one.
|
|
|
|
Node.ChildNode = NextFreeNode;
|
|
|
|
} else {
|
|
|
|
// If a child node exists, find the last child node and add a
|
|
|
|
// next node to it.
|
|
|
|
unsigned i;
|
|
|
|
for (i = Node.ChildNode; FlatTree[i].NextNode != 0;
|
|
|
|
i = FlatTree[i].NextNode) {
|
|
|
|
}
|
|
|
|
FlatTree[i].NextNode = NextFreeNode;
|
|
|
|
}
|
|
|
|
CurrentNode = NextFreeNode;
|
|
|
|
++NextFreeNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Node reading functions.
|
|
|
|
/// StartTraverse - Prepares the tree for recursive traversal.
|
|
|
|
void StartTraverse() {
|
|
|
|
ReadNode = 0;
|
|
|
|
CurrentNode = NextFreeNode;
|
|
|
|
NextFreeNode = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parent - Move the current read node to its parent.
|
|
|
|
void Parent() {
|
|
|
|
ReadNode = FlatTree[ReadNode].ParentNode;
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
void GetTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD,
|
|
|
|
Qualifiers &FromQual, Qualifiers &ToQual) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == Template && "Unexpected kind.");
|
|
|
|
FromTD = FlatTree[ReadNode].FromArgInfo.TD;
|
|
|
|
ToTD = FlatTree[ReadNode].ToArgInfo.TD;
|
|
|
|
FromQual = FlatTree[ReadNode].FromArgInfo.Qual;
|
|
|
|
ToQual = FlatTree[ReadNode].ToArgInfo.Qual;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
void GetTypeDiff(QualType &FromType, QualType &ToType) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == Type && "Unexpected kind");
|
|
|
|
FromType = FlatTree[ReadNode].FromArgInfo.ArgType;
|
|
|
|
ToType = FlatTree[ReadNode].ToArgInfo.ArgType;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
void GetExpressionDiff(Expr *&FromExpr, Expr *&ToExpr) {
|
2016-01-14 22:56:39 +00:00
|
|
|
assert(FlatTree[ReadNode].Kind == Expression && "Unexpected kind");
|
|
|
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
|
|
|
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
void GetTemplateTemplateDiff(TemplateDecl *&FromTD, TemplateDecl *&ToTD) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == TemplateTemplate && "Unexpected kind.");
|
|
|
|
FromTD = FlatTree[ReadNode].FromArgInfo.TD;
|
|
|
|
ToTD = FlatTree[ReadNode].ToArgInfo.TD;
|
2012-11-01 21:29:28 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
void GetIntegerDiff(llvm::APSInt &FromInt, llvm::APSInt &ToInt,
|
|
|
|
bool &IsValidFromInt, bool &IsValidToInt,
|
2016-01-15 02:55:17 +00:00
|
|
|
QualType &FromIntType, QualType &ToIntType,
|
2016-01-14 22:56:39 +00:00
|
|
|
Expr *&FromExpr, Expr *&ToExpr) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == Integer && "Unexpected kind.");
|
|
|
|
FromInt = FlatTree[ReadNode].FromArgInfo.Val;
|
|
|
|
ToInt = FlatTree[ReadNode].ToArgInfo.Val;
|
|
|
|
IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
|
|
|
|
IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
|
2016-01-15 02:55:17 +00:00
|
|
|
FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
|
|
|
|
ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
|
2016-01-14 22:56:39 +00:00
|
|
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
|
|
|
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
|
2012-09-28 20:32:51 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
void GetDeclarationDiff(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
|
|
|
|
bool &FromAddressOf, bool &ToAddressOf,
|
2016-01-15 01:08:56 +00:00
|
|
|
bool &FromNullPtr, bool &ToNullPtr, Expr *&FromExpr,
|
|
|
|
Expr *&ToExpr) {
|
2016-01-14 22:56:39 +00:00
|
|
|
assert(FlatTree[ReadNode].Kind == Declaration && "Unexpected kind.");
|
|
|
|
FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
|
|
|
|
ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
|
|
|
|
FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
|
|
|
|
ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
|
|
|
|
FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
|
|
|
|
ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
|
2016-01-15 01:08:56 +00:00
|
|
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
|
|
|
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
|
2016-01-14 22:56:39 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 05:01:53 +00:00
|
|
|
void GetFromDeclarationAndToIntegerDiff(
|
|
|
|
ValueDecl *&FromValueDecl, bool &FromAddressOf, bool &FromNullPtr,
|
|
|
|
Expr *&FromExpr, llvm::APSInt &ToInt, bool &IsValidToInt,
|
|
|
|
QualType &ToIntType, Expr *&ToExpr) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == FromDeclarationAndToInteger &&
|
|
|
|
"Unexpected kind.");
|
|
|
|
FromValueDecl = FlatTree[ReadNode].FromArgInfo.VD;
|
|
|
|
FromAddressOf = FlatTree[ReadNode].FromArgInfo.NeedAddressOf;
|
|
|
|
FromNullPtr = FlatTree[ReadNode].FromArgInfo.IsNullPtr;
|
|
|
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
|
|
|
|
ToInt = FlatTree[ReadNode].ToArgInfo.Val;
|
|
|
|
IsValidToInt = FlatTree[ReadNode].ToArgInfo.IsValidInt;
|
|
|
|
ToIntType = FlatTree[ReadNode].ToArgInfo.ArgType;
|
|
|
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GetFromIntegerAndToDeclarationDiff(
|
|
|
|
llvm::APSInt &FromInt, bool &IsValidFromInt, QualType &FromIntType,
|
|
|
|
Expr *&FromExpr, ValueDecl *&ToValueDecl, bool &ToAddressOf,
|
|
|
|
bool &ToNullPtr, Expr *&ToExpr) {
|
|
|
|
assert(FlatTree[ReadNode].Kind == FromIntegerAndToDeclaration &&
|
|
|
|
"Unexpected kind.");
|
|
|
|
FromInt = FlatTree[ReadNode].FromArgInfo.Val;
|
|
|
|
IsValidFromInt = FlatTree[ReadNode].FromArgInfo.IsValidInt;
|
|
|
|
FromIntType = FlatTree[ReadNode].FromArgInfo.ArgType;
|
|
|
|
FromExpr = FlatTree[ReadNode].FromArgInfo.ArgExpr;
|
|
|
|
ToValueDecl = FlatTree[ReadNode].ToArgInfo.VD;
|
|
|
|
ToAddressOf = FlatTree[ReadNode].ToArgInfo.NeedAddressOf;
|
|
|
|
ToNullPtr = FlatTree[ReadNode].ToArgInfo.IsNullPtr;
|
|
|
|
ToExpr = FlatTree[ReadNode].ToArgInfo.ArgExpr;
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
/// FromDefault - Return true if the from argument is the default.
|
|
|
|
bool FromDefault() {
|
|
|
|
return FlatTree[ReadNode].FromArgInfo.IsDefault;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ToDefault - Return true if the to argument is the default.
|
|
|
|
bool ToDefault() {
|
|
|
|
return FlatTree[ReadNode].ToArgInfo.IsDefault;
|
2013-02-27 01:41:53 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// NodeIsSame - Returns true the arguments are the same.
|
|
|
|
bool NodeIsSame() {
|
|
|
|
return FlatTree[ReadNode].Same;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// HasChildrend - Returns true if the node has children.
|
|
|
|
bool HasChildren() {
|
|
|
|
return FlatTree[ReadNode].ChildNode != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// MoveToChild - Moves from the current node to its child.
|
|
|
|
void MoveToChild() {
|
|
|
|
ReadNode = FlatTree[ReadNode].ChildNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AdvanceSibling - If there is a next sibling, advance to it and return
|
|
|
|
/// true. Otherwise, return false.
|
|
|
|
bool AdvanceSibling() {
|
|
|
|
if (FlatTree[ReadNode].NextNode == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ReadNode = FlatTree[ReadNode].NextNode;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// HasNextSibling - Return true if the node has a next sibling.
|
|
|
|
bool HasNextSibling() {
|
|
|
|
return FlatTree[ReadNode].NextNode != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Empty - Returns true if the tree has no information.
|
|
|
|
bool Empty() {
|
2013-03-15 20:35:18 +00:00
|
|
|
return GetKind() == Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// GetKind - Returns the current node's type.
|
|
|
|
DiffKind GetKind() {
|
|
|
|
return FlatTree[ReadNode].Kind;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
DiffTree Tree;
|
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// TSTiterator - a pair of iterators that walks the
|
|
|
|
/// TemplateSpecializationType and the desugared TemplateSpecializationType.
|
|
|
|
/// The deseguared TemplateArgument should provide the canonical argument
|
|
|
|
/// for comparisons.
|
|
|
|
class TSTiterator {
|
2012-06-26 18:18:47 +00:00
|
|
|
typedef const TemplateArgument& reference;
|
|
|
|
typedef const TemplateArgument* pointer;
|
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// InternalIterator - an iterator that is used to enter a
|
|
|
|
/// TemplateSpecializationType and read TemplateArguments inside template
|
|
|
|
/// parameter packs in order with the rest of the TemplateArguments.
|
|
|
|
struct InternalIterator {
|
|
|
|
/// TST - the template specialization whose arguments this iterator
|
|
|
|
/// traverse over.
|
|
|
|
const TemplateSpecializationType *TST;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// Index - the index of the template argument in TST.
|
|
|
|
unsigned Index;
|
2013-03-15 23:55:09 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// CurrentTA - if CurrentTA is not the same as EndTA, then CurrentTA
|
|
|
|
/// points to a TemplateArgument within a parameter pack.
|
|
|
|
TemplateArgument::pack_iterator CurrentTA;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// EndTA - the end iterator of a parameter pack
|
|
|
|
TemplateArgument::pack_iterator EndTA;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// InternalIterator - Constructs an iterator and sets it to the first
|
|
|
|
/// template argument.
|
|
|
|
InternalIterator(const TemplateSpecializationType *TST)
|
|
|
|
: TST(TST), Index(0), CurrentTA(nullptr), EndTA(nullptr) {
|
2016-08-05 03:16:36 +00:00
|
|
|
if (!TST) return;
|
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
if (isEnd()) return;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
// Set to first template argument. If not a parameter pack, done.
|
2022-10-24 14:18:46 +02:00
|
|
|
TemplateArgument TA = TST->template_arguments()[0];
|
2016-01-14 23:30:12 +00:00
|
|
|
if (TA.getKind() != TemplateArgument::Pack) return;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
// Start looking into the parameter pack.
|
|
|
|
CurrentTA = TA.pack_begin();
|
|
|
|
EndTA = TA.pack_end();
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
// Found a valid template argument.
|
|
|
|
if (CurrentTA != EndTA) return;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
// Parameter pack is empty, use the increment to get to a valid
|
|
|
|
// template argument.
|
|
|
|
++(*this);
|
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-10-28 19:54:43 +00:00
|
|
|
/// Return true if the iterator is non-singular.
|
|
|
|
bool isValid() const { return TST; }
|
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// isEnd - Returns true if the iterator is one past the end.
|
|
|
|
bool isEnd() const {
|
2016-08-06 01:44:06 +00:00
|
|
|
assert(TST && "InternalIterator is invalid with a null TST.");
|
2022-10-24 14:18:46 +02:00
|
|
|
return Index >= TST->template_arguments().size();
|
2016-01-14 23:30:12 +00:00
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// &operator++ - Increment the iterator to the next template argument.
|
|
|
|
InternalIterator &operator++() {
|
2016-08-06 01:44:06 +00:00
|
|
|
assert(TST && "InternalIterator is invalid with a null TST.");
|
2016-01-14 23:30:12 +00:00
|
|
|
if (isEnd()) {
|
|
|
|
return *this;
|
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
// If in a parameter pack, advance in the parameter pack.
|
|
|
|
if (CurrentTA != EndTA) {
|
|
|
|
++CurrentTA;
|
|
|
|
if (CurrentTA != EndTA)
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop until a template argument is found, or the end is reached.
|
|
|
|
while (true) {
|
|
|
|
// Advance to the next template argument. Break if reached the end.
|
2022-10-24 14:18:46 +02:00
|
|
|
if (++Index == TST->template_arguments().size())
|
2016-01-14 23:30:12 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// If the TemplateArgument is not a parameter pack, done.
|
2022-10-24 14:18:46 +02:00
|
|
|
TemplateArgument TA = TST->template_arguments()[Index];
|
2016-01-14 23:30:12 +00:00
|
|
|
if (TA.getKind() != TemplateArgument::Pack)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Handle parameter packs.
|
|
|
|
CurrentTA = TA.pack_begin();
|
|
|
|
EndTA = TA.pack_end();
|
|
|
|
|
|
|
|
// If the parameter pack is empty, try to advance again.
|
|
|
|
if (CurrentTA != EndTA)
|
|
|
|
break;
|
|
|
|
}
|
2013-03-15 23:55:09 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// operator* - Returns the appropriate TemplateArgument.
|
|
|
|
reference operator*() const {
|
2016-08-06 01:44:06 +00:00
|
|
|
assert(TST && "InternalIterator is invalid with a null TST.");
|
2016-01-14 23:30:12 +00:00
|
|
|
assert(!isEnd() && "Index exceeds number of arguments.");
|
|
|
|
if (CurrentTA == EndTA)
|
2022-10-24 14:18:46 +02:00
|
|
|
return TST->template_arguments()[Index];
|
2016-01-14 23:30:12 +00:00
|
|
|
else
|
|
|
|
return *CurrentTA;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// operator-> - Allow access to the underlying TemplateArgument.
|
|
|
|
pointer operator->() const {
|
2016-08-06 01:44:06 +00:00
|
|
|
assert(TST && "InternalIterator is invalid with a null TST.");
|
2016-01-14 23:30:12 +00:00
|
|
|
return &operator*();
|
|
|
|
}
|
|
|
|
};
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
InternalIterator SugaredIterator;
|
|
|
|
InternalIterator DesugaredIterator;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
public:
|
|
|
|
TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
|
2016-10-28 19:54:43 +00:00
|
|
|
: SugaredIterator(TST),
|
2016-01-14 23:30:12 +00:00
|
|
|
DesugaredIterator(
|
2016-10-28 19:54:43 +00:00
|
|
|
(TST->isSugared() && !TST->isTypeAlias())
|
|
|
|
? GetTemplateSpecializationType(Context, TST->desugar())
|
|
|
|
: nullptr) {}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// &operator++ - Increment the iterator to the next template argument.
|
|
|
|
TSTiterator &operator++() {
|
|
|
|
++SugaredIterator;
|
2016-10-28 19:54:43 +00:00
|
|
|
if (DesugaredIterator.isValid())
|
2016-03-30 22:23:00 +00:00
|
|
|
++DesugaredIterator;
|
2012-06-26 18:18:47 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// operator* - Returns the appropriate TemplateArgument.
|
|
|
|
reference operator*() const {
|
2016-01-14 23:30:12 +00:00
|
|
|
return *SugaredIterator;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// operator-> - Allow access to the underlying TemplateArgument.
|
|
|
|
pointer operator->() const {
|
|
|
|
return &operator*();
|
|
|
|
}
|
2013-03-15 23:55:09 +00:00
|
|
|
|
2016-01-14 23:30:12 +00:00
|
|
|
/// isEnd - Returns true if no more TemplateArguments are available.
|
|
|
|
bool isEnd() const {
|
|
|
|
return SugaredIterator.isEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// hasDesugaredTA - Returns true if there is another TemplateArgument
|
|
|
|
/// available.
|
|
|
|
bool hasDesugaredTA() const {
|
2016-10-28 19:54:43 +00:00
|
|
|
return DesugaredIterator.isValid() && !DesugaredIterator.isEnd();
|
2016-01-14 23:30:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getDesugaredTA - Returns the desugared TemplateArgument.
|
|
|
|
reference getDesugaredTA() const {
|
2016-10-28 19:54:43 +00:00
|
|
|
assert(DesugaredIterator.isValid() &&
|
2016-03-30 22:23:00 +00:00
|
|
|
"Desugared TemplateArgument should not be used.");
|
2016-01-14 23:30:12 +00:00
|
|
|
return *DesugaredIterator;
|
2013-03-15 23:55:09 +00:00
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// These functions build up the template diff tree, including functions to
|
2016-01-14 23:30:12 +00:00
|
|
|
// retrieve and compare template arguments.
|
2012-06-26 18:18:47 +00:00
|
|
|
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
static const TemplateSpecializationType *
|
|
|
|
GetTemplateSpecializationType(ASTContext &Context, QualType Ty) {
|
2012-06-26 18:18:47 +00:00
|
|
|
if (const TemplateSpecializationType *TST =
|
|
|
|
Ty->getAs<TemplateSpecializationType>())
|
|
|
|
return TST;
|
|
|
|
|
2021-08-16 16:54:10 -07:00
|
|
|
if (const auto* SubstType = Ty->getAs<SubstTemplateTypeParmType>())
|
|
|
|
Ty = SubstType->getReplacementType();
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
const RecordType *RT = Ty->getAs<RecordType>();
|
|
|
|
|
|
|
|
if (!RT)
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
const ClassTemplateSpecializationDecl *CTSD =
|
|
|
|
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
|
|
|
|
|
|
|
|
if (!CTSD)
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
Ty = Context.getTemplateSpecializationType(
|
2025-04-12 14:26:30 -03:00
|
|
|
TemplateName(CTSD->getSpecializedTemplate()),
|
|
|
|
CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/std::nullopt,
|
|
|
|
Ty.getLocalUnqualifiedType().getCanonicalType());
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
return Ty->getAs<TemplateSpecializationType>();
|
|
|
|
}
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
/// Returns true if the DiffType is Type and false for Template.
|
|
|
|
static bool OnlyPerformTypeDiff(ASTContext &Context, QualType FromType,
|
|
|
|
QualType ToType,
|
|
|
|
const TemplateSpecializationType *&FromArgTST,
|
|
|
|
const TemplateSpecializationType *&ToArgTST) {
|
|
|
|
if (FromType.isNull() || ToType.isNull())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (Context.hasSameType(FromType, ToType))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
FromArgTST = GetTemplateSpecializationType(Context, FromType);
|
|
|
|
ToArgTST = GetTemplateSpecializationType(Context, ToType);
|
|
|
|
|
|
|
|
if (!FromArgTST || !ToArgTST)
|
|
|
|
return true;
|
|
|
|
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
if (!hasSameTemplate(Context, FromArgTST, ToArgTST))
|
2016-01-14 22:56:39 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-27 06:24:47 +00:00
|
|
|
/// DiffTypes - Fills a DiffNode with information about a type difference.
|
2016-01-15 01:08:56 +00:00
|
|
|
void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter) {
|
|
|
|
QualType FromType = GetType(FromIter);
|
|
|
|
QualType ToType = GetType(ToIter);
|
2014-08-27 06:24:47 +00:00
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
bool FromDefault = FromIter.isEnd() && !FromType.isNull();
|
|
|
|
bool ToDefault = ToIter.isEnd() && !ToType.isNull();
|
2014-08-27 06:24:47 +00:00
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
const TemplateSpecializationType *FromArgTST = nullptr;
|
|
|
|
const TemplateSpecializationType *ToArgTST = nullptr;
|
|
|
|
if (OnlyPerformTypeDiff(Context, FromType, ToType, FromArgTST, ToArgTST)) {
|
|
|
|
Tree.SetTypeDiff(FromType, ToType, FromDefault, ToDefault);
|
|
|
|
Tree.SetSame(!FromType.isNull() && !ToType.isNull() &&
|
|
|
|
Context.hasSameType(FromType, ToType));
|
|
|
|
} else {
|
|
|
|
assert(FromArgTST && ToArgTST &&
|
|
|
|
"Both template specializations need to be valid.");
|
|
|
|
Qualifiers FromQual = FromType.getQualifiers(),
|
|
|
|
ToQual = ToType.getQualifiers();
|
|
|
|
FromQual -= QualType(FromArgTST, 0).getQualifiers();
|
|
|
|
ToQual -= QualType(ToArgTST, 0).getQualifiers();
|
|
|
|
Tree.SetTemplateDiff(FromArgTST->getTemplateName().getAsTemplateDecl(),
|
|
|
|
ToArgTST->getTemplateName().getAsTemplateDecl(),
|
|
|
|
FromQual, ToQual, FromDefault, ToDefault);
|
|
|
|
DiffTemplate(FromArgTST, ToArgTST);
|
2014-08-27 06:24:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DiffTemplateTemplates - Fills a DiffNode with information about a
|
|
|
|
/// template template difference.
|
|
|
|
void DiffTemplateTemplates(const TSTiterator &FromIter,
|
2016-01-15 01:08:56 +00:00
|
|
|
const TSTiterator &ToIter) {
|
|
|
|
TemplateDecl *FromDecl = GetTemplateDecl(FromIter);
|
|
|
|
TemplateDecl *ToDecl = GetTemplateDecl(ToIter);
|
2016-01-14 22:56:39 +00:00
|
|
|
Tree.SetTemplateTemplateDiff(FromDecl, ToDecl, FromIter.isEnd() && FromDecl,
|
|
|
|
ToIter.isEnd() && ToDecl);
|
2014-08-27 06:24:47 +00:00
|
|
|
Tree.SetSame(FromDecl && ToDecl &&
|
|
|
|
FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes
|
2016-01-15 02:55:17 +00:00
|
|
|
static void InitializeNonTypeDiffVariables(ASTContext &Context,
|
|
|
|
const TSTiterator &Iter,
|
|
|
|
NonTypeTemplateParmDecl *Default,
|
|
|
|
llvm::APSInt &Value, bool &HasInt,
|
|
|
|
QualType &IntType, bool &IsNullPtr,
|
|
|
|
Expr *&E, ValueDecl *&VD,
|
|
|
|
bool &NeedAddressOf) {
|
2016-01-15 01:08:56 +00:00
|
|
|
if (!Iter.isEnd()) {
|
|
|
|
switch (Iter->getKind()) {
|
2024-05-24 11:33:16 -03:00
|
|
|
case TemplateArgument::StructuralValue:
|
|
|
|
// FIXME: Diffing of structural values is not implemented.
|
|
|
|
// There is no possible fallback in this case, this will show up
|
|
|
|
// as '(no argument)'.
|
|
|
|
return;
|
2016-01-15 01:08:56 +00:00
|
|
|
case TemplateArgument::Integral:
|
2024-05-24 11:33:16 -03:00
|
|
|
Value = Iter->getAsIntegral();
|
2016-01-15 01:08:56 +00:00
|
|
|
HasInt = true;
|
2024-05-24 11:33:16 -03:00
|
|
|
IntType = Iter->getIntegralType();
|
2016-01-15 01:08:56 +00:00
|
|
|
return;
|
|
|
|
case TemplateArgument::Declaration: {
|
2024-05-24 11:33:16 -03:00
|
|
|
VD = Iter->getAsDecl();
|
|
|
|
QualType ArgType = Iter->getParamTypeForDecl();
|
2016-01-15 01:08:56 +00:00
|
|
|
QualType VDType = VD->getType();
|
|
|
|
if (ArgType->isPointerType() &&
|
|
|
|
Context.hasSameType(ArgType->getPointeeType(), VDType))
|
|
|
|
NeedAddressOf = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
IsNullPtr = true;
|
|
|
|
return;
|
|
|
|
case TemplateArgument::Expression:
|
2024-05-24 11:33:16 -03:00
|
|
|
E = Iter->getAsExpr();
|
|
|
|
break;
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
case TemplateArgument::Template:
|
|
|
|
case TemplateArgument::TemplateExpansion:
|
|
|
|
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
llvm_unreachable("TemplateArgument kind should be handled elsewhere");
|
|
|
|
}
|
|
|
|
} else if (!Default->isParameterPack()) {
|
|
|
|
E = Default->getDefaultArgument().getArgument().getAsExpr();
|
2016-01-15 01:08:56 +00:00
|
|
|
}
|
2024-05-24 11:33:16 -03:00
|
|
|
|
|
|
|
if (!Iter.hasDesugaredTA())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const TemplateArgument &TA = Iter.getDesugaredTA();
|
|
|
|
switch (TA.getKind()) {
|
|
|
|
case TemplateArgument::StructuralValue:
|
|
|
|
// FIXME: Diffing of structural values is not implemented.
|
|
|
|
// Just fall back to the expression.
|
|
|
|
return;
|
|
|
|
case TemplateArgument::Integral:
|
|
|
|
Value = TA.getAsIntegral();
|
|
|
|
HasInt = true;
|
|
|
|
IntType = TA.getIntegralType();
|
|
|
|
return;
|
|
|
|
case TemplateArgument::Declaration: {
|
|
|
|
VD = TA.getAsDecl();
|
|
|
|
QualType ArgType = TA.getParamTypeForDecl();
|
|
|
|
QualType VDType = VD->getType();
|
|
|
|
if (ArgType->isPointerType() &&
|
|
|
|
Context.hasSameType(ArgType->getPointeeType(), VDType))
|
|
|
|
NeedAddressOf = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case TemplateArgument::NullPtr:
|
|
|
|
IsNullPtr = true;
|
|
|
|
return;
|
|
|
|
case TemplateArgument::Expression:
|
|
|
|
// TODO: Sometimes, the desugared template argument Expr differs from
|
|
|
|
// the sugared template argument Expr. It may be useful in the future
|
|
|
|
// but for now, it is just discarded.
|
|
|
|
if (!E)
|
|
|
|
E = TA.getAsExpr();
|
|
|
|
return;
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
case TemplateArgument::Type:
|
|
|
|
case TemplateArgument::Template:
|
|
|
|
case TemplateArgument::TemplateExpansion:
|
|
|
|
llvm_unreachable("TemplateArgument kind is not expected for NTTP");
|
|
|
|
case TemplateArgument::Pack:
|
|
|
|
llvm_unreachable("TemplateArgument kind should be handled elsewhere");
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unexpected TemplateArgument kind");
|
2014-08-27 06:24:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// DiffNonTypes - Handles any template parameters not handled by DiffTypes
|
|
|
|
/// of DiffTemplatesTemplates, such as integer and declaration parameters.
|
|
|
|
void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter,
|
|
|
|
NonTypeTemplateParmDecl *FromDefaultNonTypeDecl,
|
|
|
|
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) {
|
|
|
|
Expr *FromExpr = nullptr, *ToExpr = nullptr;
|
|
|
|
llvm::APSInt FromInt, ToInt;
|
2016-01-15 02:55:17 +00:00
|
|
|
QualType FromIntType, ToIntType;
|
2014-08-27 06:24:47 +00:00
|
|
|
ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr;
|
2016-01-15 01:08:56 +00:00
|
|
|
bool HasFromInt = false, HasToInt = false, FromNullPtr = false,
|
|
|
|
ToNullPtr = false, NeedFromAddressOf = false, NeedToAddressOf = false;
|
2016-01-15 02:55:17 +00:00
|
|
|
InitializeNonTypeDiffVariables(
|
|
|
|
Context, FromIter, FromDefaultNonTypeDecl, FromInt, HasFromInt,
|
|
|
|
FromIntType, FromNullPtr, FromExpr, FromValueDecl, NeedFromAddressOf);
|
2016-01-15 01:08:56 +00:00
|
|
|
InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl, ToInt,
|
2016-01-15 02:55:17 +00:00
|
|
|
HasToInt, ToIntType, ToNullPtr, ToExpr,
|
|
|
|
ToValueDecl, NeedToAddressOf);
|
2016-01-15 01:08:56 +00:00
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
bool FromDefault = FromIter.isEnd() &&
|
|
|
|
(FromExpr || FromValueDecl || HasFromInt || FromNullPtr);
|
|
|
|
bool ToDefault = ToIter.isEnd() &&
|
|
|
|
(ToExpr || ToValueDecl || HasToInt || ToNullPtr);
|
|
|
|
|
2016-01-15 05:01:53 +00:00
|
|
|
bool FromDeclaration = FromValueDecl || FromNullPtr;
|
|
|
|
bool ToDeclaration = ToValueDecl || ToNullPtr;
|
|
|
|
|
|
|
|
if (FromDeclaration && HasToInt) {
|
|
|
|
Tree.SetFromDeclarationAndToIntegerDiff(
|
|
|
|
FromValueDecl, NeedFromAddressOf, FromNullPtr, FromExpr, ToInt,
|
|
|
|
HasToInt, ToIntType, ToExpr, FromDefault, ToDefault);
|
|
|
|
Tree.SetSame(false);
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasFromInt && ToDeclaration) {
|
|
|
|
Tree.SetFromIntegerAndToDeclarationDiff(
|
|
|
|
FromInt, HasFromInt, FromIntType, FromExpr, ToValueDecl,
|
|
|
|
NeedToAddressOf, ToNullPtr, ToExpr, FromDefault, ToDefault);
|
|
|
|
Tree.SetSame(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 06:24:47 +00:00
|
|
|
if (HasFromInt || HasToInt) {
|
2016-01-15 02:55:17 +00:00
|
|
|
Tree.SetIntegerDiff(FromInt, ToInt, HasFromInt, HasToInt, FromIntType,
|
|
|
|
ToIntType, FromExpr, ToExpr, FromDefault, ToDefault);
|
2015-01-24 02:48:32 +00:00
|
|
|
if (HasFromInt && HasToInt) {
|
2016-01-15 02:55:17 +00:00
|
|
|
Tree.SetSame(Context.hasSameType(FromIntType, ToIntType) &&
|
|
|
|
FromInt == ToInt);
|
2015-01-24 02:48:32 +00:00
|
|
|
}
|
2014-08-27 06:24:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
if (FromDeclaration || ToDeclaration) {
|
|
|
|
Tree.SetDeclarationDiff(FromValueDecl, ToValueDecl, NeedFromAddressOf,
|
|
|
|
NeedToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
|
|
|
|
ToExpr, FromDefault, ToDefault);
|
|
|
|
bool BothNull = FromNullPtr && ToNullPtr;
|
|
|
|
bool SameValueDecl =
|
|
|
|
FromValueDecl && ToValueDecl &&
|
|
|
|
NeedFromAddressOf == NeedToAddressOf &&
|
|
|
|
FromValueDecl->getCanonicalDecl() == ToValueDecl->getCanonicalDecl();
|
|
|
|
Tree.SetSame(BothNull || SameValueDecl);
|
|
|
|
return;
|
|
|
|
}
|
2014-08-27 06:24:47 +00:00
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
assert((FromExpr || ToExpr) && "Both template arguments cannot be empty.");
|
|
|
|
Tree.SetExpressionDiff(FromExpr, ToExpr, FromDefault, ToDefault);
|
|
|
|
Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
|
2014-08-27 06:24:47 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// DiffTemplate - recursively visits template arguments and stores the
|
|
|
|
/// argument info into a tree.
|
|
|
|
void DiffTemplate(const TemplateSpecializationType *FromTST,
|
|
|
|
const TemplateSpecializationType *ToTST) {
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
// FIXME: With P3310R0, A TST formed from a DeducedTemplateName might
|
|
|
|
// differ in template arguments which were not written.
|
2012-06-26 18:18:47 +00:00
|
|
|
// Begin descent into diffing template tree.
|
2013-10-08 16:58:52 +00:00
|
|
|
TemplateParameterList *ParamsFrom =
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
FromTST->getTemplateName()
|
|
|
|
.getAsTemplateDecl(/*IgnoreDeduced=*/true)
|
|
|
|
->getTemplateParameters();
|
2013-10-08 16:58:52 +00:00
|
|
|
TemplateParameterList *ParamsTo =
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
ToTST->getTemplateName()
|
|
|
|
.getAsTemplateDecl(/*IgnoreDeduced=*/true)
|
|
|
|
->getTemplateParameters();
|
2012-06-26 18:18:47 +00:00
|
|
|
unsigned TotalArgs = 0;
|
2013-03-15 23:55:09 +00:00
|
|
|
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
|
2012-06-26 18:18:47 +00:00
|
|
|
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
|
|
|
|
Tree.AddNode();
|
|
|
|
|
|
|
|
// Get the parameter at index TotalArgs. If index is larger
|
|
|
|
// than the total number of parameters, then there is an
|
|
|
|
// argument pack, so re-use the last parameter.
|
2014-08-27 06:24:47 +00:00
|
|
|
unsigned FromParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
|
|
|
|
unsigned ToParamIndex = std::min(TotalArgs, ParamsTo->size() - 1);
|
|
|
|
NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex);
|
|
|
|
NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex);
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
assert(FromParamND->getKind() == ToParamND->getKind() &&
|
|
|
|
"Parameter Decl are not the same kind.");
|
|
|
|
|
|
|
|
if (isa<TemplateTypeParmDecl>(FromParamND)) {
|
|
|
|
DiffTypes(FromIter, ToIter);
|
|
|
|
} else if (isa<TemplateTemplateParmDecl>(FromParamND)) {
|
|
|
|
DiffTemplateTemplates(FromIter, ToIter);
|
|
|
|
} else if (isa<NonTypeTemplateParmDecl>(FromParamND)) {
|
|
|
|
NonTypeTemplateParmDecl *FromDefaultNonTypeDecl =
|
|
|
|
cast<NonTypeTemplateParmDecl>(FromParamND);
|
|
|
|
NonTypeTemplateParmDecl *ToDefaultNonTypeDecl =
|
|
|
|
cast<NonTypeTemplateParmDecl>(ToParamND);
|
2014-08-27 06:24:47 +00:00
|
|
|
DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl,
|
|
|
|
ToDefaultNonTypeDecl);
|
2016-01-15 01:08:56 +00:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("Unexpected Decl type.");
|
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2013-03-15 23:55:09 +00:00
|
|
|
++FromIter;
|
|
|
|
++ToIter;
|
2012-06-26 18:18:47 +00:00
|
|
|
Tree.Up();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-28 19:51:57 +00:00
|
|
|
/// makeTemplateList - Dump every template alias into the vector.
|
|
|
|
static void makeTemplateList(
|
2013-07-05 19:34:19 +00:00
|
|
|
SmallVectorImpl<const TemplateSpecializationType *> &TemplateList,
|
2012-09-28 19:51:57 +00:00
|
|
|
const TemplateSpecializationType *TST) {
|
|
|
|
while (TST) {
|
|
|
|
TemplateList.push_back(TST);
|
|
|
|
if (!TST->isTypeAlias())
|
|
|
|
return;
|
|
|
|
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// hasSameBaseTemplate - Returns true when the base templates are the same,
|
|
|
|
/// even if the template arguments are not.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
static bool hasSameBaseTemplate(ASTContext &Context,
|
|
|
|
const TemplateSpecializationType *FromTST,
|
2012-09-28 19:51:57 +00:00
|
|
|
const TemplateSpecializationType *ToTST) {
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
return Context.getCanonicalTemplateName(FromTST->getTemplateName(),
|
|
|
|
/*IgnoreDeduced=*/true) ==
|
|
|
|
Context.getCanonicalTemplateName(ToTST->getTemplateName(),
|
|
|
|
/*IgnoreDeduced=*/true);
|
2012-09-28 19:51:57 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// hasSameTemplate - Returns true if both types are specialized from the
|
|
|
|
/// same template declaration. If they come from different template aliases,
|
|
|
|
/// do a parallel ascension search to determine the highest template alias in
|
|
|
|
/// common and set the arguments to them.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
static bool hasSameTemplate(ASTContext &Context,
|
|
|
|
const TemplateSpecializationType *&FromTST,
|
2012-06-26 18:18:47 +00:00
|
|
|
const TemplateSpecializationType *&ToTST) {
|
|
|
|
// Check the top templates if they are the same.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
if (hasSameBaseTemplate(Context, FromTST, ToTST))
|
2012-06-26 18:18:47 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Create vectors of template aliases.
|
|
|
|
SmallVector<const TemplateSpecializationType*, 1> FromTemplateList,
|
|
|
|
ToTemplateList;
|
|
|
|
|
2012-09-28 19:51:57 +00:00
|
|
|
makeTemplateList(FromTemplateList, FromTST);
|
|
|
|
makeTemplateList(ToTemplateList, ToTST);
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2013-07-08 03:55:09 +00:00
|
|
|
SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator
|
2012-06-26 18:18:47 +00:00
|
|
|
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
|
|
|
|
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
|
|
|
|
|
|
|
|
// Check if the lowest template types are the same. If not, return.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
if (!hasSameBaseTemplate(Context, *FromIter, *ToIter))
|
2012-06-26 18:18:47 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Begin searching up the template aliases. The bottom most template
|
|
|
|
// matches so move up until one pair does not match. Use the template
|
|
|
|
// right before that one.
|
|
|
|
for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) {
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
if (!hasSameBaseTemplate(Context, *FromIter, *ToIter))
|
2012-06-26 18:18:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
FromTST = FromIter[-1];
|
|
|
|
ToTST = ToIter[-1];
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// GetType - Retrieves the template type arguments, including default
|
|
|
|
/// arguments.
|
2016-01-15 01:08:56 +00:00
|
|
|
static QualType GetType(const TSTiterator &Iter) {
|
2012-06-26 18:18:47 +00:00
|
|
|
if (!Iter.isEnd())
|
2013-04-03 03:06:48 +00:00
|
|
|
return Iter->getAsType();
|
2016-01-15 01:08:56 +00:00
|
|
|
if (Iter.hasDesugaredTA())
|
2016-01-14 23:30:12 +00:00
|
|
|
return Iter.getDesugaredTA().getAsType();
|
2016-01-15 01:08:56 +00:00
|
|
|
return QualType();
|
2014-07-24 04:24:50 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
/// GetTemplateDecl - Retrieves the template template arguments, including
|
|
|
|
/// default arguments.
|
2016-01-15 01:08:56 +00:00
|
|
|
static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter) {
|
2012-06-26 18:18:47 +00:00
|
|
|
if (!Iter.isEnd())
|
2013-04-03 03:06:48 +00:00
|
|
|
return Iter->getAsTemplate().getAsTemplateDecl();
|
2016-01-15 01:08:56 +00:00
|
|
|
if (Iter.hasDesugaredTA())
|
|
|
|
return Iter.getDesugaredTA().getAsTemplate().getAsTemplateDecl();
|
2014-05-12 05:36:57 +00:00
|
|
|
return nullptr;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
/// IsEqualExpr - Returns true if the expressions are the same in regards to
|
|
|
|
/// template arguments. These expressions are dependent, so profile them
|
|
|
|
/// instead of trying to evaluate them.
|
2015-01-24 02:48:32 +00:00
|
|
|
static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
|
2012-06-26 18:18:47 +00:00
|
|
|
if (FromExpr == ToExpr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!FromExpr || !ToExpr)
|
|
|
|
return false;
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
llvm::FoldingSetNodeID FromID, ToID;
|
|
|
|
FromExpr->Profile(FromID, Context, true);
|
|
|
|
ToExpr->Profile(ToID, Context, true);
|
|
|
|
return FromID == ToID;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// These functions converts the tree representation of the template
|
|
|
|
// differences into the internal character vector.
|
|
|
|
|
|
|
|
/// TreeToString - Converts the Tree object into a character stream which
|
|
|
|
/// will later be turned into the output string.
|
|
|
|
void TreeToString(int Indent = 1) {
|
|
|
|
if (PrintTree) {
|
|
|
|
OS << '\n';
|
2013-02-22 16:13:34 +00:00
|
|
|
OS.indent(2 * Indent);
|
2012-06-26 18:18:47 +00:00
|
|
|
++Indent;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle cases where the difference is not templates with different
|
|
|
|
// arguments.
|
2013-03-15 20:35:18 +00:00
|
|
|
switch (Tree.GetKind()) {
|
|
|
|
case DiffTree::Invalid:
|
|
|
|
llvm_unreachable("Template diffing failed with bad DiffNode");
|
|
|
|
case DiffTree::Type: {
|
2012-06-26 18:18:47 +00:00
|
|
|
QualType FromType, ToType;
|
2016-01-14 22:56:39 +00:00
|
|
|
Tree.GetTypeDiff(FromType, ToType);
|
2012-06-26 18:18:47 +00:00
|
|
|
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
|
|
|
|
Tree.NodeIsSame());
|
|
|
|
return;
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
case DiffTree::Expression: {
|
2012-06-26 18:18:47 +00:00
|
|
|
Expr *FromExpr, *ToExpr;
|
2016-01-15 01:08:56 +00:00
|
|
|
Tree.GetExpressionDiff(FromExpr, ToExpr);
|
|
|
|
PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
|
|
|
|
Tree.NodeIsSame());
|
2012-06-26 18:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
case DiffTree::TemplateTemplate: {
|
2012-06-26 18:18:47 +00:00
|
|
|
TemplateDecl *FromTD, *ToTD;
|
2016-01-14 22:56:39 +00:00
|
|
|
Tree.GetTemplateTemplateDiff(FromTD, ToTD);
|
2012-06-26 18:18:47 +00:00
|
|
|
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
|
|
|
|
Tree.ToDefault(), Tree.NodeIsSame());
|
|
|
|
return;
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
case DiffTree::Integer: {
|
2012-11-01 21:29:28 +00:00
|
|
|
llvm::APSInt FromInt, ToInt;
|
2013-03-15 23:55:09 +00:00
|
|
|
Expr *FromExpr, *ToExpr;
|
2012-11-01 21:29:28 +00:00
|
|
|
bool IsValidFromInt, IsValidToInt;
|
2016-01-15 02:55:17 +00:00
|
|
|
QualType FromIntType, ToIntType;
|
2016-01-14 22:56:39 +00:00
|
|
|
Tree.GetIntegerDiff(FromInt, ToInt, IsValidFromInt, IsValidToInt,
|
2016-01-15 02:55:17 +00:00
|
|
|
FromIntType, ToIntType, FromExpr, ToExpr);
|
|
|
|
PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, FromIntType,
|
|
|
|
ToIntType, FromExpr, ToExpr, Tree.FromDefault(),
|
|
|
|
Tree.ToDefault(), Tree.NodeIsSame());
|
2012-11-01 21:29:28 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
case DiffTree::Declaration: {
|
2013-02-27 01:41:53 +00:00
|
|
|
ValueDecl *FromValueDecl, *ToValueDecl;
|
2013-05-07 21:36:24 +00:00
|
|
|
bool FromAddressOf, ToAddressOf;
|
2016-01-14 22:56:39 +00:00
|
|
|
bool FromNullPtr, ToNullPtr;
|
2016-01-15 01:08:56 +00:00
|
|
|
Expr *FromExpr, *ToExpr;
|
2016-01-14 22:56:39 +00:00
|
|
|
Tree.GetDeclarationDiff(FromValueDecl, ToValueDecl, FromAddressOf,
|
2016-01-15 01:08:56 +00:00
|
|
|
ToAddressOf, FromNullPtr, ToNullPtr, FromExpr,
|
|
|
|
ToExpr);
|
2013-05-07 21:36:24 +00:00
|
|
|
PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
|
2016-01-15 01:08:56 +00:00
|
|
|
FromNullPtr, ToNullPtr, FromExpr, ToExpr,
|
|
|
|
Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
|
2013-02-27 01:41:53 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-01-15 05:01:53 +00:00
|
|
|
case DiffTree::FromDeclarationAndToInteger: {
|
|
|
|
ValueDecl *FromValueDecl;
|
|
|
|
bool FromAddressOf;
|
|
|
|
bool FromNullPtr;
|
|
|
|
Expr *FromExpr;
|
|
|
|
llvm::APSInt ToInt;
|
|
|
|
bool IsValidToInt;
|
|
|
|
QualType ToIntType;
|
|
|
|
Expr *ToExpr;
|
|
|
|
Tree.GetFromDeclarationAndToIntegerDiff(
|
|
|
|
FromValueDecl, FromAddressOf, FromNullPtr, FromExpr, ToInt,
|
|
|
|
IsValidToInt, ToIntType, ToExpr);
|
|
|
|
assert((FromValueDecl || FromNullPtr) && IsValidToInt);
|
|
|
|
PrintValueDeclAndInteger(FromValueDecl, FromAddressOf, FromNullPtr,
|
|
|
|
FromExpr, Tree.FromDefault(), ToInt, ToIntType,
|
|
|
|
ToExpr, Tree.ToDefault());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case DiffTree::FromIntegerAndToDeclaration: {
|
|
|
|
llvm::APSInt FromInt;
|
|
|
|
bool IsValidFromInt;
|
|
|
|
QualType FromIntType;
|
|
|
|
Expr *FromExpr;
|
|
|
|
ValueDecl *ToValueDecl;
|
|
|
|
bool ToAddressOf;
|
|
|
|
bool ToNullPtr;
|
|
|
|
Expr *ToExpr;
|
|
|
|
Tree.GetFromIntegerAndToDeclarationDiff(
|
|
|
|
FromInt, IsValidFromInt, FromIntType, FromExpr, ToValueDecl,
|
|
|
|
ToAddressOf, ToNullPtr, ToExpr);
|
|
|
|
assert(IsValidFromInt && (ToValueDecl || ToNullPtr));
|
|
|
|
PrintIntegerAndValueDecl(FromInt, FromIntType, FromExpr,
|
|
|
|
Tree.FromDefault(), ToValueDecl, ToAddressOf,
|
|
|
|
ToNullPtr, ToExpr, Tree.ToDefault());
|
|
|
|
return;
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
case DiffTree::Template: {
|
|
|
|
// Node is root of template. Recurse on children.
|
|
|
|
TemplateDecl *FromTD, *ToTD;
|
2016-01-14 22:56:39 +00:00
|
|
|
Qualifiers FromQual, ToQual;
|
|
|
|
Tree.GetTemplateDiff(FromTD, ToTD, FromQual, ToQual);
|
2013-02-27 01:41:53 +00:00
|
|
|
|
2016-01-15 05:48:38 +00:00
|
|
|
PrintQualifiers(FromQual, ToQual);
|
|
|
|
|
2013-03-15 20:35:18 +00:00
|
|
|
if (!Tree.HasChildren()) {
|
|
|
|
// If we're dealing with a template specialization with zero
|
|
|
|
// arguments, there are no children; special-case this.
|
2020-08-05 11:48:09 +01:00
|
|
|
OS << FromTD->getDeclName() << "<>";
|
2013-03-15 20:35:18 +00:00
|
|
|
return;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
|
2020-08-05 11:48:09 +01:00
|
|
|
OS << FromTD->getDeclName() << '<';
|
2013-03-15 20:35:18 +00:00
|
|
|
Tree.MoveToChild();
|
|
|
|
unsigned NumElideArgs = 0;
|
2016-02-02 00:36:59 +00:00
|
|
|
bool AllArgsElided = true;
|
2013-03-15 20:35:18 +00:00
|
|
|
do {
|
|
|
|
if (ElideType) {
|
|
|
|
if (Tree.NodeIsSame()) {
|
|
|
|
++NumElideArgs;
|
|
|
|
continue;
|
|
|
|
}
|
2016-02-02 00:36:59 +00:00
|
|
|
AllArgsElided = false;
|
2013-03-15 20:35:18 +00:00
|
|
|
if (NumElideArgs > 0) {
|
|
|
|
PrintElideArgs(NumElideArgs, Indent);
|
|
|
|
NumElideArgs = 0;
|
|
|
|
OS << ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TreeToString(Indent);
|
|
|
|
if (Tree.HasNextSibling())
|
|
|
|
OS << ", ";
|
|
|
|
} while (Tree.AdvanceSibling());
|
2016-02-02 00:36:59 +00:00
|
|
|
if (NumElideArgs > 0) {
|
|
|
|
if (AllArgsElided)
|
|
|
|
OS << "...";
|
|
|
|
else
|
|
|
|
PrintElideArgs(NumElideArgs, Indent);
|
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
|
|
|
|
Tree.Parent();
|
|
|
|
OS << ">";
|
|
|
|
return;
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
2013-03-15 20:35:18 +00:00
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// To signal to the text printer that a certain text needs to be bolded,
|
|
|
|
// a special character is injected into the character stream which the
|
|
|
|
// text printer will later strip out.
|
|
|
|
|
|
|
|
/// Bold - Start bolding text.
|
|
|
|
void Bold() {
|
|
|
|
assert(!IsBold && "Attempting to bold text that is already bold.");
|
|
|
|
IsBold = true;
|
|
|
|
if (ShowColor)
|
|
|
|
OS << ToggleHighlight;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Unbold - Stop bolding text.
|
|
|
|
void Unbold() {
|
|
|
|
assert(IsBold && "Attempting to remove bold from unbold text.");
|
|
|
|
IsBold = false;
|
|
|
|
if (ShowColor)
|
|
|
|
OS << ToggleHighlight;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Functions to print out the arguments and highlighting the difference.
|
|
|
|
|
|
|
|
/// PrintTypeNames - prints the typenames, bolding differences. Will detect
|
|
|
|
/// typenames that are the same and attempt to disambiguate them by using
|
|
|
|
/// canonical typenames.
|
|
|
|
void PrintTypeNames(QualType FromType, QualType ToType,
|
|
|
|
bool FromDefault, bool ToDefault, bool Same) {
|
|
|
|
assert((!FromType.isNull() || !ToType.isNull()) &&
|
|
|
|
"Only one template argument may be missing.");
|
|
|
|
|
|
|
|
if (Same) {
|
2014-07-25 00:24:02 +00:00
|
|
|
OS << FromType.getAsString(Policy);
|
2012-06-26 18:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-28 20:32:51 +00:00
|
|
|
if (!FromType.isNull() && !ToType.isNull() &&
|
|
|
|
FromType.getLocalUnqualifiedType() ==
|
|
|
|
ToType.getLocalUnqualifiedType()) {
|
|
|
|
Qualifiers FromQual = FromType.getLocalQualifiers(),
|
2013-11-26 02:52:41 +00:00
|
|
|
ToQual = ToType.getLocalQualifiers();
|
2012-09-28 20:32:51 +00:00
|
|
|
PrintQualifiers(FromQual, ToQual);
|
|
|
|
FromType.getLocalUnqualifiedType().print(OS, Policy);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
std::string FromTypeStr = FromType.isNull() ? "(no argument)"
|
2014-07-25 00:24:02 +00:00
|
|
|
: FromType.getAsString(Policy);
|
2012-06-26 18:18:47 +00:00
|
|
|
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
|
2014-07-25 00:24:02 +00:00
|
|
|
: ToType.getAsString(Policy);
|
[clang] Implement ElaboratedType sugaring for types written bare
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.
The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.
An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.
---
Troubleshooting list to deal with any breakage seen with this patch:
1) The most likely effect one would see by this patch is a change in how
a type is printed. The type printer will, by design and default,
print types as written. There are customization options there, but
not that many, and they mainly apply to how to print a type that we
somehow failed to track how it was written. This patch fixes a
problem where we failed to distinguish between a type
that was written without any elaborated-type qualifiers,
such as a 'struct'/'class' tags and name spacifiers such as 'std::',
and one that has been stripped of any 'metadata' that identifies such,
the so called canonical types.
Example:
```
namespace foo {
struct A {};
A a;
};
```
If one were to print the type of `foo::a`, prior to this patch, this
would result in `foo::A`. This is how the type printer would have,
by default, printed the canonical type of A as well.
As soon as you add any name qualifiers to A, the type printer would
suddenly start accurately printing the type as written. This patch
will make it print it accurately even when written without
qualifiers, so we will just print `A` for the initial example, as
the user did not really write that `foo::` namespace qualifier.
2) This patch could expose a bug in some AST matcher. Matching types
is harder to get right when there is sugar involved. For example,
if you want to match a type against being a pointer to some type A,
then you have to account for getting a type that is sugar for a
pointer to A, or being a pointer to sugar to A, or both! Usually
you would get the second part wrong, and this would work for a
very simple test where you don't use any name qualifiers, but
you would discover is broken when you do. The usual fix is to
either use the matcher which strips sugar, which is annoying
to use as for example if you match an N level pointer, you have
to put N+1 such matchers in there, beginning to end and between
all those levels. But in a lot of cases, if the property you want
to match is present in the canonical type, it's easier and faster
to just match on that... This goes with what is said in 1), if
you want to match against the name of a type, and you want
the name string to be something stable, perhaps matching on
the name of the canonical type is the better choice.
3) This patch could expose a bug in how you get the source range of some
TypeLoc. For some reason, a lot of code is using getLocalSourceRange(),
which only looks at the given TypeLoc node. This patch introduces a new,
and more common TypeLoc node which contains no source locations on itself.
This is not an inovation here, and some other, more rare TypeLoc nodes could
also have this property, but if you use getLocalSourceRange on them, it's not
going to return any valid locations, because it doesn't have any. The right fix
here is to always use getSourceRange() or getBeginLoc/getEndLoc which will dive
into the inner TypeLoc to get the source range if it doesn't find it on the
top level one. You can use getLocalSourceRange if you are really into
micro-optimizations and you have some outside knowledge that the TypeLocs you are
dealing with will always include some source location.
4) Exposed a bug somewhere in the use of the normal clang type class API, where you
have some type, you want to see if that type is some particular kind, you try a
`dyn_cast` such as `dyn_cast<TypedefType>` and that fails because now you have an
ElaboratedType which has a TypeDefType inside of it, which is what you wanted to match.
Again, like 2), this would usually have been tested poorly with some simple tests with
no qualifications, and would have been broken had there been any other kind of type sugar,
be it an ElaboratedType or a TemplateSpecializationType or a SubstTemplateParmType.
The usual fix here is to use `getAs` instead of `dyn_cast`, which will look deeper
into the type. Or use `getAsAdjusted` when dealing with TypeLocs.
For some reason the API is inconsistent there and on TypeLocs getAs behaves like a dyn_cast.
5) It could be a bug in this patch perhaps.
Let me know if you need any help!
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Differential Revision: https://reviews.llvm.org/D112374
2021-10-11 18:15:36 +02:00
|
|
|
// Print without ElaboratedType sugar if it is better.
|
2012-06-26 18:18:47 +00:00
|
|
|
// TODO: merge this with other aka printing above.
|
|
|
|
if (FromTypeStr == ToTypeStr) {
|
[clang] Implement ElaboratedType sugaring for types written bare
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.
The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.
An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.
---
Troubleshooting list to deal with any breakage seen with this patch:
1) The most likely effect one would see by this patch is a change in how
a type is printed. The type printer will, by design and default,
print types as written. There are customization options there, but
not that many, and they mainly apply to how to print a type that we
somehow failed to track how it was written. This patch fixes a
problem where we failed to distinguish between a type
that was written without any elaborated-type qualifiers,
such as a 'struct'/'class' tags and name spacifiers such as 'std::',
and one that has been stripped of any 'metadata' that identifies such,
the so called canonical types.
Example:
```
namespace foo {
struct A {};
A a;
};
```
If one were to print the type of `foo::a`, prior to this patch, this
would result in `foo::A`. This is how the type printer would have,
by default, printed the canonical type of A as well.
As soon as you add any name qualifiers to A, the type printer would
suddenly start accurately printing the type as written. This patch
will make it print it accurately even when written without
qualifiers, so we will just print `A` for the initial example, as
the user did not really write that `foo::` namespace qualifier.
2) This patch could expose a bug in some AST matcher. Matching types
is harder to get right when there is sugar involved. For example,
if you want to match a type against being a pointer to some type A,
then you have to account for getting a type that is sugar for a
pointer to A, or being a pointer to sugar to A, or both! Usually
you would get the second part wrong, and this would work for a
very simple test where you don't use any name qualifiers, but
you would discover is broken when you do. The usual fix is to
either use the matcher which strips sugar, which is annoying
to use as for example if you match an N level pointer, you have
to put N+1 such matchers in there, beginning to end and between
all those levels. But in a lot of cases, if the property you want
to match is present in the canonical type, it's easier and faster
to just match on that... This goes with what is said in 1), if
you want to match against the name of a type, and you want
the name string to be something stable, perhaps matching on
the name of the canonical type is the better choice.
3) This patch could expose a bug in how you get the source range of some
TypeLoc. For some reason, a lot of code is using getLocalSourceRange(),
which only looks at the given TypeLoc node. This patch introduces a new,
and more common TypeLoc node which contains no source locations on itself.
This is not an inovation here, and some other, more rare TypeLoc nodes could
also have this property, but if you use getLocalSourceRange on them, it's not
going to return any valid locations, because it doesn't have any. The right fix
here is to always use getSourceRange() or getBeginLoc/getEndLoc which will dive
into the inner TypeLoc to get the source range if it doesn't find it on the
top level one. You can use getLocalSourceRange if you are really into
micro-optimizations and you have some outside knowledge that the TypeLocs you are
dealing with will always include some source location.
4) Exposed a bug somewhere in the use of the normal clang type class API, where you
have some type, you want to see if that type is some particular kind, you try a
`dyn_cast` such as `dyn_cast<TypedefType>` and that fails because now you have an
ElaboratedType which has a TypeDefType inside of it, which is what you wanted to match.
Again, like 2), this would usually have been tested poorly with some simple tests with
no qualifications, and would have been broken had there been any other kind of type sugar,
be it an ElaboratedType or a TemplateSpecializationType or a SubstTemplateParmType.
The usual fix here is to use `getAs` instead of `dyn_cast`, which will look deeper
into the type. Or use `getAsAdjusted` when dealing with TypeLocs.
For some reason the API is inconsistent there and on TypeLocs getAs behaves like a dyn_cast.
5) It could be a bug in this patch perhaps.
Let me know if you need any help!
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Differential Revision: https://reviews.llvm.org/D112374
2021-10-11 18:15:36 +02:00
|
|
|
const auto *FromElTy = dyn_cast<ElaboratedType>(FromType),
|
|
|
|
*ToElTy = dyn_cast<ElaboratedType>(ToType);
|
|
|
|
if (FromElTy || ToElTy) {
|
|
|
|
std::string FromNamedTypeStr =
|
|
|
|
FromElTy ? FromElTy->getNamedType().getAsString(Policy)
|
|
|
|
: FromTypeStr;
|
|
|
|
std::string ToNamedTypeStr =
|
|
|
|
ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr;
|
|
|
|
if (FromNamedTypeStr != ToNamedTypeStr) {
|
|
|
|
FromTypeStr = FromNamedTypeStr;
|
|
|
|
ToTypeStr = ToNamedTypeStr;
|
|
|
|
goto PrintTypes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Switch to canonical typename if it is better.
|
2014-07-25 00:24:02 +00:00
|
|
|
std::string FromCanTypeStr =
|
|
|
|
FromType.getCanonicalType().getAsString(Policy);
|
|
|
|
std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy);
|
2012-06-26 18:18:47 +00:00
|
|
|
if (FromCanTypeStr != ToCanTypeStr) {
|
|
|
|
FromTypeStr = FromCanTypeStr;
|
|
|
|
ToTypeStr = ToCanTypeStr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clang] Implement ElaboratedType sugaring for types written bare
Without this patch, clang will not wrap in an ElaboratedType node types written
without a keyword and nested name qualifier, which goes against the intent that
we should produce an AST which retains enough details to recover how things are
written.
The lack of this sugar is incompatible with the intent of the type printer
default policy, which is to print types as written, but to fall back and print
them fully qualified when they are desugared.
An ElaboratedTypeLoc without keyword / NNS uses no storage by itself, but still
requires pointer alignment due to pre-existing bug in the TypeLoc buffer
handling.
---
Troubleshooting list to deal with any breakage seen with this patch:
1) The most likely effect one would see by this patch is a change in how
a type is printed. The type printer will, by design and default,
print types as written. There are customization options there, but
not that many, and they mainly apply to how to print a type that we
somehow failed to track how it was written. This patch fixes a
problem where we failed to distinguish between a type
that was written without any elaborated-type qualifiers,
such as a 'struct'/'class' tags and name spacifiers such as 'std::',
and one that has been stripped of any 'metadata' that identifies such,
the so called canonical types.
Example:
```
namespace foo {
struct A {};
A a;
};
```
If one were to print the type of `foo::a`, prior to this patch, this
would result in `foo::A`. This is how the type printer would have,
by default, printed the canonical type of A as well.
As soon as you add any name qualifiers to A, the type printer would
suddenly start accurately printing the type as written. This patch
will make it print it accurately even when written without
qualifiers, so we will just print `A` for the initial example, as
the user did not really write that `foo::` namespace qualifier.
2) This patch could expose a bug in some AST matcher. Matching types
is harder to get right when there is sugar involved. For example,
if you want to match a type against being a pointer to some type A,
then you have to account for getting a type that is sugar for a
pointer to A, or being a pointer to sugar to A, or both! Usually
you would get the second part wrong, and this would work for a
very simple test where you don't use any name qualifiers, but
you would discover is broken when you do. The usual fix is to
either use the matcher which strips sugar, which is annoying
to use as for example if you match an N level pointer, you have
to put N+1 such matchers in there, beginning to end and between
all those levels. But in a lot of cases, if the property you want
to match is present in the canonical type, it's easier and faster
to just match on that... This goes with what is said in 1), if
you want to match against the name of a type, and you want
the name string to be something stable, perhaps matching on
the name of the canonical type is the better choice.
3) This patch could expose a bug in how you get the source range of some
TypeLoc. For some reason, a lot of code is using getLocalSourceRange(),
which only looks at the given TypeLoc node. This patch introduces a new,
and more common TypeLoc node which contains no source locations on itself.
This is not an inovation here, and some other, more rare TypeLoc nodes could
also have this property, but if you use getLocalSourceRange on them, it's not
going to return any valid locations, because it doesn't have any. The right fix
here is to always use getSourceRange() or getBeginLoc/getEndLoc which will dive
into the inner TypeLoc to get the source range if it doesn't find it on the
top level one. You can use getLocalSourceRange if you are really into
micro-optimizations and you have some outside knowledge that the TypeLocs you are
dealing with will always include some source location.
4) Exposed a bug somewhere in the use of the normal clang type class API, where you
have some type, you want to see if that type is some particular kind, you try a
`dyn_cast` such as `dyn_cast<TypedefType>` and that fails because now you have an
ElaboratedType which has a TypeDefType inside of it, which is what you wanted to match.
Again, like 2), this would usually have been tested poorly with some simple tests with
no qualifications, and would have been broken had there been any other kind of type sugar,
be it an ElaboratedType or a TemplateSpecializationType or a SubstTemplateParmType.
The usual fix here is to use `getAs` instead of `dyn_cast`, which will look deeper
into the type. Or use `getAsAdjusted` when dealing with TypeLocs.
For some reason the API is inconsistent there and on TypeLocs getAs behaves like a dyn_cast.
5) It could be a bug in this patch perhaps.
Let me know if you need any help!
Signed-off-by: Matheus Izvekov <mizvekov@gmail.com>
Differential Revision: https://reviews.llvm.org/D112374
2021-10-11 18:15:36 +02:00
|
|
|
PrintTypes:
|
2012-06-26 18:18:47 +00:00
|
|
|
if (PrintTree) OS << '[';
|
|
|
|
OS << (FromDefault ? "(default) " : "");
|
|
|
|
Bold();
|
|
|
|
OS << FromTypeStr;
|
|
|
|
Unbold();
|
|
|
|
if (PrintTree) {
|
|
|
|
OS << " != " << (ToDefault ? "(default) " : "");
|
|
|
|
Bold();
|
|
|
|
OS << ToTypeStr;
|
|
|
|
Unbold();
|
|
|
|
OS << "]";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintExpr - Prints out the expr template arguments, highlighting argument
|
|
|
|
/// differences.
|
2016-01-15 01:08:56 +00:00
|
|
|
void PrintExpr(const Expr *FromExpr, const Expr *ToExpr, bool FromDefault,
|
|
|
|
bool ToDefault, bool Same) {
|
2012-06-26 18:18:47 +00:00
|
|
|
assert((FromExpr || ToExpr) &&
|
|
|
|
"Only one template argument may be missing.");
|
|
|
|
if (Same) {
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintExpr(FromExpr);
|
2012-06-26 18:18:47 +00:00
|
|
|
} else if (!PrintTree) {
|
|
|
|
OS << (FromDefault ? "(default) " : "");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintExpr(FromExpr);
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
OS << (FromDefault ? "[(default) " : "[");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintExpr(FromExpr);
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
OS << " != " << (ToDefault ? "(default) " : "");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintExpr(ToExpr);
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintExpr - Actual formatting and printing of expressions.
|
2016-01-15 01:08:56 +00:00
|
|
|
void PrintExpr(const Expr *E) {
|
2014-07-24 04:24:50 +00:00
|
|
|
if (E) {
|
2014-05-12 05:36:57 +00:00
|
|
|
E->printPretty(OS, nullptr, Policy);
|
2014-07-24 04:24:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
OS << "(no argument)";
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintTemplateTemplate - Handles printing of template template arguments,
|
|
|
|
/// highlighting argument differences.
|
|
|
|
void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,
|
|
|
|
bool FromDefault, bool ToDefault, bool Same) {
|
|
|
|
assert((FromTD || ToTD) && "Only one template argument may be missing.");
|
2013-01-31 02:47:46 +00:00
|
|
|
|
2020-01-28 20:23:46 +01:00
|
|
|
std::string FromName =
|
|
|
|
std::string(FromTD ? FromTD->getName() : "(no argument)");
|
|
|
|
std::string ToName = std::string(ToTD ? ToTD->getName() : "(no argument)");
|
2013-01-31 02:47:46 +00:00
|
|
|
if (FromTD && ToTD && FromName == ToName) {
|
|
|
|
FromName = FromTD->getQualifiedNameAsString();
|
|
|
|
ToName = ToTD->getQualifiedNameAsString();
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
if (Same) {
|
2020-08-05 11:48:09 +01:00
|
|
|
OS << "template " << FromTD->getDeclName();
|
2012-06-26 18:18:47 +00:00
|
|
|
} else if (!PrintTree) {
|
|
|
|
OS << (FromDefault ? "(default) template " : "template ");
|
|
|
|
Bold();
|
2013-01-31 02:47:46 +00:00
|
|
|
OS << FromName;
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
OS << (FromDefault ? "[(default) template " : "[template ");
|
|
|
|
Bold();
|
2013-01-31 02:47:46 +00:00
|
|
|
OS << FromName;
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
OS << " != " << (ToDefault ? "(default) template " : "template ");
|
|
|
|
Bold();
|
2013-01-31 02:47:46 +00:00
|
|
|
OS << ToName;
|
2012-06-26 18:18:47 +00:00
|
|
|
Unbold();
|
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-01 21:29:28 +00:00
|
|
|
/// PrintAPSInt - Handles printing of integral arguments, highlighting
|
|
|
|
/// argument differences.
|
2016-06-15 14:20:56 +00:00
|
|
|
void PrintAPSInt(const llvm::APSInt &FromInt, const llvm::APSInt &ToInt,
|
2016-01-15 02:55:17 +00:00
|
|
|
bool IsValidFromInt, bool IsValidToInt, QualType FromIntType,
|
|
|
|
QualType ToIntType, Expr *FromExpr, Expr *ToExpr,
|
|
|
|
bool FromDefault, bool ToDefault, bool Same) {
|
2012-11-01 21:29:28 +00:00
|
|
|
assert((IsValidFromInt || IsValidToInt) &&
|
|
|
|
"Only one integral argument may be missing.");
|
|
|
|
|
|
|
|
if (Same) {
|
2016-01-15 02:55:17 +00:00
|
|
|
if (FromIntType->isBooleanType()) {
|
|
|
|
OS << ((FromInt == 0) ? "false" : "true");
|
|
|
|
} else {
|
2021-06-11 13:19:00 +01:00
|
|
|
OS << toString(FromInt, 10);
|
2016-01-15 02:55:17 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrintType = IsValidFromInt && IsValidToInt &&
|
|
|
|
!Context.hasSameType(FromIntType, ToIntType);
|
|
|
|
|
|
|
|
if (!PrintTree) {
|
2012-11-01 21:29:28 +00:00
|
|
|
OS << (FromDefault ? "(default) " : "");
|
2016-01-15 02:55:17 +00:00
|
|
|
PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
|
2012-11-01 21:29:28 +00:00
|
|
|
} else {
|
|
|
|
OS << (FromDefault ? "[(default) " : "[");
|
2016-01-15 02:55:17 +00:00
|
|
|
PrintAPSInt(FromInt, FromExpr, IsValidFromInt, FromIntType, PrintType);
|
2012-11-01 21:29:28 +00:00
|
|
|
OS << " != " << (ToDefault ? "(default) " : "");
|
2016-01-15 02:55:17 +00:00
|
|
|
PrintAPSInt(ToInt, ToExpr, IsValidToInt, ToIntType, PrintType);
|
2012-11-01 21:29:28 +00:00
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 23:55:09 +00:00
|
|
|
/// PrintAPSInt - If valid, print the APSInt. If the expression is
|
|
|
|
/// gives more information, print it too.
|
2016-06-15 14:20:56 +00:00
|
|
|
void PrintAPSInt(const llvm::APSInt &Val, Expr *E, bool Valid,
|
|
|
|
QualType IntType, bool PrintType) {
|
2013-03-15 23:55:09 +00:00
|
|
|
Bold();
|
|
|
|
if (Valid) {
|
|
|
|
if (HasExtraInfo(E)) {
|
|
|
|
PrintExpr(E);
|
|
|
|
Unbold();
|
|
|
|
OS << " aka ";
|
|
|
|
Bold();
|
|
|
|
}
|
2016-01-15 02:55:17 +00:00
|
|
|
if (PrintType) {
|
|
|
|
Unbold();
|
|
|
|
OS << "(";
|
|
|
|
Bold();
|
|
|
|
IntType.print(OS, Context.getPrintingPolicy());
|
|
|
|
Unbold();
|
|
|
|
OS << ") ";
|
|
|
|
Bold();
|
|
|
|
}
|
|
|
|
if (IntType->isBooleanType()) {
|
|
|
|
OS << ((Val == 0) ? "false" : "true");
|
|
|
|
} else {
|
2021-06-11 13:19:00 +01:00
|
|
|
OS << toString(Val, 10);
|
2016-01-15 02:55:17 +00:00
|
|
|
}
|
2014-07-01 04:17:53 +00:00
|
|
|
} else if (E) {
|
|
|
|
PrintExpr(E);
|
2013-03-15 23:55:09 +00:00
|
|
|
} else {
|
|
|
|
OS << "(no argument)";
|
|
|
|
}
|
|
|
|
Unbold();
|
|
|
|
}
|
2015-01-24 02:48:32 +00:00
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
/// HasExtraInfo - Returns true if E is not an integer literal, the
|
|
|
|
/// negation of an integer literal, or a boolean literal.
|
2013-03-15 23:55:09 +00:00
|
|
|
bool HasExtraInfo(Expr *E) {
|
|
|
|
if (!E) return false;
|
2015-01-24 02:48:32 +00:00
|
|
|
|
|
|
|
E = E->IgnoreImpCasts();
|
|
|
|
|
2024-12-01 19:21:42 -08:00
|
|
|
auto CheckIntegerLiteral = [](Expr *E) {
|
|
|
|
if (auto *TemplateExpr = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
|
|
|
|
E = TemplateExpr->getReplacement();
|
|
|
|
return isa<IntegerLiteral>(E);
|
|
|
|
};
|
|
|
|
|
|
|
|
if (CheckIntegerLiteral(E)) return false;
|
2013-03-15 23:55:09 +00:00
|
|
|
|
|
|
|
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
|
|
|
|
if (UO->getOpcode() == UO_Minus)
|
2024-12-01 19:21:42 -08:00
|
|
|
if (CheckIntegerLiteral(UO->getSubExpr()))
|
2013-03-15 23:55:09 +00:00
|
|
|
return false;
|
|
|
|
|
2016-01-14 22:56:39 +00:00
|
|
|
if (isa<CXXBoolLiteralExpr>(E))
|
|
|
|
return false;
|
|
|
|
|
2013-03-15 23:55:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-15 01:08:56 +00:00
|
|
|
void PrintValueDecl(ValueDecl *VD, bool AddressOf, Expr *E, bool NullPtr) {
|
2014-07-24 04:24:50 +00:00
|
|
|
if (VD) {
|
|
|
|
if (AddressOf)
|
|
|
|
OS << "&";
|
2020-09-20 23:16:08 -07:00
|
|
|
else if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD)) {
|
|
|
|
// FIXME: Diffing the APValue would be neat.
|
|
|
|
// FIXME: Suppress this and use the full name of the declaration if the
|
|
|
|
// parameter is a pointer or reference.
|
2023-09-21 11:57:11 -07:00
|
|
|
TPO->getType().getUnqualifiedType().print(OS, Policy);
|
2022-03-01 19:33:43 -06:00
|
|
|
TPO->printAsInit(OS, Policy);
|
2020-09-20 23:16:08 -07:00
|
|
|
return;
|
|
|
|
}
|
2022-10-14 08:17:16 -04:00
|
|
|
VD->printName(OS, Policy);
|
2014-07-24 04:24:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NullPtr) {
|
2016-01-15 01:08:56 +00:00
|
|
|
if (E && !isa<CXXNullPtrLiteralExpr>(E)) {
|
|
|
|
PrintExpr(E);
|
|
|
|
if (IsBold) {
|
|
|
|
Unbold();
|
|
|
|
OS << " aka ";
|
|
|
|
Bold();
|
|
|
|
} else {
|
|
|
|
OS << " aka ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-24 04:24:50 +00:00
|
|
|
OS << "nullptr";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-05-24 11:38:22 -03:00
|
|
|
if (E) {
|
|
|
|
PrintExpr(E);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-24 04:24:50 +00:00
|
|
|
OS << "(no argument)";
|
|
|
|
}
|
|
|
|
|
2013-02-27 01:41:53 +00:00
|
|
|
/// PrintDecl - Handles printing of Decl arguments, highlighting
|
|
|
|
/// argument differences.
|
|
|
|
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
|
2014-07-24 04:24:50 +00:00
|
|
|
bool FromAddressOf, bool ToAddressOf, bool FromNullPtr,
|
2016-01-15 01:08:56 +00:00
|
|
|
bool ToNullPtr, Expr *FromExpr, Expr *ToExpr,
|
|
|
|
bool FromDefault, bool ToDefault, bool Same) {
|
2014-07-24 04:24:50 +00:00
|
|
|
assert((FromValueDecl || FromNullPtr || ToValueDecl || ToNullPtr) &&
|
2013-02-27 01:41:53 +00:00
|
|
|
"Only one Decl argument may be NULL");
|
|
|
|
|
|
|
|
if (Same) {
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
|
2013-02-27 01:41:53 +00:00
|
|
|
} else if (!PrintTree) {
|
|
|
|
OS << (FromDefault ? "(default) " : "");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
|
2013-02-27 01:41:53 +00:00
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
OS << (FromDefault ? "[(default) " : "[");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintValueDecl(FromValueDecl, FromAddressOf, FromExpr, FromNullPtr);
|
2013-02-27 01:41:53 +00:00
|
|
|
Unbold();
|
|
|
|
OS << " != " << (ToDefault ? "(default) " : "");
|
|
|
|
Bold();
|
2016-01-15 01:08:56 +00:00
|
|
|
PrintValueDecl(ToValueDecl, ToAddressOf, ToExpr, ToNullPtr);
|
2013-02-27 01:41:53 +00:00
|
|
|
Unbold();
|
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-15 05:01:53 +00:00
|
|
|
/// PrintValueDeclAndInteger - Uses the print functions for ValueDecl and
|
|
|
|
/// APSInt to print a mixed difference.
|
|
|
|
void PrintValueDeclAndInteger(ValueDecl *VD, bool NeedAddressOf,
|
|
|
|
bool IsNullPtr, Expr *VDExpr, bool DefaultDecl,
|
2016-06-15 14:20:56 +00:00
|
|
|
const llvm::APSInt &Val, QualType IntType,
|
2016-01-15 05:01:53 +00:00
|
|
|
Expr *IntExpr, bool DefaultInt) {
|
|
|
|
if (!PrintTree) {
|
|
|
|
OS << (DefaultDecl ? "(default) " : "");
|
|
|
|
Bold();
|
|
|
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
|
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
OS << (DefaultDecl ? "[(default) " : "[");
|
|
|
|
Bold();
|
|
|
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
|
|
|
|
Unbold();
|
|
|
|
OS << " != " << (DefaultInt ? "(default) " : "");
|
|
|
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
|
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// PrintIntegerAndValueDecl - Uses the print functions for APSInt and
|
|
|
|
/// ValueDecl to print a mixed difference.
|
2016-06-15 14:20:56 +00:00
|
|
|
void PrintIntegerAndValueDecl(const llvm::APSInt &Val, QualType IntType,
|
2016-01-15 05:01:53 +00:00
|
|
|
Expr *IntExpr, bool DefaultInt, ValueDecl *VD,
|
|
|
|
bool NeedAddressOf, bool IsNullPtr,
|
|
|
|
Expr *VDExpr, bool DefaultDecl) {
|
|
|
|
if (!PrintTree) {
|
|
|
|
OS << (DefaultInt ? "(default) " : "");
|
|
|
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
|
|
|
|
} else {
|
|
|
|
OS << (DefaultInt ? "[(default) " : "[");
|
|
|
|
PrintAPSInt(Val, IntExpr, true /*Valid*/, IntType, false /*PrintType*/);
|
|
|
|
OS << " != " << (DefaultDecl ? "(default) " : "");
|
|
|
|
Bold();
|
|
|
|
PrintValueDecl(VD, NeedAddressOf, VDExpr, IsNullPtr);
|
|
|
|
Unbold();
|
|
|
|
OS << ']';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
// Prints the appropriate placeholder for elided template arguments.
|
|
|
|
void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) {
|
|
|
|
if (PrintTree) {
|
|
|
|
OS << '\n';
|
|
|
|
for (unsigned i = 0; i < Indent; ++i)
|
|
|
|
OS << " ";
|
|
|
|
}
|
|
|
|
if (NumElideArgs == 0) return;
|
|
|
|
if (NumElideArgs == 1)
|
|
|
|
OS << "[...]";
|
|
|
|
else
|
|
|
|
OS << "[" << NumElideArgs << " * ...]";
|
|
|
|
}
|
|
|
|
|
2012-09-28 20:32:51 +00:00
|
|
|
// Prints and highlights differences in Qualifiers.
|
|
|
|
void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) {
|
|
|
|
// Both types have no qualifiers
|
|
|
|
if (FromQual.empty() && ToQual.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Both types have same qualifiers
|
|
|
|
if (FromQual == ToQual) {
|
|
|
|
PrintQualifier(FromQual, /*ApplyBold*/false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find common qualifiers and strip them from FromQual and ToQual.
|
|
|
|
Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual,
|
|
|
|
ToQual);
|
|
|
|
|
|
|
|
// The qualifiers are printed before the template name.
|
|
|
|
// Inline printing:
|
|
|
|
// The common qualifiers are printed. Then, qualifiers only in this type
|
|
|
|
// are printed and highlighted. Finally, qualifiers only in the other
|
|
|
|
// type are printed and highlighted inside parentheses after "missing".
|
|
|
|
// Tree printing:
|
|
|
|
// Qualifiers are printed next to each other, inside brackets, and
|
|
|
|
// separated by "!=". The printing order is:
|
|
|
|
// common qualifiers, highlighted from qualifiers, "!=",
|
|
|
|
// common qualifiers, highlighted to qualifiers
|
|
|
|
if (PrintTree) {
|
|
|
|
OS << "[";
|
|
|
|
if (CommonQual.empty() && FromQual.empty()) {
|
|
|
|
Bold();
|
|
|
|
OS << "(no qualifiers) ";
|
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
PrintQualifier(CommonQual, /*ApplyBold*/false);
|
|
|
|
PrintQualifier(FromQual, /*ApplyBold*/true);
|
|
|
|
}
|
|
|
|
OS << "!= ";
|
|
|
|
if (CommonQual.empty() && ToQual.empty()) {
|
|
|
|
Bold();
|
|
|
|
OS << "(no qualifiers)";
|
|
|
|
Unbold();
|
|
|
|
} else {
|
|
|
|
PrintQualifier(CommonQual, /*ApplyBold*/false,
|
|
|
|
/*appendSpaceIfNonEmpty*/!ToQual.empty());
|
|
|
|
PrintQualifier(ToQual, /*ApplyBold*/true,
|
|
|
|
/*appendSpaceIfNonEmpty*/false);
|
|
|
|
}
|
|
|
|
OS << "] ";
|
|
|
|
} else {
|
|
|
|
PrintQualifier(CommonQual, /*ApplyBold*/false);
|
|
|
|
PrintQualifier(FromQual, /*ApplyBold*/true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PrintQualifier(Qualifiers Q, bool ApplyBold,
|
|
|
|
bool AppendSpaceIfNonEmpty = true) {
|
|
|
|
if (Q.empty()) return;
|
|
|
|
if (ApplyBold) Bold();
|
|
|
|
Q.print(OS, Policy, AppendSpaceIfNonEmpty);
|
|
|
|
if (ApplyBold) Unbold();
|
|
|
|
}
|
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
public:
|
|
|
|
|
2013-02-22 16:08:12 +00:00
|
|
|
TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType,
|
|
|
|
QualType ToType, bool PrintTree, bool PrintFromType,
|
|
|
|
bool ElideType, bool ShowColor)
|
2012-06-26 18:18:47 +00:00
|
|
|
: Context(Context),
|
|
|
|
Policy(Context.getLangOpts()),
|
|
|
|
ElideType(ElideType),
|
|
|
|
PrintTree(PrintTree),
|
|
|
|
ShowColor(ShowColor),
|
|
|
|
// When printing a single type, the FromType is the one printed.
|
2016-01-15 05:48:38 +00:00
|
|
|
FromTemplateType(PrintFromType ? FromType : ToType),
|
|
|
|
ToTemplateType(PrintFromType ? ToType : FromType),
|
2013-02-22 16:08:12 +00:00
|
|
|
OS(OS),
|
2012-06-26 18:18:47 +00:00
|
|
|
IsBold(false) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/// DiffTemplate - Start the template type diffing.
|
|
|
|
void DiffTemplate() {
|
2016-01-15 05:48:38 +00:00
|
|
|
Qualifiers FromQual = FromTemplateType.getQualifiers(),
|
|
|
|
ToQual = ToTemplateType.getQualifiers();
|
2012-09-28 20:32:51 +00:00
|
|
|
|
2012-06-26 18:18:47 +00:00
|
|
|
const TemplateSpecializationType *FromOrigTST =
|
2016-01-15 05:48:38 +00:00
|
|
|
GetTemplateSpecializationType(Context, FromTemplateType);
|
2012-06-26 18:18:47 +00:00
|
|
|
const TemplateSpecializationType *ToOrigTST =
|
2016-01-15 05:48:38 +00:00
|
|
|
GetTemplateSpecializationType(Context, ToTemplateType);
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
// Only checking templates.
|
|
|
|
if (!FromOrigTST || !ToOrigTST)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Different base templates.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
if (!hasSameTemplate(Context, FromOrigTST, ToOrigTST)) {
|
2012-06-26 18:18:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-28 20:32:51 +00:00
|
|
|
FromQual -= QualType(FromOrigTST, 0).getQualifiers();
|
|
|
|
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
// Same base template, but different arguments.
|
[clang] Implement CWG2398 provisional TTP matching to class templates (#94981)
This extends default argument deduction to cover class templates as
well, applying only to partial ordering, adding to the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807.
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
2024-09-07 15:49:07 -03:00
|
|
|
Tree.SetTemplateDiff(
|
|
|
|
FromOrigTST->getTemplateName().getAsTemplateDecl(
|
|
|
|
/*IgnoreDeduced=*/true),
|
|
|
|
ToOrigTST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true),
|
|
|
|
FromQual, ToQual, false /*FromDefault*/, false /*ToDefault*/);
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
DiffTemplate(FromOrigTST, ToOrigTST);
|
2012-06-26 18:52:09 +00:00
|
|
|
}
|
2012-06-26 18:18:47 +00:00
|
|
|
|
2013-02-22 16:13:34 +00:00
|
|
|
/// Emit - When the two types given are templated types with the same
|
2012-06-26 18:18:47 +00:00
|
|
|
/// base template, a string representation of the type difference will be
|
2013-02-22 16:13:34 +00:00
|
|
|
/// emitted to the stream and return true. Otherwise, return false.
|
2013-02-22 16:08:12 +00:00
|
|
|
bool Emit() {
|
2012-06-26 18:18:47 +00:00
|
|
|
Tree.StartTraverse();
|
|
|
|
if (Tree.Empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
TreeToString();
|
|
|
|
assert(!IsBold && "Bold is applied to end of string.");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}; // end class TemplateDiff
|
2016-02-10 19:11:58 +00:00
|
|
|
} // end anonymous namespace
|
2012-06-26 18:18:47 +00:00
|
|
|
|
|
|
|
/// FormatTemplateTypeDiff - A helper static function to start the template
|
|
|
|
/// diff and return the properly formatted string. Returns true if the diff
|
|
|
|
/// is successful.
|
|
|
|
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
|
|
|
|
QualType ToType, bool PrintTree,
|
2018-07-30 19:24:48 +00:00
|
|
|
bool PrintFromType, bool ElideType,
|
2013-02-22 16:08:12 +00:00
|
|
|
bool ShowColors, raw_ostream &OS) {
|
2012-06-26 18:18:47 +00:00
|
|
|
if (PrintTree)
|
|
|
|
PrintFromType = true;
|
2013-02-22 16:08:12 +00:00
|
|
|
TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType,
|
2012-06-26 18:18:47 +00:00
|
|
|
ElideType, ShowColors);
|
|
|
|
TD.DiffTemplate();
|
2013-02-22 16:08:12 +00:00
|
|
|
return TD.Emit();
|
2012-06-26 18:18:47 +00:00
|
|
|
}
|