aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/TemplateBase.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/AST/TemplateBase.cpp308
1 files changed, 255 insertions, 53 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp b/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
index baf62bd115a8..3310d7dc24c5 100644
--- a/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
+++ b/contrib/llvm-project/clang/lib/AST/TemplateBase.cpp
@@ -29,8 +29,8 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
@@ -40,6 +40,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <optional>
using namespace clang;
@@ -50,43 +51,137 @@ using namespace clang;
/// \param Out the raw_ostream instance to use for printing.
///
/// \param Policy the printing policy for EnumConstantDecl printing.
-static void printIntegral(const TemplateArgument &TemplArg,
- raw_ostream &Out, const PrintingPolicy& Policy) {
+///
+/// \param IncludeType If set, ensure that the type of the expression printed
+/// matches the type of the template argument.
+static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out,
+ const PrintingPolicy &Policy, bool IncludeType) {
const Type *T = TemplArg.getIntegralType().getTypePtr();
const llvm::APSInt &Val = TemplArg.getAsIntegral();
- if (const EnumType *ET = T->getAs<EnumType>()) {
- for (const EnumConstantDecl* ECD : ET->getDecl()->enumerators()) {
- // In Sema::CheckTemplateArugment, enum template arguments value are
- // extended to the size of the integer underlying the enum type. This
- // may create a size difference between the enum value and template
- // argument value, requiring isSameValue here instead of operator==.
- if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) {
- ECD->printQualifiedName(Out, Policy);
- return;
+ if (Policy.UseEnumerators) {
+ if (const EnumType *ET = T->getAs<EnumType>()) {
+ for (const EnumConstantDecl *ECD : ET->getDecl()->enumerators()) {
+ // In Sema::CheckTemplateArugment, enum template arguments value are
+ // extended to the size of the integer underlying the enum type. This
+ // may create a size difference between the enum value and template
+ // argument value, requiring isSameValue here instead of operator==.
+ if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) {
+ ECD->printQualifiedName(Out, Policy);
+ return;
+ }
}
}
}
- if (T->isBooleanType() && !Policy.MSVCFormatting) {
- Out << (Val.getBoolValue() ? "true" : "false");
+ if (Policy.MSVCFormatting)
+ IncludeType = false;
+
+ if (T->isBooleanType()) {
+ if (!Policy.MSVCFormatting)
+ Out << (Val.getBoolValue() ? "true" : "false");
+ else
+ Out << Val;
} else if (T->isCharType()) {
- const char Ch = Val.getZExtValue();
- Out << ((Ch == '\'') ? "'\\" : "'");
- Out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true);
- Out << "'";
- } else {
+ if (IncludeType) {
+ if (T->isSpecificBuiltinType(BuiltinType::SChar))
+ Out << "(signed char)";
+ else if (T->isSpecificBuiltinType(BuiltinType::UChar))
+ Out << "(unsigned char)";
+ }
+ CharacterLiteral::print(Val.getZExtValue(), CharacterLiteralKind::Ascii,
+ Out);
+ } else if (T->isAnyCharacterType() && !Policy.MSVCFormatting) {
+ CharacterLiteralKind Kind;
+ if (T->isWideCharType())
+ Kind = CharacterLiteralKind::Wide;
+ else if (T->isChar8Type())
+ Kind = CharacterLiteralKind::UTF8;
+ else if (T->isChar16Type())
+ Kind = CharacterLiteralKind::UTF16;
+ else if (T->isChar32Type())
+ Kind = CharacterLiteralKind::UTF32;
+ else
+ Kind = CharacterLiteralKind::Ascii;
+ CharacterLiteral::print(Val.getExtValue(), Kind, Out);
+ } else if (IncludeType) {
+ if (const auto *BT = T->getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ case BuiltinType::ULongLong:
+ Out << Val << "ULL";
+ break;
+ case BuiltinType::LongLong:
+ Out << Val << "LL";
+ break;
+ case BuiltinType::ULong:
+ Out << Val << "UL";
+ break;
+ case BuiltinType::Long:
+ Out << Val << "L";
+ break;
+ case BuiltinType::UInt:
+ Out << Val << "U";
+ break;
+ case BuiltinType::Int:
+ Out << Val;
+ break;
+ default:
+ Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")"
+ << Val;
+ break;
+ }
+ } else
+ Out << "(" << T->getCanonicalTypeInternal().getAsString(Policy) << ")"
+ << Val;
+ } else
Out << Val;
+}
+
+static unsigned getArrayDepth(QualType type) {
+ unsigned count = 0;
+ while (const auto *arrayType = type->getAsArrayTypeUnsafe()) {
+ count++;
+ type = arrayType->getElementType();
}
+ return count;
+}
+
+static bool needsAmpersandOnTemplateArg(QualType paramType, QualType argType) {
+ // Generally, if the parameter type is a pointer, we must be taking the
+ // address of something and need a &. However, if the argument is an array,
+ // this could be implicit via array-to-pointer decay.
+ if (!paramType->isPointerType())
+ return paramType->isMemberPointerType();
+ if (argType->isArrayType())
+ return getArrayDepth(argType) == getArrayDepth(paramType->getPointeeType());
+ return true;
}
//===----------------------------------------------------------------------===//
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//
-TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
- QualType Type) {
+void TemplateArgument::initFromType(QualType T, bool IsNullPtr,
+ bool IsDefaulted) {
+ TypeOrValue.Kind = IsNullPtr ? NullPtr : Type;
+ TypeOrValue.IsDefaulted = IsDefaulted;
+ TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+}
+
+void TemplateArgument::initFromDeclaration(ValueDecl *D, QualType QT,
+ bool IsDefaulted) {
+ assert(D && "Expected decl");
+ DeclArg.Kind = Declaration;
+ DeclArg.IsDefaulted = IsDefaulted;
+ DeclArg.QT = QT.getAsOpaquePtr();
+ DeclArg.D = D;
+}
+
+void TemplateArgument::initFromIntegral(const ASTContext &Ctx,
+ const llvm::APSInt &Value,
+ QualType Type, bool IsDefaulted) {
Integer.Kind = Integral;
+ Integer.IsDefaulted = IsDefaulted;
// Copy the APSInt value into our decomposed form.
Integer.BitWidth = Value.getBitWidth();
Integer.IsUnsigned = Value.isUnsigned();
@@ -103,6 +198,56 @@ TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
Integer.Type = Type.getAsOpaquePtr();
}
+void TemplateArgument::initFromStructural(const ASTContext &Ctx, QualType Type,
+ const APValue &V, bool IsDefaulted) {
+ Value.Kind = StructuralValue;
+ Value.IsDefaulted = IsDefaulted;
+ Value.Value = new (Ctx) APValue(V);
+ Ctx.addDestruction(Value.Value);
+ Value.Type = Type.getAsOpaquePtr();
+}
+
+TemplateArgument::TemplateArgument(const ASTContext &Ctx,
+ const llvm::APSInt &Value, QualType Type,
+ bool IsDefaulted) {
+ initFromIntegral(Ctx, Value, Type, IsDefaulted);
+}
+
+static const ValueDecl *getAsSimpleValueDeclRef(const ASTContext &Ctx,
+ QualType T, const APValue &V) {
+ // Pointers to members are relatively easy.
+ if (V.isMemberPointer() && V.getMemberPointerPath().empty())
+ return V.getMemberPointerDecl();
+
+ // We model class non-type template parameters as their template parameter
+ // object declaration.
+ if (V.isStruct() || V.isUnion())
+ return Ctx.getTemplateParamObjectDecl(T, V);
+
+ // Pointers and references with an empty path use the special 'Declaration'
+ // representation.
+ if (V.isLValue() && V.hasLValuePath() && V.getLValuePath().empty() &&
+ !V.isLValueOnePastTheEnd())
+ return V.getLValueBase().dyn_cast<const ValueDecl *>();
+
+ // Everything else uses the 'structural' representation.
+ return nullptr;
+}
+
+TemplateArgument::TemplateArgument(const ASTContext &Ctx, QualType Type,
+ const APValue &V, bool IsDefaulted) {
+ if (Type->isIntegralOrEnumerationType() && V.isInt())
+ initFromIntegral(Ctx, V.getInt(), Type, IsDefaulted);
+ else if ((V.isLValue() && V.isNullPointer()) ||
+ (V.isMemberPointer() && !V.getMemberPointerDecl()))
+ initFromType(Type, /*isNullPtr=*/true, IsDefaulted);
+ else if (const ValueDecl *VD = getAsSimpleValueDeclRef(Ctx, Type, V))
+ // FIXME: The Declaration form should expose a const ValueDecl*.
+ initFromDeclaration(const_cast<ValueDecl *>(VD), Type, IsDefaulted);
+ else
+ initFromStructural(Ctx, Type, V, IsDefaulted);
+}
+
TemplateArgument
TemplateArgument::CreatePackCopy(ASTContext &Context,
ArrayRef<TemplateArgument> Args) {
@@ -143,6 +288,7 @@ TemplateArgumentDependence TemplateArgument::getDependence() const {
case NullPtr:
case Integral:
+ case StructuralValue:
return TemplateArgumentDependence::None;
case Expression:
@@ -173,6 +319,7 @@ bool TemplateArgument::isPackExpansion() const {
case Null:
case Declaration:
case Integral:
+ case StructuralValue:
case Pack:
case Template:
case NullPtr:
@@ -195,12 +342,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return getDependence() & TemplateArgumentDependence::UnexpandedPack;
}
-Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+std::optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(getKind() == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return None;
+ return std::nullopt;
}
QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
@@ -223,6 +370,9 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
case TemplateArgument::NullPtr:
return getNullPtrType();
+
+ case TemplateArgument::StructuralValue:
+ return getStructuralValueType();
}
llvm_unreachable("Invalid TemplateArgument Kind!");
@@ -245,30 +395,24 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
case Declaration:
getParamTypeForDecl().Profile(ID);
- ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
+ ID.AddPointer(getAsDecl());
break;
+ case TemplateExpansion:
+ ID.AddInteger(TemplateArg.NumExpansions);
+ [[fallthrough]];
case Template:
- case TemplateExpansion: {
- TemplateName Template = getAsTemplateOrTemplatePattern();
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Template.getAsTemplateDecl())) {
- ID.AddBoolean(true);
- ID.AddInteger(TTP->getDepth());
- ID.AddInteger(TTP->getPosition());
- ID.AddBoolean(TTP->isParameterPack());
- } else {
- ID.AddBoolean(false);
- ID.AddPointer(Context.getCanonicalTemplateName(Template)
- .getAsVoidPointer());
- }
+ ID.AddPointer(TemplateArg.Name);
break;
- }
case Integral:
- getAsIntegral().Profile(ID);
getIntegralType().Profile(ID);
+ getAsIntegral().Profile(ID);
+ break;
+
+ case StructuralValue:
+ getStructuralValueType().Profile(ID);
+ getAsStructuralValue().Profile(ID);
break;
case Expression:
@@ -298,12 +442,24 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
TemplateArg.NumExpansions == Other.TemplateArg.NumExpansions;
case Declaration:
- return getAsDecl() == Other.getAsDecl();
+ return getAsDecl() == Other.getAsDecl() &&
+ getParamTypeForDecl() == Other.getParamTypeForDecl();
case Integral:
return getIntegralType() == Other.getIntegralType() &&
getAsIntegral() == Other.getAsIntegral();
+ case StructuralValue: {
+ if (getStructuralValueType().getCanonicalType() !=
+ Other.getStructuralValueType().getCanonicalType())
+ return false;
+
+ llvm::FoldingSetNodeID A, B;
+ getAsStructuralValue().Profile(A);
+ Other.getAsStructuralValue().Profile(B);
+ return A == B;
+ }
+
case Pack:
if (Args.NumArgs != Other.Args.NumArgs) return false;
for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
@@ -330,6 +486,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
case Declaration:
case Integral:
+ case StructuralValue:
case Pack:
case Null:
case Template:
@@ -340,8 +497,9 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-void TemplateArgument::print(const PrintingPolicy &Policy,
- raw_ostream &Out) const {
+void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
+ bool IncludeType) const {
+
switch (getKind()) {
case Null:
Out << "(no value)";
@@ -358,23 +516,30 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
NamedDecl *ND = getAsDecl();
if (getParamTypeForDecl()->isRecordType()) {
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
- // FIXME: Include the type if it's not obvious from the context.
- TPO->printAsInit(Out);
+ TPO->getType().getUnqualifiedType().print(Out, Policy);
+ TPO->printAsInit(Out, Policy);
break;
}
}
- if (!getParamTypeForDecl()->isReferenceType())
- Out << '&';
+ if (auto *VD = dyn_cast<ValueDecl>(ND)) {
+ if (needsAmpersandOnTemplateArg(getParamTypeForDecl(), VD->getType()))
+ Out << "&";
+ }
ND->printQualifiedName(Out);
break;
}
+ case StructuralValue:
+ getAsStructuralValue().printPretty(Out, Policy, getStructuralValueType());
+ break;
+
case NullPtr:
+ // FIXME: Include the type if it's not obvious from the context.
Out << "nullptr";
break;
case Template:
- getAsTemplate().print(Out, Policy);
+ getAsTemplate().print(Out, Policy, TemplateName::Qualified::Fully);
break;
case TemplateExpansion:
@@ -383,7 +548,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
case Integral:
- printIntegral(*this, Out, Policy);
+ printIntegral(*this, Out, Policy, IncludeType);
break;
case Expression:
@@ -399,7 +564,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
else
Out << ", ";
- P.print(Policy, Out);
+ P.print(Policy, Out, IncludeType);
}
Out << ">";
break;
@@ -410,7 +575,7 @@ void TemplateArgument::dump(raw_ostream &Out) const {
LangOptions LO; // FIXME! see also TemplateName::dump().
LO.CPlusPlus = true;
LO.Bool = true;
- print(PrintingPolicy(LO), Out);
+ print(PrintingPolicy(LO), Out, /*IncludeType*/ true);
}
LLVM_DUMP_METHOD void TemplateArgument::dump() const { dump(llvm::errs()); }
@@ -451,6 +616,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Integral:
return getSourceIntegralExpression()->getSourceRange();
+ case TemplateArgument::StructuralValue:
+ return getSourceStructuralValueExpression()->getSourceRange();
+
case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
@@ -477,7 +645,19 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
return DB << "nullptr";
case TemplateArgument::Integral:
- return DB << Arg.getAsIntegral().toString(10);
+ return DB << toString(Arg.getAsIntegral(), 10);
+
+ case TemplateArgument::StructuralValue: {
+ // FIXME: We're guessing at LangOptions!
+ SmallString<32> Str;
+ llvm::raw_svector_ostream OS(Str);
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = true;
+ PrintingPolicy Policy(LangOpts);
+ Arg.getAsStructuralValue().printPretty(OS, Policy,
+ Arg.getStructuralValueType());
+ return DB << OS.str();
+ }
case TemplateArgument::Template:
return DB << Arg.getAsTemplate();
@@ -505,7 +685,7 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
LangOptions LangOpts;
LangOpts.CPlusPlus = true;
PrintingPolicy Policy(LangOpts);
- Arg.print(Policy, OS);
+ Arg.print(Policy, OS, /*IncludeType*/ true);
return DB << OS.str();
}
}
@@ -537,6 +717,17 @@ ASTTemplateArgumentListInfo::Create(const ASTContext &C,
return new (Mem) ASTTemplateArgumentListInfo(List);
}
+const ASTTemplateArgumentListInfo *
+ASTTemplateArgumentListInfo::Create(const ASTContext &C,
+ const ASTTemplateArgumentListInfo *List) {
+ if (!List)
+ return nullptr;
+ std::size_t size =
+ totalSizeToAlloc<TemplateArgumentLoc>(List->getNumTemplateArgs());
+ void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
+ return new (Mem) ASTTemplateArgumentListInfo(List);
+}
+
ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
const TemplateArgumentListInfo &Info) {
LAngleLoc = Info.getLAngleLoc();
@@ -548,6 +739,17 @@ ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
}
+ASTTemplateArgumentListInfo::ASTTemplateArgumentListInfo(
+ const ASTTemplateArgumentListInfo *Info) {
+ LAngleLoc = Info->getLAngleLoc();
+ RAngleLoc = Info->getRAngleLoc();
+ NumTemplateArgs = Info->getNumTemplateArgs();
+
+ TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&ArgBuffer[i]) TemplateArgumentLoc((*Info)[i]);
+}
+
void ASTTemplateKWAndArgsInfo::initializeFrom(
SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
TemplateArgumentLoc *OutArgArray) {