mirror of
https://github.com/apple/swift.git
synced 2026-10-06 12:37:28 +02:00
0699fd2cfepreviously disabled caching for FRTInfo requests, to prevent stale cache entries keyed on AST nodes allocated out of transient Clang sub-instances used to build the PCMs used by Swift/C++ interop. Specifically, NameImporter is used during PCM building, so requests from NameImporter should not be cached.6e9a491172brought back FRTInfo caching after name lookup was redesigned to eliminate the need for that FRTInfo during name lookup (it was involved in determining whether C++ methods need the "__Unsafe" name mangling). It turns out FRTInfo is needed in one other place during NameImporter, to determine the template instance name. I did not realize it existed while working on6e9a491172. This patch avoids the stale cache issues by introduces an uncached FRTInfo API, for use during PCM building. rdar://184577717
287 lines
9.7 KiB
C++
287 lines
9.7 KiB
C++
//===--- ClangClassTemplateNamePrinter.cpp --------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ClangClassTemplateNamePrinter.h"
|
|
#include "ImporterImpl.h"
|
|
#include "swift/ClangImporter/ClangImporter.h"
|
|
#include "swift/ClangImporter/ClangImporterRequests.h"
|
|
#include "clang/AST/TemplateArgumentVisitor.h"
|
|
#include "clang/AST/TypeVisitor.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::importer;
|
|
|
|
struct TemplateInstantiationNamePrinter
|
|
: clang::TypeVisitor<TemplateInstantiationNamePrinter, std::string> {
|
|
NameImporter *nameImporter;
|
|
ImportNameVersion version;
|
|
|
|
TemplateInstantiationNamePrinter(NameImporter *nameImporter,
|
|
ImportNameVersion version)
|
|
: nameImporter(nameImporter), version(version) {}
|
|
|
|
std::string VisitType(const clang::Type *type) {
|
|
// Print "_" as a fallback if we couldn't emit a more meaningful type name.
|
|
return "_";
|
|
}
|
|
|
|
std::string VisitBuiltinType(const clang::BuiltinType *type) {
|
|
switch (type->getKind()) {
|
|
case clang::BuiltinType::Void:
|
|
return "Void";
|
|
case clang::BuiltinType::NullPtr:
|
|
return "__cxxNullPtrT";
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (std::optional<StringRef> swiftName = getBuiltinTypeSwiftName(type))
|
|
return swiftName->str();
|
|
|
|
return VisitType(type);
|
|
}
|
|
|
|
void emitWithCVQualifiers(llvm::raw_svector_ostream &buffer,
|
|
clang::QualType type) {
|
|
if (type.isConstQualified())
|
|
buffer << "__cxxConst<";
|
|
if (type.isVolatileQualified())
|
|
buffer << "__cxxVolatile<";
|
|
|
|
buffer << Visit(type.getTypePtr());
|
|
|
|
if (type.isVolatileQualified())
|
|
buffer << ">";
|
|
if (type.isConstQualified())
|
|
buffer << ">";
|
|
}
|
|
|
|
void emitQualifiedName(const clang::NamedDecl *namedDecl,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
SmallVector<DeclName, 2> qualifiedNameComponents;
|
|
auto unqualifiedName = nameImporter->importName(namedDecl, version);
|
|
qualifiedNameComponents.push_back(unqualifiedName.getDeclName());
|
|
const clang::DeclContext *parentCtx =
|
|
unqualifiedName.getEffectiveContext().getAsDeclContext();
|
|
while (parentCtx) {
|
|
if (auto namedParentDecl = dyn_cast<clang::NamedDecl>(parentCtx)) {
|
|
// If this component of the fully-qualified name is a decl that is
|
|
// imported into Swift, remember its name.
|
|
auto componentName = nameImporter->importName(namedParentDecl, version);
|
|
qualifiedNameComponents.push_back(componentName.getDeclName());
|
|
parentCtx = componentName.getEffectiveContext().getAsDeclContext();
|
|
} else {
|
|
// If this component is not imported into Swift, skip it.
|
|
parentCtx = parentCtx->getParent();
|
|
}
|
|
}
|
|
|
|
llvm::interleave(
|
|
llvm::reverse(qualifiedNameComponents),
|
|
[&](const DeclName &each) { each.print(buffer); },
|
|
[&]() { buffer << "."; });
|
|
}
|
|
|
|
std::string VisitTagType(const clang::TagType *type) {
|
|
auto tagDecl = type->getAsTagDecl();
|
|
if (auto namedArg = dyn_cast_or_null<clang::NamedDecl>(tagDecl)) {
|
|
if (auto typeDefDecl = tagDecl->getTypedefNameForAnonDecl())
|
|
namedArg = typeDefDecl;
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
emitQualifiedName(namedArg, buffer);
|
|
return buffer.str().str();
|
|
}
|
|
return "_";
|
|
}
|
|
|
|
std::string VisitReferenceType(const clang::ReferenceType *type) {
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
if (type->isLValueReferenceType()) {
|
|
buffer << "__cxxLRef<";
|
|
} else {
|
|
buffer << "__cxxRRef<";
|
|
}
|
|
|
|
emitWithCVQualifiers(buffer, type->getPointeeType());
|
|
|
|
buffer << ">";
|
|
return buffer.str().str();
|
|
}
|
|
|
|
std::string VisitPointerType(const clang::PointerType *type) {
|
|
clang::QualType pointee = type->getPointeeType();
|
|
std::string pointeeResult = Visit(pointee.getTypePtr());
|
|
|
|
// If this is a pointer to foreign reference type, we should not wrap
|
|
// it in Unsafe(Mutable)?Pointer, since it will be imported as a class
|
|
// in Swift.
|
|
//
|
|
// Use the uncached FRT info API here, because NamePrinter is used during
|
|
// PCM building (via NameImporter), which means pointee->getAsRecordDecl()
|
|
// might live in a transient clang::ASTContext (from a module-building
|
|
// Clang sub-instance). Caching that pointer can lead to faulty cache hits.
|
|
bool isReferenceType = false;
|
|
if (auto *rd = pointee->getAsRecordDecl())
|
|
isReferenceType = getUncachedForeignReferenceTypeInfo(rd).isReference();
|
|
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
|
|
if (pointee.isVolatileQualified())
|
|
buffer << "__cxxVolatile<";
|
|
|
|
if (!isReferenceType) {
|
|
buffer << (pointee.isConstQualified() ? "UnsafePointer<"
|
|
: "UnsafeMutablePointer<");
|
|
buffer << pointeeResult;
|
|
buffer << '>';
|
|
} else {
|
|
if (pointee.isConstQualified())
|
|
buffer << "__cxxConst<";
|
|
buffer << pointeeResult;
|
|
if (pointee.isConstQualified())
|
|
buffer << ">";
|
|
}
|
|
|
|
if (pointee.isVolatileQualified())
|
|
buffer << ">";
|
|
|
|
return buffer.str().str();
|
|
}
|
|
|
|
std::string VisitFunctionProtoType(const clang::FunctionProtoType *type) {
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
|
|
buffer << "((";
|
|
llvm::interleaveComma(type->getParamTypes(), buffer,
|
|
[&](const clang::QualType ¶mType) {
|
|
buffer << Visit(paramType.getTypePtr());
|
|
});
|
|
buffer << ") -> ";
|
|
buffer << Visit(type->getReturnType().getTypePtr());
|
|
buffer << ")";
|
|
|
|
return buffer.str().str();
|
|
}
|
|
|
|
std::string VisitVectorType(const clang::VectorType *type) {
|
|
return (Twine("SIMD") + std::to_string(type->getNumElements()) + "<" +
|
|
Visit(type->getElementType().getTypePtr()) + ">")
|
|
.str();
|
|
}
|
|
|
|
std::string VisitArrayType(const clang::ArrayType *type) {
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
buffer << "[";
|
|
emitWithCVQualifiers(buffer, type->getElementType());
|
|
buffer << "]";
|
|
return buffer.str().str();
|
|
}
|
|
|
|
std::string VisitConstantArrayType(const clang::ConstantArrayType *type) {
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
buffer << "Vector<";
|
|
emitWithCVQualifiers(buffer, type->getElementType());
|
|
buffer << ", ";
|
|
buffer << type->getSExtSize();
|
|
buffer << ">";
|
|
return buffer.str().str();
|
|
}
|
|
};
|
|
|
|
struct TemplateArgumentPrinter
|
|
: clang::ConstTemplateArgumentVisitor<TemplateArgumentPrinter, void,
|
|
llvm::raw_svector_ostream &> {
|
|
TemplateInstantiationNamePrinter typePrinter;
|
|
|
|
TemplateArgumentPrinter(NameImporter *nameImporter, ImportNameVersion version)
|
|
: typePrinter(nameImporter, version) {}
|
|
|
|
void VisitTemplateArgument(const clang::TemplateArgument &arg,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
// Print "_" as a fallback if we couldn't emit a more meaningful type name.
|
|
buffer << "_";
|
|
}
|
|
|
|
void VisitTypeTemplateArgument(const clang::TemplateArgument &arg,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
auto ty = arg.getAsType();
|
|
|
|
typePrinter.emitWithCVQualifiers(buffer, ty);
|
|
}
|
|
|
|
void VisitIntegralTemplateArgument(const clang::TemplateArgument &arg,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
buffer << "_";
|
|
if (arg.getIntegralType()->isBuiltinType()) {
|
|
buffer << typePrinter.Visit(arg.getIntegralType().getTypePtr()) << "_";
|
|
}
|
|
auto value = arg.getAsIntegral();
|
|
if (value.isNegative()) {
|
|
value.negate();
|
|
buffer << "Neg_";
|
|
}
|
|
value.print(buffer, arg.getIntegralType()->isSignedIntegerType());
|
|
}
|
|
|
|
void VisitPackTemplateArgument(const clang::TemplateArgument &arg,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
VisitTemplateArgumentArray(arg.getPackAsArray(), buffer);
|
|
}
|
|
|
|
void VisitTemplateArgumentArray(ArrayRef<clang::TemplateArgument> args,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
bool needsComma = false;
|
|
for (auto &arg : args) {
|
|
// Do not try to print empty packs.
|
|
if (arg.getKind() == clang::TemplateArgument::ArgKind::Pack &&
|
|
arg.getPackAsArray().empty())
|
|
continue;
|
|
|
|
if (needsComma)
|
|
buffer << ", ";
|
|
Visit(arg, buffer);
|
|
needsComma = true;
|
|
}
|
|
}
|
|
|
|
void VisitTemplateTemplateArgument(const clang::TemplateArgument &arg,
|
|
llvm::raw_svector_ostream &buffer) {
|
|
auto templateName = arg.getAsTemplate();
|
|
if (auto templateDecl = templateName.getAsTemplateDecl()) {
|
|
typePrinter.emitQualifiedName(templateDecl, buffer);
|
|
} else {
|
|
buffer << "_";
|
|
}
|
|
}
|
|
};
|
|
|
|
std::string swift::importer::printClassTemplateSpecializationName(
|
|
const clang::ClassTemplateSpecializationDecl *decl,
|
|
NameImporter *nameImporter, ImportNameVersion version) {
|
|
TemplateArgumentPrinter templateArgPrinter(nameImporter, version);
|
|
|
|
llvm::SmallString<128> storage;
|
|
llvm::raw_svector_ostream buffer(storage);
|
|
decl->printName(buffer);
|
|
buffer << "<";
|
|
templateArgPrinter.VisitTemplateArgumentArray(
|
|
decl->getTemplateArgs().asArray(), buffer);
|
|
buffer << ">";
|
|
return buffer.str().str();
|
|
}
|