aboutsummaryrefslogtreecommitdiff
path: root/clang/include
diff options
context:
space:
mode:
Diffstat (limited to 'clang/include')
-rw-r--r--clang/include/clang/APINotes/Types.h27
-rw-r--r--clang/include/clang/AST/APNumericStorage.h3
-rw-r--r--clang/include/clang/AST/APValue.h2
-rw-r--r--clang/include/clang/AST/ASTConcept.h9
-rw-r--r--clang/include/clang/AST/ASTContext.h217
-rw-r--r--clang/include/clang/AST/ASTImporter.h2
-rw-r--r--clang/include/clang/AST/ASTNodeTraverser.h40
-rw-r--r--clang/include/clang/AST/ASTTypeTraits.h15
-rw-r--r--clang/include/clang/AST/AbstractBasicReader.h41
-rw-r--r--clang/include/clang/AST/AbstractBasicWriter.h37
-rw-r--r--clang/include/clang/AST/CXXInheritance.h2
-rw-r--r--clang/include/clang/AST/CanonicalType.h11
-rw-r--r--clang/include/clang/AST/Comment.h21
-rw-r--r--clang/include/clang/AST/CommentHTMLTags.td5
-rw-r--r--clang/include/clang/AST/CommentSema.h1
-rw-r--r--clang/include/clang/AST/Decl.h73
-rw-r--r--clang/include/clang/AST/DeclBase.h16
-rw-r--r--clang/include/clang/AST/DeclCXX.h61
-rw-r--r--clang/include/clang/AST/DeclObjC.h3
-rw-r--r--clang/include/clang/AST/DeclTemplate.h47
-rw-r--r--clang/include/clang/AST/DeclarationName.h2
-rw-r--r--clang/include/clang/AST/DependenceFlags.h2
-rw-r--r--clang/include/clang/AST/DynamicRecursiveASTVisitor.h13
-rw-r--r--clang/include/clang/AST/Expr.h31
-rw-r--r--clang/include/clang/AST/ExprCXX.h21
-rw-r--r--clang/include/clang/AST/JSONNodeDumper.h1
-rw-r--r--clang/include/clang/AST/NestedNameSpecifier.h665
-rw-r--r--clang/include/clang/AST/NestedNameSpecifierBase.h586
-rw-r--r--clang/include/clang/AST/ODRHash.h2
-rw-r--r--clang/include/clang/AST/OpenACCClause.h67
-rw-r--r--clang/include/clang/AST/OpenMPClause.h59
-rw-r--r--clang/include/clang/AST/PrettyPrinter.h11
-rw-r--r--clang/include/clang/AST/PropertiesBase.td5
-rw-r--r--clang/include/clang/AST/QualTypeNames.h10
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h306
-rw-r--r--clang/include/clang/AST/TemplateBase.h42
-rw-r--r--clang/include/clang/AST/TemplateName.h30
-rw-r--r--clang/include/clang/AST/TextNodeDumper.h2
-rw-r--r--clang/include/clang/AST/Type.h9094
-rw-r--r--clang/include/clang/AST/TypeBase.h9281
-rw-r--r--clang/include/clang/AST/TypeLoc.h424
-rw-r--r--clang/include/clang/AST/TypeProperties.td159
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchFinder.h5
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchers.h186
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchersInternal.h20
-rw-r--r--clang/include/clang/Analysis/Analyses/LifetimeSafety.h51
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/ASTOps.h10
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h34
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h14
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/Formula.h19
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h40
-rw-r--r--clang/include/clang/Analysis/FlowSensitive/StorageLocation.h11
-rw-r--r--clang/include/clang/Basic/ABIVersions.def135
-rw-r--r--clang/include/clang/Basic/AllDiagnosticKinds.inc1
-rw-r--r--clang/include/clang/Basic/AllDiagnostics.h11
-rw-r--r--clang/include/clang/Basic/Attr.td16
-rw-r--r--clang/include/clang/Basic/AttrDocs.td149
-rw-r--r--clang/include/clang/Basic/BuiltinTemplates.td4
-rw-r--r--clang/include/clang/Basic/Builtins.td56
-rw-r--r--clang/include/clang/Basic/BuiltinsAMDGPU.def6
-rw-r--r--clang/include/clang/Basic/BuiltinsPPC.def6
-rw-r--r--clang/include/clang/Basic/BuiltinsX86.td504
-rw-r--r--clang/include/clang/Basic/CMakeLists.txt1
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.def4
-rw-r--r--clang/include/clang/Basic/CodeGenOptions.h10
-rw-r--r--clang/include/clang/Basic/Diagnostic.h6
-rw-r--r--clang/include/clang/Basic/Diagnostic.td5
-rw-r--r--clang/include/clang/Basic/DiagnosticASTKinds.td3
-rw-r--r--clang/include/clang/Basic/DiagnosticDriverKinds.td12
-rw-r--r--clang/include/clang/Basic/DiagnosticFrontendKinds.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td11
-rw-r--r--clang/include/clang/Basic/DiagnosticIDs.h156
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td5
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td7
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td112
-rw-r--r--clang/include/clang/Basic/DiagnosticTrap.h14
-rw-r--r--clang/include/clang/Basic/DiagnosticTrapKinds.td30
-rw-r--r--clang/include/clang/Basic/Features.def18
-rw-r--r--clang/include/clang/Basic/LangOptions.def3
-rw-r--r--clang/include/clang/Basic/LangOptions.h97
-rw-r--r--clang/include/clang/Basic/PointerAuthOptions.h16
-rw-r--r--clang/include/clang/Basic/TargetInfo.h10
-rw-r--r--clang/include/clang/Basic/TokenKinds.h18
-rw-r--r--clang/include/clang/Basic/TypeNodes.td32
-rw-r--r--clang/include/clang/Basic/arm_sme.td180
-rw-r--r--clang/include/clang/Basic/arm_sve.td108
-rw-r--r--clang/include/clang/Basic/riscv_vector.td935
-rw-r--r--clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h128
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIRAttrs.td263
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h35
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIRDialect.td2
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIROps.td741
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h12
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td8
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIRTypes.td8
-rw-r--r--clang/include/clang/CIR/Dialect/Passes.h1
-rw-r--r--clang/include/clang/CIR/Dialect/Passes.td10
-rw-r--r--clang/include/clang/CIR/MissingFeatures.h39
-rw-r--r--clang/include/clang/CodeGen/CGFunctionInfo.h47
-rw-r--r--clang/include/clang/CodeGen/CodeGenABITypes.h7
-rw-r--r--clang/include/clang/Driver/Action.h14
-rw-r--r--clang/include/clang/Driver/CommonArgs.h2
-rw-r--r--clang/include/clang/Driver/Driver.h32
-rw-r--r--clang/include/clang/Driver/OffloadBundler.h2
-rw-r--r--clang/include/clang/Driver/Options.td109
-rw-r--r--clang/include/clang/Driver/ToolChain.h6
-rw-r--r--clang/include/clang/ExtractAPI/DeclarationFragments.h5
-rw-r--r--clang/include/clang/Format/Format.h47
-rw-r--r--clang/include/clang/Frontend/FrontendActions.h12
-rw-r--r--clang/include/clang/Index/IndexSymbol.h1
-rw-r--r--clang/include/clang/Interpreter/Interpreter.h16
-rw-r--r--clang/include/clang/Lex/DependencyDirectivesScanner.h7
-rw-r--r--clang/include/clang/Lex/Lexer.h3
-rw-r--r--clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h310
-rw-r--r--clang/include/clang/Lex/Preprocessor.h12
-rw-r--r--clang/include/clang/Lex/Token.h17
-rw-r--r--clang/include/clang/Parse/ParseHLSLRootSignature.h4
-rw-r--r--clang/include/clang/Sema/CodeCompleteConsumer.h7
-rw-r--r--clang/include/clang/Sema/DeclSpec.h36
-rw-r--r--clang/include/clang/Sema/HeuristicResolver.h3
-rw-r--r--clang/include/clang/Sema/ParsedTemplate.h26
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h2
-rw-r--r--clang/include/clang/Sema/Sema.h111
-rw-r--r--clang/include/clang/Sema/SemaHLSL.h15
-rw-r--r--clang/include/clang/Sema/SemaInternal.h19
-rw-r--r--clang/include/clang/Sema/SemaOpenACC.h25
-rw-r--r--clang/include/clang/Sema/SemaSYCL.h1
-rw-r--r--clang/include/clang/Sema/SemaWasm.h3
-rw-r--r--clang/include/clang/Sema/TypoCorrection.h29
-rw-r--r--clang/include/clang/Serialization/ASTReader.h3
-rw-r--r--clang/include/clang/Serialization/ASTRecordReader.h2
-rw-r--r--clang/include/clang/Serialization/ASTRecordWriter.h5
-rw-r--r--clang/include/clang/Serialization/TypeBitCodes.def2
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h6
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/Checker.h4
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/CheckerManager.h11
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h23
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h13
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h4
-rw-r--r--clang/include/clang/Tooling/Refactoring/Lookup.h3
-rw-r--r--clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h16
-rw-r--r--clang/include/module.modulemap1
142 files changed, 14466 insertions, 12325 deletions
diff --git a/clang/include/clang/APINotes/Types.h b/clang/include/clang/APINotes/Types.h
index 0f2e496..7162571 100644
--- a/clang/include/clang/APINotes/Types.h
+++ b/clang/include/clang/APINotes/Types.h
@@ -141,6 +141,9 @@ class CommonTypeInfo : public CommonEntityInfo {
/// The NS error domain for this type.
std::optional<std::string> NSErrorDomain;
+ /// The Swift protocol that this type should be automatically conformed to.
+ std::optional<std::string> SwiftConformance;
+
public:
CommonTypeInfo() {}
@@ -165,6 +168,14 @@ public:
: std::nullopt;
}
+ std::optional<std::string> getSwiftConformance() const {
+ return SwiftConformance;
+ }
+
+ void setSwiftConformance(std::optional<std::string> conformance) {
+ SwiftConformance = conformance;
+ }
+
friend bool operator==(const CommonTypeInfo &, const CommonTypeInfo &);
CommonTypeInfo &operator|=(const CommonTypeInfo &RHS) {
@@ -175,6 +186,8 @@ public:
setSwiftBridge(RHS.getSwiftBridge());
if (!NSErrorDomain)
setNSErrorDomain(RHS.getNSErrorDomain());
+ if (SwiftConformance)
+ setSwiftConformance(RHS.getSwiftConformance());
return *this;
}
@@ -185,7 +198,8 @@ public:
inline bool operator==(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
LHS.SwiftBridge == RHS.SwiftBridge &&
- LHS.NSErrorDomain == RHS.NSErrorDomain;
+ LHS.NSErrorDomain == RHS.NSErrorDomain &&
+ LHS.SwiftConformance == RHS.SwiftConformance;
}
inline bool operator!=(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
@@ -737,11 +751,9 @@ public:
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
std::optional<std::string> SwiftReleaseOp;
+ std::optional<std::string> SwiftDestroyOp;
std::optional<std::string> SwiftDefaultOwnership;
- /// The Swift protocol that this type should be automatically conformed to.
- std::optional<std::string> SwiftConformance;
-
std::optional<EnumExtensibilityKind> EnumExtensibility;
TagInfo()
@@ -787,12 +799,11 @@ public:
SwiftRetainOp = RHS.SwiftRetainOp;
if (!SwiftReleaseOp)
SwiftReleaseOp = RHS.SwiftReleaseOp;
+ if (!SwiftDestroyOp)
+ SwiftDestroyOp = RHS.SwiftDestroyOp;
if (!SwiftDefaultOwnership)
SwiftDefaultOwnership = RHS.SwiftDefaultOwnership;
- if (!SwiftConformance)
- SwiftConformance = RHS.SwiftConformance;
-
if (!HasFlagEnum)
setFlagEnum(RHS.isFlagEnum());
@@ -818,8 +829,8 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
LHS.SwiftImportAs == RHS.SwiftImportAs &&
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
+ LHS.SwiftDestroyOp == RHS.SwiftDestroyOp &&
LHS.SwiftDefaultOwnership == RHS.SwiftDefaultOwnership &&
- LHS.SwiftConformance == RHS.SwiftConformance &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
LHS.isSwiftEscapable() == RHS.isSwiftEscapable() &&
diff --git a/clang/include/clang/AST/APNumericStorage.h b/clang/include/clang/AST/APNumericStorage.h
index 95eddbc..e1948a5 100644
--- a/clang/include/clang/AST/APNumericStorage.h
+++ b/clang/include/clang/AST/APNumericStorage.h
@@ -28,7 +28,6 @@ class APNumericStorage {
uint64_t VAL; ///< Used to store the <= 64 bits integer value.
uint64_t *pVal; ///< Used to store the >64 bits integer value.
};
- unsigned BitWidth;
bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; }
@@ -36,6 +35,7 @@ class APNumericStorage {
void operator=(const APNumericStorage &) = delete;
protected:
+ unsigned BitWidth;
APNumericStorage() : VAL(0), BitWidth(0) {}
llvm::APInt getIntValue() const {
@@ -51,6 +51,7 @@ protected:
class APIntStorage : private APNumericStorage {
public:
llvm::APInt getValue() const { return getIntValue(); }
+ unsigned getBitWidth() const { return BitWidth; }
void setValue(const ASTContext &C, const llvm::APInt &Val) {
setIntValue(C, Val);
}
diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h
index 9999a30..cb942ea 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -143,7 +143,7 @@ public:
AddrLabelDiff
};
- class LValueBase {
+ class alignas(uint64_t) LValueBase {
typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue,
DynamicAllocLValue>
PtrTy;
diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h
index 7ccac44..72da005 100644
--- a/clang/include/clang/AST/ASTConcept.h
+++ b/clang/include/clang/AST/ASTConcept.h
@@ -15,7 +15,7 @@
#define LLVM_CLANG_AST_ASTCONCEPT_H
#include "clang/AST/DeclarationName.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/TemplateBase.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/UnsignedOrNone.h"
@@ -177,12 +177,7 @@ public:
SourceLocation getLocation() const { return getConceptNameLoc(); }
- SourceLocation getBeginLoc() const LLVM_READONLY {
- // Note that if the qualifier is null the template KW must also be null.
- if (auto QualifierLoc = getNestedNameSpecifierLoc())
- return QualifierLoc.getBeginLoc();
- return getConceptNameInfo().getBeginLoc();
- }
+ SourceLocation getBeginLoc() const LLVM_READONLY;
SourceLocation getEndLoc() const LLVM_READONLY {
return getTemplateArgsAsWritten() &&
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 2b7ba41..1c17333 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -230,13 +230,16 @@ class ASTContext : public RefCountedBase<ASTContext> {
SubstTemplateTypeParmTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
SubstTemplateTypeParmPackTypes;
+ mutable llvm::FoldingSet<SubstBuiltinTemplatePackType>
+ SubstBuiltinTemplatePackTypes;
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
TemplateSpecializationTypes;
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
+ mutable llvm::FoldingSet<TagTypeFoldingSetPlaceholder> TagTypes;
+ mutable llvm::FoldingSet<FoldingSetPlaceholder<UnresolvedUsingType>>
+ UnresolvedUsingTypes;
mutable llvm::FoldingSet<UsingType> UsingTypes;
- mutable llvm::FoldingSet<TypedefType> TypedefTypes;
- mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{
- GeneralTypesLog2InitSize};
+ mutable llvm::FoldingSet<FoldingSetPlaceholder<TypedefType>> TypedefTypes;
mutable llvm::FoldingSet<DependentNameType> DependentNameTypes;
mutable llvm::DenseMap<llvm::FoldingSetNodeID,
DependentTemplateSpecializationType *>
@@ -282,11 +285,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
llvm::to_underlying(PredefinedSugarType::Kind::Last) + 1>
PredefinedSugarTypes{};
- /// The set of nested name specifiers.
+ /// Internal storage for NestedNameSpecifiers.
///
/// This set is managed by the NestedNameSpecifier class.
- mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers;
- mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr;
+ mutable llvm::FoldingSet<NamespaceAndPrefixStorage>
+ NamespaceAndPrefixStorages;
/// A cache mapping from RecordDecls to ASTRecordLayouts.
///
@@ -639,7 +642,7 @@ public:
/// contain data that is address discriminated. This includes
/// implicitly authenticated values like vtable pointers, as well as
/// explicitly qualified fields.
- bool containsAddressDiscriminatedPointerAuth(QualType T) {
+ bool containsAddressDiscriminatedPointerAuth(QualType T) const {
if (!isPointerAuthenticationAvailable())
return false;
return findPointerAuthContent(T) != PointerAuthContent::None;
@@ -653,8 +656,7 @@ public:
bool containsNonRelocatablePointerAuth(QualType T) {
if (!isPointerAuthenticationAvailable())
return false;
- return findPointerAuthContent(T) ==
- PointerAuthContent::AddressDiscriminatedData;
+ return findPointerAuthContent(T) != PointerAuthContent::None;
}
private:
@@ -672,8 +674,8 @@ private:
bool isPointerAuthenticationAvailable() const {
return LangOpts.PointerAuthCalls || LangOpts.PointerAuthIntrinsics;
}
- PointerAuthContent findPointerAuthContent(QualType T);
- llvm::DenseMap<const RecordDecl *, PointerAuthContent>
+ PointerAuthContent findPointerAuthContent(QualType T) const;
+ mutable llvm::DenseMap<const RecordDecl *, PointerAuthContent>
RecordContainsAddressDiscriminatedPointerAuth;
ImportDecl *FirstLocalImport = nullptr;
@@ -1386,8 +1388,6 @@ private:
/// Return a type with extended qualifiers.
QualType getExtQualType(const Type *Base, Qualifiers Quals) const;
- QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const;
-
QualType getPipeType(QualType T, bool ReadOnly) const;
public:
@@ -1630,7 +1630,7 @@ public:
/// Return the uniqued reference to the type for a member pointer to
/// the specified type in the specified nested name.
- QualType getMemberPointerType(QualType T, NestedNameSpecifier *Qualifier,
+ QualType getMemberPointerType(QualType T, NestedNameSpecifier Qualifier,
const CXXRecordDecl *Cls) const;
/// Return a non-unique reference to the type for a variable array of
@@ -1767,34 +1767,53 @@ private:
bool IsCanon = false) const;
public:
+ QualType getTypeDeclType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TypeDecl *Decl) const;
+
/// Return the unique reference to the type for the specified type
/// declaration.
- QualType getTypeDeclType(const TypeDecl *Decl,
- const TypeDecl *PrevDecl = nullptr) const {
- assert(Decl && "Passed null for Decl param");
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
-
- if (PrevDecl) {
- assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
- Decl->TypeForDecl = PrevDecl->TypeForDecl;
- return QualType(PrevDecl->TypeForDecl, 0);
- }
+ QualType getTypeDeclType(const TypeDecl *Decl) const;
- return getTypeDeclTypeSlow(Decl);
- }
+ /// Use the normal 'getFooBarType' constructors to obtain these types.
+ QualType getTypeDeclType(const TagDecl *) const = delete;
+ QualType getTypeDeclType(const TypedefDecl *) const = delete;
+ QualType getTypeDeclType(const TypeAliasDecl *) const = delete;
+ QualType getTypeDeclType(const UnresolvedUsingTypenameDecl *) const = delete;
+
+ CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const;
- QualType getUsingType(const UsingShadowDecl *Found,
- QualType Underlying) const;
+ QualType getUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const UsingShadowDecl *D,
+ QualType UnderlyingType = QualType()) const;
/// Return the unique reference to the type for the specified
/// typedef-name decl.
- QualType getTypedefType(const TypedefNameDecl *Decl,
- QualType Underlying = QualType()) const;
+ /// FIXME: TypeMatchesDeclOrNone is a workaround for a serialization issue:
+ /// The decl underlying type might still not be available.
+ QualType getTypedefType(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
+ const TypedefNameDecl *Decl, QualType UnderlyingType = QualType(),
+ std::optional<bool> TypeMatchesDeclOrNone = std::nullopt) const;
+
+ CanQualType getCanonicalTagType(const TagDecl *TD) const;
+ QualType getTagType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *TD,
+ bool OwnsTag) const;
- QualType getRecordType(const RecordDecl *Decl) const;
+private:
+ UnresolvedUsingType *getUnresolvedUsingTypeInternal(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D, void *InsertPos,
+ const Type *CanonicalType) const;
- QualType getEnumType(const EnumDecl *Decl) const;
+ TagType *getTagTypeInternal(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *Tag,
+ bool OwnsTag, bool IsInjected,
+ const Type *CanonicalType,
+ bool WithFoldingSetNode) const;
+public:
/// Compute BestType and BestPromotionType for an enum based on the highest
/// number of negative and positive bits of its elements.
/// Returns true if enum width is too large.
@@ -1843,10 +1862,11 @@ public:
return MembersRepresentableByInt;
}
- QualType
- getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;
-
- QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
+ CanQualType
+ getCanonicalUnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) const;
+ QualType getUnresolvedUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D) const;
QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
QualType equivalentType,
@@ -1876,6 +1896,7 @@ public:
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);
+ QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
QualType
getTemplateTypeParmType(unsigned Depth, unsigned Index,
@@ -1886,18 +1907,20 @@ public:
TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
QualType
- getTemplateSpecializationType(TemplateName T,
+ getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T,
ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Underlying = QualType()) const;
QualType
- getTemplateSpecializationType(TemplateName T,
+ getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T,
ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
QualType Canon = QualType()) const;
TypeSourceInfo *getTemplateSpecializationTypeInfo(
+ ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc,
TemplateName T, SourceLocation TLoc,
const TemplateArgumentListInfo &SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs,
@@ -1908,11 +1931,8 @@ public:
QualType getMacroQualifiedType(QualType UnderlyingTy,
const IdentifierInfo *MacroII) const;
- QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, QualType NamedType,
- TagDecl *OwnedTagDecl = nullptr) const;
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
+ NestedNameSpecifier NNS,
const IdentifierInfo *Name) const;
QualType getDependentTemplateSpecializationType(
@@ -1999,21 +2019,17 @@ public:
QualType getUnconstrainedType(QualType T) const;
/// C++17 deduced class template specialization type.
- QualType getDeducedTemplateSpecializationType(TemplateName Template,
+ QualType getDeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
+ TemplateName Template,
QualType DeducedType,
bool IsDependent) const;
private:
- QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template,
- QualType DeducedType,
- bool IsDependent,
- QualType Canon) const;
+ QualType getDeducedTemplateSpecializationTypeInternal(
+ ElaboratedTypeKeyword Keyword, TemplateName Template,
+ QualType DeducedType, bool IsDependent, QualType Canon) const;
public:
- /// Return the unique reference to the type for the specified TagDecl
- /// (struct/union/class/enum) decl.
- QualType getTagDeclType(const TagDecl *Decl) const;
-
/// Return the unique type for "size_t" (C99 7.17), defined in
/// <stddef.h>.
///
@@ -2089,7 +2105,9 @@ public:
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
if (CFConstantStringTypeDecl)
- return getTypedefType(CFConstantStringTypeDecl);
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt,
+ CFConstantStringTypeDecl);
return QualType();
}
void setCFConstantStringType(QualType T);
@@ -2186,10 +2204,11 @@ public:
}
#include "clang/Basic/BuiltinTemplates.inc"
- /// Retrieve the Objective-C "instancetype" type, if already known;
- /// otherwise, returns a NULL type;
+ /// Retrieve the Objective-C "instancetype" type.
QualType getObjCInstanceType() {
- return getTypeDeclType(getObjCInstanceTypeDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt,
+ getObjCInstanceTypeDecl());
}
/// Retrieve the typedef declaration corresponding to the Objective-C
@@ -2202,7 +2221,8 @@ public:
/// Retrieve the C FILE type.
QualType getFILEType() const {
if (FILEDecl)
- return getTypeDeclType(FILEDecl);
+ return getTypeDeclType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, FILEDecl);
return QualType();
}
@@ -2214,7 +2234,8 @@ public:
/// Retrieve the C jmp_buf type.
QualType getjmp_bufType() const {
if (jmp_bufDecl)
- return getTypeDeclType(jmp_bufDecl);
+ return getTypeDeclType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, jmp_bufDecl);
return QualType();
}
@@ -2226,7 +2247,8 @@ public:
/// Retrieve the C sigjmp_buf type.
QualType getsigjmp_bufType() const {
if (sigjmp_bufDecl)
- return getTypeDeclType(sigjmp_bufDecl);
+ return getTypeDeclType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, sigjmp_bufDecl);
return QualType();
}
@@ -2238,12 +2260,13 @@ public:
/// Retrieve the C ucontext_t type.
QualType getucontext_tType() const {
if (ucontext_tDecl)
- return getTypeDeclType(ucontext_tDecl);
+ return getTypeDeclType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, ucontext_tDecl);
return QualType();
}
/// The result type of logical operations, '<', '>', '!=', etc.
- QualType getLogicalOperationType() const {
+ CanQualType getLogicalOperationType() const {
return getLangOpts().CPlusPlus ? BoolTy : IntTy;
}
@@ -2308,7 +2331,8 @@ public:
/// This is set up lazily, by Sema. \c id is always a (typedef for a)
/// pointer type, a pointer to a struct.
QualType getObjCIdType() const {
- return getTypeDeclType(getObjCIdDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getObjCIdDecl());
}
/// Retrieve the typedef corresponding to the predefined 'SEL' type
@@ -2318,7 +2342,8 @@ public:
/// Retrieve the type that corresponds to the predefined Objective-C
/// 'SEL' type.
QualType getObjCSelType() const {
- return getTypeDeclType(getObjCSelDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getObjCSelDecl());
}
PointerAuthQualifier getObjCMemberSelTypePtrAuth();
@@ -2332,7 +2357,8 @@ public:
/// This is set up lazily, by Sema. \c Class is always a (typedef for a)
/// pointer type, a pointer to a struct.
QualType getObjCClassType() const {
- return getTypeDeclType(getObjCClassDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getObjCClassDecl());
}
/// Retrieve the Objective-C class declaration corresponding to
@@ -2351,7 +2377,8 @@ public:
/// type of 'BOOL' type.
QualType getBOOLType() const {
- return getTypeDeclType(getBOOLDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getBOOLDecl());
}
/// Retrieve the type of the Objective-C \c Protocol class.
@@ -2365,7 +2392,8 @@ public:
/// Retrieve the type of the \c __builtin_va_list type.
QualType getBuiltinVaListType() const {
- return getTypeDeclType(getBuiltinVaListDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getBuiltinVaListDecl());
}
/// Retrieve the C type declaration corresponding to the predefined
@@ -2379,16 +2407,17 @@ public:
/// Retrieve the type of the \c __builtin_ms_va_list type.
QualType getBuiltinMSVaListType() const {
- return getTypeDeclType(getBuiltinMSVaListDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, getBuiltinMSVaListDecl());
}
/// Retrieve the implicitly-predeclared 'struct _GUID' declaration.
TagDecl *getMSGuidTagDecl() const { return MSGuidTagDecl; }
/// Retrieve the implicitly-predeclared 'struct _GUID' type.
- QualType getMSGuidType() const {
+ CanQualType getMSGuidType() const {
assert(MSGuidTagDecl && "asked for GUID type but MS extensions disabled");
- return getTagDeclType(MSGuidTagDecl);
+ return getCanonicalTagType(MSGuidTagDecl);
}
/// Retrieve the implicitly-predeclared 'struct type_info' declaration.
@@ -2477,7 +2506,7 @@ public:
UnresolvedSetIterator End) const;
TemplateName getAssumedTemplateName(DeclarationName Name) const;
- TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ TemplateName getQualifiedTemplateName(NestedNameSpecifier Qualifier,
bool TemplateKeyword,
TemplateName Template) const;
TemplateName
@@ -2919,32 +2948,6 @@ public:
/// Determine if two types are similar, ignoring only CVR qualifiers.
bool hasCvrSimilarType(QualType T1, QualType T2);
- /// Retrieves the "canonical" nested name specifier for a
- /// given nested name specifier.
- ///
- /// The canonical nested name specifier is a nested name specifier
- /// that uniquely identifies a type or namespace within the type
- /// system. For example, given:
- ///
- /// \code
- /// namespace N {
- /// struct S {
- /// template<typename T> struct X { typename T* type; };
- /// };
- /// }
- ///
- /// template<typename T> struct Y {
- /// typename N::S::X<T>::type member;
- /// };
- /// \endcode
- ///
- /// Here, the nested-name-specifier for N::S::X<T>:: will be
- /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
- /// by declarations in the type system and the canonical type for
- /// the template type parameter 'T' is template-param-0-0.
- NestedNameSpecifier *
- getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
-
/// Retrieves the default calling convention for the current context.
///
/// The context's default calling convention may differ from the current
@@ -3158,7 +3161,7 @@ public:
mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
FunctionProtoType::ExceptionSpecInfo ESI2,
SmallVectorImpl<QualType> &ExceptionTypeStorage,
- bool AcceptDependent);
+ bool AcceptDependent) const;
// For two "same" types, return a type which has
// the common sugar between them. If Unqualified is true,
@@ -3166,7 +3169,7 @@ public:
// The result will drop the qualifiers which do not occur
// in both types.
QualType getCommonSugaredType(QualType X, QualType Y,
- bool Unqualified = false);
+ bool Unqualified = false) const;
private:
// Helper for integer ordering
@@ -3184,23 +3187,11 @@ public:
bool propertyTypesAreCompatible(QualType, QualType);
bool typesAreBlockPointerCompatible(QualType, QualType);
- bool isObjCIdType(QualType T) const {
- if (const auto *ET = dyn_cast<ElaboratedType>(T))
- T = ET->getNamedType();
- return T == getObjCIdType();
- }
+ bool isObjCIdType(QualType T) const { return T == getObjCIdType(); }
- bool isObjCClassType(QualType T) const {
- if (const auto *ET = dyn_cast<ElaboratedType>(T))
- T = ET->getNamedType();
- return T == getObjCClassType();
- }
+ bool isObjCClassType(QualType T) const { return T == getObjCClassType(); }
- bool isObjCSelType(QualType T) const {
- if (const auto *ET = dyn_cast<ElaboratedType>(T))
- T = ET->getNamedType();
- return T == getObjCSelType();
- }
+ bool isObjCSelType(QualType T) const { return T == getObjCSelType(); }
bool ObjCQualifiedIdTypesAreCompatible(const ObjCObjectPointerType *LHS,
const ObjCObjectPointerType *RHS,
@@ -3731,7 +3722,7 @@ public:
/// Resolve the root record to be used to derive the vtable pointer
/// authentication policy for the specified record.
const CXXRecordDecl *
- baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
+ baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const;
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);
diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index c40b926..4a0ca45 100644
--- a/clang/include/clang/AST/ASTImporter.h
+++ b/clang/include/clang/AST/ASTImporter.h
@@ -404,7 +404,7 @@ class TypeSourceInfo;
///
/// \returns The equivalent nested-name-specifier in the "to"
/// context, or the import error.
- llvm::Expected<NestedNameSpecifier *> Import(NestedNameSpecifier *FromNNS);
+ llvm::Expected<NestedNameSpecifier> Import(NestedNameSpecifier FromNNS);
/// Import the given nested-name-specifier-loc from the "from"
/// context into the "to" context.
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 8ebabb2..fe08d637 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -394,12 +394,14 @@ public:
}
void VisitMemberPointerType(const MemberPointerType *T) {
// FIXME: Provide a NestedNameSpecifier visitor.
- NestedNameSpecifier *Qualifier = T->getQualifier();
- if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind();
- K == NestedNameSpecifier::TypeSpec)
- Visit(Qualifier->getAsType());
+ NestedNameSpecifier Qualifier = T->getQualifier();
+ if (NestedNameSpecifier::Kind K = Qualifier.getKind();
+ K == NestedNameSpecifier::Kind::Type)
+ Visit(Qualifier.getAsType());
if (T->isSugared())
- Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl());
+ Visit(cast<MemberPointerType>(T->getCanonicalTypeUnqualified())
+ ->getQualifier()
+ .getAsType());
Visit(T->getPointeeType());
}
void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); }
@@ -510,7 +512,7 @@ public:
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
// FIXME: Provide NestedNamespecifierLoc visitor.
- Visit(TL.getQualifierLoc().getTypeLoc());
+ Visit(TL.getQualifierLoc().castAsTypeLoc());
}
void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
Visit(TL.getSizeExpr());
@@ -647,21 +649,8 @@ public:
template <typename SpecializationDecl>
void dumpTemplateDeclSpecialization(const SpecializationDecl *D) {
- for (const auto *RedeclWithBadType : D->redecls()) {
- // FIXME: The redecls() range sometimes has elements of a less-specific
- // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
- // us TagDecls, and should give CXXRecordDecls).
- auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
- if (!Redecl) {
- // Found the injected-class-name for a class template. This will be
- // dumped as part of its surrounding class so we don't need to dump it
- // here.
- assert(isa<CXXRecordDecl>(RedeclWithBadType) &&
- "expected an injected-class-name");
- continue;
- }
- Visit(Redecl);
- }
+ for (const auto *Redecl : D->redecls())
+ Visit(cast<SpecializationDecl>(Redecl));
}
template <typename TemplateDecl>
@@ -772,17 +761,16 @@ public:
}
void VisitUsingShadowDecl(const UsingShadowDecl *D) {
- if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
- Visit(TD->getTypeForDecl());
+ Visit(D->getTargetDecl());
}
void VisitFriendDecl(const FriendDecl *D) {
if (D->getFriendType()) {
// Traverse any CXXRecordDecl owned by this type, since
// it will not be in the parent context:
- if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>())
- if (auto *TD = ET->getOwnedTagDecl())
- Visit(TD);
+ if (auto *TT = D->getFriendType()->getType()->getAs<TagType>())
+ if (TT->isTagOwned())
+ Visit(TT->getOriginalDecl());
} else {
Visit(D->getFriendDecl());
}
diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h
index 3988a15..6f40705 100644
--- a/clang/include/clang/AST/ASTTypeTraits.h
+++ b/clang/include/clang/AST/ASTTypeTraits.h
@@ -307,7 +307,7 @@ public:
/// For nodes which represent textual entities in the source code,
/// return their SourceRange. For all other nodes, return SourceRange().
- SourceRange getSourceRange() const;
+ SourceRange getSourceRange(bool IncludeQualifier = false) const;
/// @{
/// Imposes an order on \c DynTypedNode.
@@ -336,9 +336,9 @@ public:
NodeKind)) {
auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
- return std::make_pair(NNSLA.getNestedNameSpecifier(),
+ return std::make_pair(NNSLA.getNestedNameSpecifier().getAsVoidPointer(),
NNSLA.getOpaqueData()) <
- std::make_pair(NNSLB.getNestedNameSpecifier(),
+ std::make_pair(NNSLB.getNestedNameSpecifier().getAsVoidPointer(),
NNSLB.getOpaqueData());
}
@@ -393,8 +393,9 @@ public:
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
Val.NodeKind)) {
auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
- return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
- NNSL.getOpaqueData());
+ return llvm::hash_combine(
+ NNSL.getNestedNameSpecifier().getAsVoidPointer(),
+ NNSL.getOpaqueData());
}
assert(Val.getMemoizationData());
@@ -539,8 +540,8 @@ struct DynTypedNode::BaseConverter<
: public DynCastPtrConverter<T, Attr> {};
template <>
-struct DynTypedNode::BaseConverter<
- NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
+struct DynTypedNode::BaseConverter<NestedNameSpecifier, void>
+ : public ValueConverter<NestedNameSpecifier> {};
template <>
struct DynTypedNode::BaseConverter<
diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h
index 0a2db9e..0d187eb4 100644
--- a/clang/include/clang/AST/AbstractBasicReader.h
+++ b/clang/include/clang/AST/AbstractBasicReader.h
@@ -193,11 +193,11 @@ public:
auto elemTy = origTy;
unsigned pathLength = asImpl().readUInt32();
for (unsigned i = 0; i < pathLength; ++i) {
- if (elemTy->template getAs<RecordType>()) {
+ if (elemTy->isRecordType()) {
unsigned int_ = asImpl().readUInt32();
Decl *decl = asImpl().template readDeclAs<Decl>();
if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl))
- elemTy = getASTContext().getRecordType(recordDecl);
+ elemTy = getASTContext().getCanonicalTagType(recordDecl);
else
elemTy = cast<ValueDecl>(decl)->getType();
path.push_back(
@@ -252,39 +252,34 @@ public:
return EffectConditionExpr{asImpl().readExprRef()};
}
- NestedNameSpecifier *readNestedNameSpecifier() {
+ NestedNameSpecifier readNestedNameSpecifier() {
auto &ctx = getASTContext();
// We build this up iteratively.
- NestedNameSpecifier *cur = nullptr;
+ NestedNameSpecifier cur = std::nullopt;
uint32_t depth = asImpl().readUInt32();
for (uint32_t i = 0; i != depth; ++i) {
auto kind = asImpl().readNestedNameSpecifierKind();
switch (kind) {
- case NestedNameSpecifier::Identifier:
- cur = NestedNameSpecifier::Create(ctx, cur,
- asImpl().readIdentifier());
+ case NestedNameSpecifier::Kind::Namespace:
+ cur =
+ NestedNameSpecifier(ctx, asImpl().readNamespaceBaseDeclRef(), cur);
continue;
-
- case NestedNameSpecifier::Namespace:
- cur = NestedNameSpecifier::Create(ctx, cur,
- asImpl().readNamespaceBaseDeclRef());
+ case NestedNameSpecifier::Kind::Type:
+ assert(!cur);
+ cur = NestedNameSpecifier(asImpl().readQualType().getTypePtr());
continue;
-
- case NestedNameSpecifier::TypeSpec:
- cur = NestedNameSpecifier::Create(ctx, cur,
- asImpl().readQualType().getTypePtr());
+ case NestedNameSpecifier::Kind::Global:
+ assert(!cur);
+ cur = NestedNameSpecifier::getGlobal();
continue;
-
- case NestedNameSpecifier::Global:
- cur = NestedNameSpecifier::GlobalSpecifier(ctx);
- continue;
-
- case NestedNameSpecifier::Super:
- cur = NestedNameSpecifier::SuperSpecifier(ctx,
- asImpl().readCXXRecordDeclRef());
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ assert(!cur);
+ cur = NestedNameSpecifier(asImpl().readCXXRecordDeclRef());
continue;
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
}
llvm_unreachable("bad nested name specifier kind");
}
diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h
index c105bbb..8ea0c29 100644
--- a/clang/include/clang/AST/AbstractBasicWriter.h
+++ b/clang/include/clang/AST/AbstractBasicWriter.h
@@ -176,12 +176,12 @@ public:
asImpl().writeUInt32(path.size());
auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
for (auto elem : path) {
- if (elemTy->getAs<RecordType>()) {
+ if (elemTy->isRecordType()) {
asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
asImpl().writeDeclRef(recordDecl);
- elemTy = ctx.getRecordType(recordDecl);
+ elemTy = ctx.getCanonicalTagType(recordDecl);
} else {
const auto *valueDecl = cast<ValueDecl>(baseOrMember);
asImpl().writeDeclRef(valueDecl);
@@ -229,42 +229,43 @@ public:
asImpl().writeExprRef(CE.getCondition());
}
- void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ void writeNestedNameSpecifier(NestedNameSpecifier NNS) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.
- SmallVector<NestedNameSpecifier *, 8> nestedNames;
+ SmallVector<NestedNameSpecifier, 8> nestedNames;
// Push each of the NNS's onto a stack for serialization in reverse order.
while (NNS) {
nestedNames.push_back(NNS);
- NNS = NNS->getPrefix();
+ NNS = NNS.getKind() == NestedNameSpecifier::Kind::Namespace
+ ? NNS.getAsNamespaceAndPrefix().Prefix
+ : std::nullopt;
}
asImpl().writeUInt32(nestedNames.size());
while (!nestedNames.empty()) {
NNS = nestedNames.pop_back_val();
- NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
+ NestedNameSpecifier::Kind kind = NNS.getKind();
asImpl().writeNestedNameSpecifierKind(kind);
switch (kind) {
- case NestedNameSpecifier::Identifier:
- asImpl().writeIdentifier(NNS->getAsIdentifier());
+ case NestedNameSpecifier::Kind::Namespace:
+ asImpl().writeNamespaceBaseDeclRef(
+ NNS.getAsNamespaceAndPrefix().Namespace);
continue;
-
- case NestedNameSpecifier::Namespace:
- asImpl().writeNamespaceBaseDeclRef(NNS->getAsNamespace());
- continue;
-
- case NestedNameSpecifier::TypeSpec:
- asImpl().writeQualType(QualType(NNS->getAsType(), 0));
+ case NestedNameSpecifier::Kind::Type:
+ asImpl().writeQualType(QualType(NNS.getAsType(), 0));
continue;
- case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Kind::Global:
// Don't need to write an associated value.
continue;
- case NestedNameSpecifier::Super:
- asImpl().writeDeclRef(NNS->getAsRecordDecl());
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ asImpl().writeDeclRef(NNS.getAsMicrosoftSuper());
continue;
+
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
}
llvm_unreachable("bad nested name specifier kind");
}
diff --git a/clang/include/clang/AST/CXXInheritance.h b/clang/include/clang/AST/CXXInheritance.h
index bbef018..e893260 100644
--- a/clang/include/clang/AST/CXXInheritance.h
+++ b/clang/include/clang/AST/CXXInheritance.h
@@ -359,7 +359,7 @@ class CXXFinalOverriderMap
/// A set of all the primary bases for a class.
class CXXIndirectPrimaryBaseSet
- : public llvm::SmallSet<const CXXRecordDecl*, 32> {};
+ : public llvm::SmallPtrSet<const CXXRecordDecl *, 32> {};
inline bool
inheritanceModelHasVBPtrOffsetField(MSInheritanceModel Inheritance) {
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 35db689..b5a4e94e13 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -453,7 +453,7 @@ template<>
struct CanProxyAdaptor<MemberPointerType>
: public CanProxyBase<MemberPointerType> {
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier *, getQualifier)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier, getQualifier)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const CXXRecordDecl *,
getMostRecentCXXRecordDecl)
};
@@ -551,21 +551,18 @@ struct CanProxyAdaptor<UnaryTransformType>
template<>
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getOriginalDecl)
};
template<>
struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getOriginalDecl)
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
};
template<>
struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> {
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
+ LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getOriginalDecl)
};
template<>
diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h
index dd99067..5ba95c8 100644
--- a/clang/include/clang/AST/Comment.h
+++ b/clang/include/clang/AST/Comment.h
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
namespace clang {
class Decl;
@@ -119,6 +120,11 @@ protected:
LLVM_PREFERRED_TYPE(CommandTraits::KnownCommandIDs)
unsigned CommandID : CommandInfo::NumCommandIDBits;
+
+ /// Describes the syntax that was used in a documentation command.
+ /// Contains values from CommandMarkerKind enum.
+ LLVM_PREFERRED_TYPE(CommandMarkerKind)
+ unsigned CommandMarker : 1;
};
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 3 +
CommandInfo::NumCommandIDBits };
@@ -347,6 +353,16 @@ public:
InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK);
InlineCommandCommentBits.CommandID = CommandID;
}
+ InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd,
+ unsigned CommandID, InlineCommandRenderKind RK,
+ CommandMarkerKind CommandMarker, ArrayRef<Argument> Args)
+ : InlineContentComment(CommentKind::InlineCommandComment, LocBegin,
+ LocEnd),
+ Args(Args) {
+ InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK);
+ InlineCommandCommentBits.CommandID = CommandID;
+ InlineCommandCommentBits.CommandMarker = llvm::to_underlying(CommandMarker);
+ }
static bool classof(const Comment *C) {
return C->getCommentKind() == CommentKind::InlineCommandComment;
@@ -384,6 +400,11 @@ public:
SourceRange getArgRange(unsigned Idx) const {
return Args[Idx].Range;
}
+
+ CommandMarkerKind getCommandMarker() const {
+ return static_cast<CommandMarkerKind>(
+ InlineCommandCommentBits.CommandMarker);
+ }
};
/// Abstract class for opening and closing HTML tags. HTML tags are always
diff --git a/clang/include/clang/AST/CommentHTMLTags.td b/clang/include/clang/AST/CommentHTMLTags.td
index a1ce8c6..9b89bc0 100644
--- a/clang/include/clang/AST/CommentHTMLTags.td
+++ b/clang/include/clang/AST/CommentHTMLTags.td
@@ -51,6 +51,11 @@ def Col : Tag<"col"> { let EndTagForbidden = 1; }
def Tr : Tag<"tr"> { let EndTagOptional = 1; }
def Th : Tag<"th"> { let EndTagOptional = 1; }
def Td : Tag<"td"> { let EndTagOptional = 1; }
+def Summary : Tag<"summary">;
+def Details : Tag<"details">;
+def Mark : Tag<"mark">;
+def Figure : Tag<"figure">;
+def FigCaption : Tag<"figcaption">;
// Define a list of attributes that are not safe to pass through to HTML
// output if the input is untrusted.
diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h
index 916d794..3169e2b 100644
--- a/clang/include/clang/AST/CommentSema.h
+++ b/clang/include/clang/AST/CommentSema.h
@@ -131,6 +131,7 @@ public:
InlineCommandComment *actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd,
unsigned CommandID,
+ CommandMarkerKind CommandMarker,
ArrayRef<Comment::Argument> Args);
InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin,
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 08fe1f8..7c9245d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -20,9 +20,9 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/Redeclarable.h"
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
@@ -833,9 +833,9 @@ public:
/// Retrieve the nested-name-specifier that qualifies the name of this
/// declaration, if it was present in the source.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
- : nullptr;
+ : std::nullopt;
}
/// Retrieve the nested-name-specifier (with source-location
@@ -3526,10 +3526,16 @@ protected:
public:
// Low-level accessor. If you just want the type defined by this node,
// check out ASTContext::getTypeDeclType or one of
- // ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you
+ // ASTContext::getTypedefType, ASTContext::getTagType, etc. if you
// already know the specific kind of node this is.
- const Type *getTypeForDecl() const { return TypeForDecl; }
- void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
+ const Type *getTypeForDecl() const {
+ assert(!isa<TagDecl>(this));
+ return TypeForDecl;
+ }
+ void setTypeForDecl(const Type *TD) {
+ assert(!isa<TagDecl>(this));
+ TypeForDecl = TD;
+ }
SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; }
void setLocStart(SourceLocation L) { LocStart = L; }
@@ -3635,6 +3641,10 @@ public:
return isTransparentTagSlow();
}
+ // These types are created lazily, use the ASTContext methods to obtain them.
+ const Type *getTypeForDecl() const = delete;
+ void setTypeForDecl(const Type *TD) = delete;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
@@ -3754,14 +3764,6 @@ protected:
/// True if this decl is currently being defined.
void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; }
- /// Indicates whether it is possible for declarations of this kind
- /// to have an out-of-date definition.
- ///
- /// This option is only enabled when modules are enabled.
- void setMayHaveOutOfDateDef(bool V = true) {
- TagDeclBits.MayHaveOutOfDateDef = V;
- }
-
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
@@ -3842,12 +3844,6 @@ public:
TagDeclBits.IsFreeStanding = isFreeStanding;
}
- /// Indicates whether it is possible for declarations of this kind
- /// to have an out-of-date definition.
- ///
- /// This option is only enabled when modules are enabled.
- bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; }
-
/// Whether this declaration declares a type that is
/// dependent, i.e., a type that somehow depends on template
/// parameters.
@@ -3888,6 +3884,19 @@ public:
/// the struct/union/class/enum.
TagDecl *getDefinition() const;
+ TagDecl *getDefinitionOrSelf() const {
+ if (TagDecl *Def = getDefinition())
+ return Def;
+ return const_cast<TagDecl *>(this);
+ }
+
+ /// Determines whether this entity is in the process of being defined.
+ bool isEntityBeingDefined() const {
+ if (const TagDecl *Def = getDefinition())
+ return Def->isBeingDefined();
+ return false;
+ }
+
StringRef getKindName() const {
return TypeWithKeyword::getTagTypeKindName(getTagKind());
}
@@ -3906,6 +3915,10 @@ public:
bool isUnion() const { return getTagKind() == TagTypeKind::Union; }
bool isEnum() const { return getTagKind() == TagTypeKind::Enum; }
+ bool isStructureOrClass() const {
+ return isStruct() || isClass() || isInterface();
+ }
+
/// Is this tag type named, either directly or via being defined in
/// a typedef of this type?
///
@@ -3934,9 +3947,9 @@ public:
/// Retrieve the nested-name-specifier that qualifies the name of this
/// declaration, if it was present in the source.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
- : nullptr;
+ : std::nullopt;
}
/// Retrieve the nested-name-specifier (with source-location
@@ -3958,6 +3971,10 @@ public:
return getExtInfo()->TemplParamLists[i];
}
+ // These types are created lazily, use the ASTContext methods to obtain them.
+ const Type *getTypeForDecl() const = delete;
+ void setTypeForDecl(const Type *TD) = delete;
+
using TypeDecl::printName;
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
@@ -4087,6 +4104,10 @@ public:
return cast_or_null<EnumDecl>(TagDecl::getDefinition());
}
+ EnumDecl *getDefinitionOrSelf() const {
+ return cast_or_null<EnumDecl>(TagDecl::getDefinitionOrSelf());
+ }
+
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, EnumDecl *PrevDecl,
@@ -4469,6 +4490,10 @@ public:
return cast_or_null<RecordDecl>(TagDecl::getDefinition());
}
+ RecordDecl *getDefinitionOrSelf() const {
+ return cast_or_null<RecordDecl>(TagDecl::getDefinitionOrSelf());
+ }
+
/// Returns whether this record is a union, or contains (at any nesting level)
/// a union member. This is used by CMSE to warn about possible information
/// leaks.
@@ -5299,6 +5324,8 @@ void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
/// We use this function to break a cycle between the inline definitions in
/// Type.h and Decl.h.
inline bool IsEnumDeclComplete(EnumDecl *ED) {
+ if (const auto *Def = ED->getDefinition())
+ return Def->isComplete();
return ED->isComplete();
}
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index dd67ebc..c6326a8 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -410,9 +410,6 @@ protected:
virtual ~Decl();
- /// Update a potentially out-of-date declaration.
- void updateOutOfDate(IdentifierInfo &II) const;
-
Linkage getCachedLinkage() const {
return static_cast<Linkage>(CacheValidAndLinkage);
}
@@ -625,6 +622,12 @@ public:
void setReferenced(bool R = true) { Referenced = R; }
+ /// When doing manipulations which might change the computed linkage,
+ /// such as changing the DeclContext after the declaration has already been
+ /// used, invalidating the cache will make sure its linkage will be
+ /// recomputed.
+ void invalidateCachedLinkage() { setCachedLinkage(Linkage::Invalid); }
+
/// Whether this declaration is a top-level declaration (function,
/// global variable, etc.) that is lexically inside an objc container
/// definition.
@@ -1564,13 +1567,6 @@ protected:
LLVM_PREFERRED_TYPE(bool)
uint64_t IsFreeStanding : 1;
- /// Indicates whether it is possible for declarations of this kind
- /// to have an out-of-date definition.
- ///
- /// This option is only enabled when modules are enabled.
- LLVM_PREFERRED_TYPE(bool)
- uint64_t MayHaveOutOfDateDef : 1;
-
/// Has the full definition of this type been required by a use somewhere in
/// the TU.
LLVM_PREFERRED_TYPE(bool)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 33ae3d6..8802664 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -22,10 +22,10 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/LambdaCapture.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/Redeclarable.h"
#include "clang/AST/Stmt.h"
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/LLVM.h"
@@ -545,20 +545,6 @@ public:
return const_cast<CXXRecordDecl*>(this)->getMostRecentDecl();
}
- CXXRecordDecl *getMostRecentNonInjectedDecl() {
- CXXRecordDecl *Recent = getMostRecentDecl();
- while (Recent->isInjectedClassName()) {
- // FIXME: Does injected class name need to be in the redeclarations chain?
- assert(Recent->getPreviousDecl());
- Recent = Recent->getPreviousDecl();
- }
- return Recent;
- }
-
- const CXXRecordDecl *getMostRecentNonInjectedDecl() const {
- return const_cast<CXXRecordDecl*>(this)->getMostRecentNonInjectedDecl();
- }
-
CXXRecordDecl *getDefinition() const {
// We only need an update if we don't already know which
// declaration is the definition.
@@ -566,13 +552,18 @@ public:
return DD ? DD->Definition : nullptr;
}
+ CXXRecordDecl *getDefinitionOrSelf() const {
+ if (auto *Def = getDefinition())
+ return Def;
+ return const_cast<CXXRecordDecl *>(this);
+ }
+
bool hasDefinition() const { return DefinitionData || dataPtr(); }
static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl = nullptr,
- bool DelayTypeCreation = false);
+ CXXRecordDecl *PrevDecl = nullptr);
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
unsigned DependencyKind, bool IsGeneric,
@@ -1903,6 +1894,20 @@ public:
/// \endcode
bool isInjectedClassName() const;
+ /// Determines whether this declaration has is canonically of an injected
+ /// class type. These are non-instantiated class template patterns, which can
+ /// be used from within the class template itself. For example:
+ ///
+ /// \code
+ /// template<class T> struct C {
+ /// C *t; // Here `C *` is a pointer to an injected class type.
+ /// };
+ /// \endcode
+ bool hasInjectedClassType() const;
+
+ CanQualType
+ getCanonicalTemplateSpecializationType(const ASTContext &Ctx) const;
+
// Determine whether this type is an Interface Like type for
// __interface inheritance purposes.
bool isInterfaceLike() const;
@@ -3131,7 +3136,7 @@ public:
/// Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3252,7 +3257,7 @@ public:
/// Retrieve the nested-name-specifier that qualifies the
/// name of the namespace.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3614,7 +3619,7 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3804,13 +3809,11 @@ public:
/// The source location of the 'enum' keyword.
SourceLocation getEnumLoc() const { return EnumLocation; }
void setEnumLoc(SourceLocation L) { EnumLocation = L; }
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return getQualifierLoc().getNestedNameSpecifier();
}
NestedNameSpecifierLoc getQualifierLoc() const {
- if (auto ETL = EnumType->getTypeLoc().getAs<ElaboratedTypeLoc>())
- return ETL.getQualifierLoc();
- return NestedNameSpecifierLoc();
+ return getEnumTypeLoc().getPrefix();
}
// Returns the "qualifier::Name" part as a TypeLoc.
TypeLoc getEnumTypeLoc() const {
@@ -3822,7 +3825,9 @@ public:
void setEnumType(TypeSourceInfo *TSI) { EnumType = TSI; }
public:
- EnumDecl *getEnumDecl() const { return cast<EnumDecl>(EnumType->getType()->getAsTagDecl()); }
+ EnumDecl *getEnumDecl() const {
+ return EnumType->getType()->castAs<clang::EnumType>()->getOriginalDecl();
+ }
static UsingEnumDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation UsingL, SourceLocation EnumL,
@@ -3970,7 +3975,7 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -4060,7 +4065,7 @@ public:
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// Retrieve the nested-name-specifier that qualifies the name.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index 9014d76..2541edb 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -643,6 +643,9 @@ public:
/// from the explicitly-specified bound.
SourceLocation getColonLoc() const { return ColonLoc; }
+ using TypeDecl::getTypeForDecl;
+ using TypeDecl::setTypeForDecl;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCTypeParam; }
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 32de203..bba7236 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1796,7 +1796,10 @@ public:
}
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
+
+ bool isPackProducingBuiltinTemplate() const;
};
+bool isPackProducingBuiltinTemplateName(TemplateName N);
/// Provides information about an explicit instantiation of a variable or class
/// template.
@@ -1898,14 +1901,14 @@ public:
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
bool Qualified) const override;
- // FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a
- // different "most recent" declaration from this function for the same
- // declaration, because we don't override getMostRecentDeclImpl(). But
- // it's not clear that we should override that, because the most recent
- // declaration as a CXXRecordDecl sometimes is the injected-class-name.
ClassTemplateSpecializationDecl *getMostRecentDecl() {
return cast<ClassTemplateSpecializationDecl>(
- getMostRecentNonInjectedDecl());
+ CXXRecordDecl::getMostRecentDecl());
+ }
+
+ ClassTemplateSpecializationDecl *getDefinitionOrSelf() const {
+ return cast<ClassTemplateSpecializationDecl>(
+ CXXRecordDecl::getDefinitionOrSelf());
}
/// Retrieve the template that this specialization specializes.
@@ -2123,10 +2126,13 @@ class ClassTemplatePartialSpecializationDecl
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;
+ mutable CanQualType CanonInjectedTST;
+
ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
+ CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl(ASTContext &C)
@@ -2143,7 +2149,7 @@ public:
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
- ArrayRef<TemplateArgument> Args, QualType CanonInjectedType,
+ ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl);
static ClassTemplatePartialSpecializationDecl *
@@ -2160,12 +2166,6 @@ public:
return TemplateParams;
}
- /// Get the template argument list of the template parameter list.
- ArrayRef<TemplateArgument>
- getInjectedTemplateArgs(const ASTContext &Context) const {
- return getTemplateParameters()->getInjectedTemplateArgs(Context);
- }
-
/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
@@ -2247,14 +2247,10 @@ public:
return First->InstantiatedFromMember.setInt(true);
}
- /// Retrieves the injected specialization type for this partial
- /// specialization. This is not the same as the type-decl-type for
- /// this partial specialization, which is an InjectedClassNameType.
- QualType getInjectedSpecializationType() const {
- assert(getTypeForDecl() && "partial specialization has no type set!");
- return cast<InjectedClassNameType>(getTypeForDecl())
- ->getInjectedSpecializationType();
- }
+ /// Retrieves the canonical injected specialization type for this partial
+ /// specialization.
+ CanQualType
+ getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const;
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -2289,8 +2285,8 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
PartialSpecializations;
- /// The injected-class-name type for this class template.
- QualType InjectedClassNameType;
+ /// The Injected Template Specialization Type for this declaration.
+ CanQualType CanonInjectedTST;
Common() = default;
};
@@ -2427,7 +2423,7 @@ public:
findPartialSpecInstantiatedFromMember(
ClassTemplatePartialSpecializationDecl *D);
- /// Retrieve the template specialization type of the
+ /// Retrieve the canonical template specialization type of the
/// injected-class-name for this class template.
///
/// The injected-class-name for a class template \c X is \c
@@ -2441,7 +2437,8 @@ public:
/// typedef array this_type; // "array" is equivalent to "array<T, N>"
/// };
/// \endcode
- QualType getInjectedClassNameSpecialization();
+ CanQualType
+ getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const;
using spec_iterator = SpecIterator<ClassTemplateSpecializationDecl>;
using spec_range = llvm::iterator_range<spec_iterator>;
diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h
index 284228d..a7185f5 100644
--- a/clang/include/clang/AST/DeclarationName.h
+++ b/clang/include/clang/AST/DeclarationName.h
@@ -13,7 +13,7 @@
#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H
#define LLVM_CLANG_AST_DECLARATIONNAME_H
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OperatorKinds.h"
diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h
index bdcaabc..c439525 100644
--- a/clang/include/clang/AST/DependenceFlags.h
+++ b/clang/include/clang/AST/DependenceFlags.h
@@ -293,7 +293,7 @@ inline TypeDependence toSemanticDependence(TypeDependence D) {
}
inline NestedNameSpecifierDependence
-toNestedNameSpecifierDependendence(TypeDependence D) {
+toNestedNameSpecifierDependence(TypeDependence D) {
return Dependence(D).nestedNameSpecifier();
}
diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h
index 703cca2..7b5bdca 100644
--- a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h
+++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h
@@ -134,8 +134,7 @@ public:
/// Recursively visit a C++ nested-name-specifier.
///
/// \returns false if the visitation was terminated early, true otherwise.
- virtual bool
- TraverseNestedNameSpecifier(MaybeConst<NestedNameSpecifier> *NNS);
+ virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
/// Recursively visit a C++ nested-name-specifier with location
/// information.
@@ -181,14 +180,14 @@ public:
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type).
- virtual bool TraverseType(QualType T);
+ virtual bool TraverseType(QualType T, bool TraverseQualifier = true);
/// Recursively visit a type with location, by dispatching to
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type location).
- virtual bool TraverseTypeLoc(TypeLoc TL);
+ virtual bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true);
/// Recursively visit an Objective-C protocol reference with location
/// information.
@@ -273,7 +272,8 @@ public:
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
bool WalkUpFrom##CLASS##Type(MaybeConst<CLASS##Type> *T); \
- virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T);
+ virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T, \
+ bool TraverseQualifier = true);
#include "clang/AST/TypeNodes.inc"
#define TYPE(CLASS, BASE) \
@@ -283,7 +283,8 @@ public:
// TypeLocs.
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
- virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
+ virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, \
+ bool TraverseQualifier);
#include "clang/AST/TypeLocNodes.def"
#define TYPELOC(CLASS, BASE) \
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 237b3b2..23a0996 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -23,7 +23,7 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SyncScope.h"
@@ -40,6 +40,7 @@
#include <optional>
namespace clang {
+ class AllocSizeAttr;
class APValue;
class ASTContext;
class BlockDecl;
@@ -1369,7 +1370,7 @@ public:
/// If the name was qualified, retrieves the nested-name-specifier
/// that precedes the name. Otherwise, returns NULL.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return getQualifierLoc().getNestedNameSpecifier();
}
@@ -3261,6 +3262,15 @@ public:
setDependence(getDependence() | ExprDependence::TypeValueInstantiation);
}
+ /// Try to get the alloc_size attribute of the callee. May return null.
+ const AllocSizeAttr *getCalleeAllocSizeAttr() const;
+
+ /// Evaluates the total size in bytes allocated by calling a function
+ /// decorated with alloc_size. Returns std::nullopt if the the result cannot
+ /// be evaluated.
+ std::optional<llvm::APInt>
+ evaluateBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const;
+
bool isCallToStdMove() const;
static bool classof(const Stmt *T) {
@@ -3398,7 +3408,7 @@ public:
/// If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return getQualifierLoc().getNestedNameSpecifier();
}
@@ -3548,6 +3558,7 @@ public:
QualType T, ExprValueKind VK, Expr *init, bool fileScope)
: Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary),
LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) {
+ assert(Init && "Init is a nullptr");
setDependence(computeDependence(this));
}
@@ -3577,19 +3588,11 @@ public:
APValue &getStaticValue() const;
SourceLocation getBeginLoc() const LLVM_READONLY {
- // FIXME: Init should never be null.
- if (!Init)
- return SourceLocation();
if (LParenLoc.isInvalid())
return Init->getBeginLoc();
return LParenLoc;
}
- SourceLocation getEndLoc() const LLVM_READONLY {
- // FIXME: Init should never be null.
- if (!Init)
- return SourceLocation();
- return Init->getEndLoc();
- }
+ SourceLocation getEndLoc() const LLVM_READONLY { return Init->getEndLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CompoundLiteralExprClass;
@@ -5110,9 +5113,9 @@ public:
"trying to dereference an invalid iterator");
IntegerLiteral *N = EExpr->FakeChildNode;
N->setValue(*EExpr->Ctx,
- llvm::APInt(N->getValue().getBitWidth(),
+ llvm::APInt(N->getBitWidth(),
EExpr->Data->BinaryData->getCodeUnit(CurOffset),
- N->getType()->isSignedIntegerType()));
+ /*Signed=*/true));
// We want to return a reference to the fake child node in the
// EmbedExpr, not the local variable N.
return const_cast<typename BaseTy::reference>(EExpr->FakeChildNode);
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 7a26934..9fedb23 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1712,6 +1712,19 @@ public:
CXXConstructExprBits.IsImmediateEscalating = Set;
}
+ /// Returns the WarnUnusedResultAttr that is declared on the callee
+ /// or its return type declaration, together with a NamedDecl that
+ /// refers to the declaration the attribute is attached to.
+ std::pair<const NamedDecl *, const WarnUnusedResultAttr *>
+ getUnusedResultAttr(const ASTContext &Ctx) const {
+ return getUnusedResultAttrImpl(getConstructor(), getType());
+ }
+
+ /// Returns true if this call expression should warn on unused results.
+ bool hasUnusedResultAttr(const ASTContext &Ctx) const {
+ return getUnusedResultAttr(Ctx).second != nullptr;
+ }
+
SourceLocation getBeginLoc() const LLVM_READONLY;
SourceLocation getEndLoc() const LLVM_READONLY;
SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; }
@@ -2781,7 +2794,7 @@ public:
/// If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// null.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3222,7 +3235,7 @@ public:
SourceLocation getNameLoc() const { return NameInfo.getLoc(); }
/// Fetches the nested-name qualifier, if one was given.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3540,7 +3553,7 @@ public:
/// Retrieve the nested-name-specifier that qualifies this
/// declaration.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
@@ -3955,7 +3968,7 @@ public:
}
/// Retrieve the nested-name-specifier that qualifies the member name.
- NestedNameSpecifier *getQualifier() const {
+ NestedNameSpecifier getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 570662b..8640780 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -240,7 +240,6 @@ public:
void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
void VisitObjCInterfaceType(const ObjCInterfaceType *OIT);
void VisitPackExpansionType(const PackExpansionType *PET);
- void VisitElaboratedType(const ElaboratedType *ET);
void VisitMacroQualifiedType(const MacroQualifiedType *MQT);
void VisitMemberPointerType(const MemberPointerType *MPT);
diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h
index 1614f9d..f198a8b 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -6,507 +6,266 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the NestedNameSpecifier class, which represents
-// a C++ nested-name-specifier.
+// This file completes the definition of the NestedNameSpecifier class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
-#include "clang/AST/DependenceFlags.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/SourceLocation.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/DenseMapInfo.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/Support/Compiler.h"
-#include <cstdint>
-#include <cstdlib>
-#include <utility>
namespace clang {
-class ASTContext;
-class CXXRecordDecl;
-class IdentifierInfo;
-class LangOptions;
-class NamespaceBaseDecl;
-struct PrintingPolicy;
-class Type;
-class TypeLoc;
-
-/// Represents a C++ nested name specifier, such as
-/// "\::std::vector<int>::".
-///
-/// C++ nested name specifiers are the prefixes to qualified
-/// names. For example, "foo::" in "foo::x" is a nested name
-/// specifier. Nested name specifiers are made up of a sequence of
-/// specifiers, each of which can be a namespace, type, identifier
-/// (for dependent names), decltype specifier, or the global specifier ('::').
-/// The last two specifiers can only appear at the start of a
-/// nested-namespace-specifier.
-class NestedNameSpecifier : public llvm::FoldingSetNode {
- /// Enumeration describing
- enum StoredSpecifierKind {
- StoredIdentifier = 0,
- StoredDecl = 1,
- StoredTypeSpec = 2
- };
-
- /// The nested name specifier that precedes this nested name
- /// specifier.
- ///
- /// The pointer is the nested-name-specifier that precedes this
- /// one. The integer stores one of the first four values of type
- /// SpecifierKind.
- llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix;
-
- /// The last component in the nested name specifier, which
- /// can be an identifier, a declaration, or a type.
- ///
- /// When the pointer is NULL, this specifier represents the global
- /// specifier '::'. Otherwise, the pointer is one of
- /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
- /// specifier as encoded within the prefix.
- void* Specifier = nullptr;
-
-public:
- /// The kind of specifier that completes this nested name
- /// specifier.
- enum SpecifierKind {
- /// An identifier, stored as an IdentifierInfo*.
- Identifier,
-
- /// A namespace-like entity, stored as a NamespaceBaseDecl*.
- Namespace,
-
- /// A type, stored as a Type*.
- TypeSpec,
-
- /// The global specifier '::'. There is no stored value.
- Global,
-
- /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
- /// the class it appeared in.
- Super
- };
-
-private:
- /// Builds the global specifier.
- NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {}
-
- /// Copy constructor used internally to clone nested name
- /// specifiers.
- NestedNameSpecifier(const NestedNameSpecifier &Other) = default;
-
- /// Either find or insert the given nested name specifier
- /// mockup in the given context.
- static NestedNameSpecifier *FindOrInsert(const ASTContext &Context,
- const NestedNameSpecifier &Mockup);
-
-public:
- NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete;
-
- /// Builds a specifier combining a prefix and an identifier.
- ///
- /// The prefix must be dependent, since nested name specifiers
- /// referencing an identifier are only permitted when the identifier
- /// cannot be resolved.
- static NestedNameSpecifier *Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix,
- const IdentifierInfo *II);
-
- /// Builds a nested name specifier that names a namespace or namespace alias.
- static NestedNameSpecifier *Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix,
- const NamespaceBaseDecl *NS);
-
- /// Builds a nested name specifier that names a type.
- static NestedNameSpecifier *
- Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T);
-
- /// Builds a specifier that consists of just an identifier.
- ///
- /// The nested-name-specifier is assumed to be dependent, but has no
- /// prefix because the prefix is implied by something outside of the
- /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
- /// type.
- static NestedNameSpecifier *Create(const ASTContext &Context,
- const IdentifierInfo *II);
-
- /// Returns the nested name specifier representing the global
- /// scope.
- static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
-
- /// Returns the nested name specifier representing the __super scope
- /// for the given CXXRecordDecl.
- static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context,
- CXXRecordDecl *RD);
-
- /// Return the prefix of this nested name specifier.
- ///
- /// The prefix contains all of the parts of the nested name
- /// specifier that precede this current specifier. For example, for a
- /// nested name specifier that represents "foo::bar::", the current
- /// specifier will contain "bar::" and the prefix will contain
- /// "foo::".
- NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
-
- /// Determine what kind of nested name specifier is stored.
- SpecifierKind getKind() const;
-
- /// Retrieve the identifier stored in this nested name
- /// specifier.
- IdentifierInfo *getAsIdentifier() const {
- if (Prefix.getInt() == StoredIdentifier)
- return (IdentifierInfo *)Specifier;
-
- return nullptr;
+auto NestedNameSpecifier::getKind() const -> Kind {
+ if (!isStoredKind()) {
+ switch (getFlagKind()) {
+ case FlagKind::Null:
+ return Kind::Null;
+ case FlagKind::Global:
+ return Kind::Global;
+ case FlagKind::Invalid:
+ llvm_unreachable("use of invalid NestedNameSpecifier");
+ }
+ llvm_unreachable("unhandled FlagKind");
}
+ switch (auto [K, Ptr] = getStored(); K) {
+ case StoredKind::Type:
+ return Kind::Type;
+ case StoredKind::NamespaceWithGlobal:
+ case StoredKind::NamespaceWithNamespace:
+ return Kind::Namespace;
+ case StoredKind::NamespaceOrSuper:
+ switch (static_cast<const Decl *>(Ptr)->getKind()) {
+ case Decl::Namespace:
+ case Decl::NamespaceAlias:
+ return Kind::Namespace;
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ return Kind::MicrosoftSuper;
+ default:
+ llvm_unreachable("unexpected decl kind");
+ }
+ }
+ llvm_unreachable("unknown StoredKind");
+}
- /// Retrieve the namespace or namespace alias stored in this nested name
- /// specifier.
- NamespaceBaseDecl *getAsNamespace() const;
-
- /// Retrieve the record declaration stored in this nested name
- /// specifier.
- CXXRecordDecl *getAsRecordDecl() const;
-
- /// Retrieve the type stored in this nested name specifier.
- const Type *getAsType() const {
- if (Prefix.getInt() == StoredTypeSpec)
- return (const Type *)Specifier;
+NestedNameSpecifier::NestedNameSpecifier(const Type *T)
+ : NestedNameSpecifier({StoredKind::Type, T}) {
+ assert(getKind() == Kind::Type);
+}
- return nullptr;
+auto NestedNameSpecifier::MakeNamespacePtrKind(
+ const ASTContext &Ctx, const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix) -> PtrKind {
+ switch (Prefix.getKind()) {
+ case Kind::Null:
+ return {StoredKind::NamespaceOrSuper, Namespace};
+ case Kind::Global:
+ return {StoredKind::NamespaceWithGlobal, Namespace};
+ case Kind::Namespace:
+ return {StoredKind::NamespaceWithNamespace,
+ MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)};
+ case Kind::MicrosoftSuper:
+ case Kind::Type:
+ llvm_unreachable("invalid prefix for namespace");
}
+ llvm_unreachable("unhandled kind");
+}
- /// Fully translate this nested name specifier to a type.
- /// Unlike getAsType, this will convert this entire nested
- /// name specifier chain into its equivalent type.
- const Type *translateToType(const ASTContext &Context) const;
+/// Builds a nested name specifier that names a namespace.
+NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx,
+ const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix)
+ : NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) {
+ assert(getKind() == Kind::Namespace);
+}
- NestedNameSpecifierDependence getDependence() const;
+/// Builds a nested name specifier that names a class through microsoft's
+/// __super specifier.
+NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD)
+ : NestedNameSpecifier({StoredKind::NamespaceOrSuper, RD}) {
+ assert(getKind() == Kind::MicrosoftSuper);
+}
- /// Whether this nested name specifier refers to a dependent
- /// type or not.
- bool isDependent() const;
+CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
+ switch (getKind()) {
+ case Kind::MicrosoftSuper:
+ return getAsMicrosoftSuper();
+ case Kind::Type:
+ return getAsType()->getAsCXXRecordDecl();
+ case Kind::Global:
+ case Kind::Namespace:
+ case Kind::Null:
+ return nullptr;
+ }
+ llvm_unreachable("Invalid NNS Kind!");
+}
- /// Whether this nested name specifier involves a template
- /// parameter.
- bool isInstantiationDependent() const;
+NestedNameSpecifier NestedNameSpecifier::getCanonical() const {
+ switch (getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ // These are canonical and unique.
+ return *this;
+ case NestedNameSpecifier::Kind::Namespace: {
+ // A namespace is canonical; build a nested-name-specifier with
+ // this namespace and no prefix.
+ const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace;
+ return NestedNameSpecifier(
+ {StoredKind::NamespaceOrSuper, ND->getNamespace()->getCanonicalDecl()});
+ }
+ case NestedNameSpecifier::Kind::Type:
+ return NestedNameSpecifier(
+ getAsType()->getCanonicalTypeInternal().getTypePtr());
+ }
+ llvm_unreachable("unhandled kind");
+}
- /// Whether this nested-name-specifier contains an unexpanded
- /// parameter pack (for C++11 variadic templates).
- bool containsUnexpandedParameterPack() const;
+bool NestedNameSpecifier::isCanonical() const {
+ return *this == getCanonical();
+}
- /// Whether this nested name specifier contains an error.
- bool containsErrors() const;
+TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const {
+ return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/0));
+}
- /// Print this nested name specifier to the given output stream. If
- /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
- /// `ns::SomeTemplate<int, MyClass>` instead of
- /// `ns::SomeTemplate<Container::value_type, T>`.
- void print(raw_ostream &OS, const PrintingPolicy &Policy,
- bool ResolveTemplateArguments = false,
- bool PrintFinalScopeResOp = true) const;
+TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const {
+ if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)
+ return TypeLoc();
+ return castAsTypeLoc();
+}
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(Prefix.getOpaqueValue());
- ID.AddPointer(Specifier);
+unsigned
+NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) {
+ // Location of the trailing '::'.
+ unsigned Length = sizeof(SourceLocation::UIntTy);
+
+ switch (Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Global:
+ // Nothing more to add.
+ break;
+
+ case NestedNameSpecifier::Kind::Namespace:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ // The location of the identifier or namespace name.
+ Length += sizeof(SourceLocation::UIntTy);
+ break;
+
+ case NestedNameSpecifier::Kind::Type:
+ // The "void*" that points at the TypeLoc data.
+ // Note: the 'template' keyword is part of the TypeLoc.
+ Length += sizeof(void *);
+ break;
+
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("Expected a non-NULL qualifier");
}
- /// Dump the nested name specifier to standard output to aid
- /// in debugging.
- void dump(const LangOptions &LO) const;
- void dump() const;
- void dump(llvm::raw_ostream &OS) const;
- void dump(llvm::raw_ostream &OS, const LangOptions &LO) const;
-};
+ return Length;
+}
-/// A C++ nested-name-specifier augmented with source location
-/// information.
-class NestedNameSpecifierLoc {
- NestedNameSpecifier *Qualifier = nullptr;
- void *Data = nullptr;
-
- /// Determines the data length for the last component in the
- /// given nested-name-specifier.
- static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier);
-
- /// Determines the data length for the entire
- /// nested-name-specifier.
- static unsigned getDataLength(NestedNameSpecifier *Qualifier);
-
-public:
- /// Construct an empty nested-name-specifier.
- NestedNameSpecifierLoc() = default;
-
- /// Construct a nested-name-specifier with source location information
- /// from
- NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
- : Qualifier(Qualifier), Data(Data) {}
-
- /// Evaluates true when this nested-name-specifier location is
- /// non-empty.
- explicit operator bool() const { return Qualifier; }
-
- /// Evaluates true when this nested-name-specifier location is
- /// non-empty.
- bool hasQualifier() const { return Qualifier; }
-
- /// Retrieve the nested-name-specifier to which this instance
- /// refers.
- NestedNameSpecifier *getNestedNameSpecifier() const {
- return Qualifier;
- }
+NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const {
+ auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix();
+ return {Namespace, NestedNameSpecifierLoc(Prefix, Data)};
+}
- /// Retrieve the opaque pointer that refers to source-location data.
- void *getOpaqueData() const { return Data; }
-
- /// Retrieve the source range covering the entirety of this
- /// nested-name-specifier.
- ///
- /// For example, if this instance refers to a nested-name-specifier
- /// \c \::std::vector<int>::, the returned source range would cover
- /// from the initial '::' to the last '::'.
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getBeginLoc(), getEndLoc());
- }
+NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const {
+ if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace)
+ return {};
+ return castAsNamespaceAndPrefix();
+}
- /// Retrieve the source range covering just the last part of
- /// this nested-name-specifier, not including the prefix.
- ///
- /// For example, if this instance refers to a nested-name-specifier
- /// \c \::std::vector<int>::, the returned source range would cover
- /// from "vector" to the last '::'.
- SourceRange getLocalSourceRange() const;
-
- /// Retrieve the location of the beginning of this
- /// nested-name-specifier.
- SourceLocation getBeginLoc() const {
- if (!Qualifier)
- return SourceLocation();
-
- NestedNameSpecifierLoc First = *this;
- while (NestedNameSpecifierLoc Prefix = First.getPrefix())
- First = Prefix;
- return First.getLocalSourceRange().getBegin();
+unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) {
+ unsigned Length = 0;
+ for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) {
+ Length += getLocalDataLength(Qualifier);
+ if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace)
+ break;
}
+ return Length;
+}
- /// Retrieve the location of the end of this
- /// nested-name-specifier.
- SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); }
+unsigned NestedNameSpecifierLoc::getDataLength() const {
+ return getDataLength(Qualifier);
+}
- /// Retrieve the location of the beginning of this
- /// component of the nested-name-specifier.
- SourceLocation getLocalBeginLoc() const {
- return getLocalSourceRange().getBegin();
+SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
+ switch (auto Kind = Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ return SourceRange();
+ case NestedNameSpecifier::Kind::Global:
+ return LoadSourceLocation(/*Offset=*/0);
+ case NestedNameSpecifier::Kind::Namespace:
+ case NestedNameSpecifier::Kind::MicrosoftSuper: {
+ unsigned Offset =
+ Kind == NestedNameSpecifier::Kind::Namespace
+ ? getDataLength(Qualifier.getAsNamespaceAndPrefix().Prefix)
+ : 0;
+ return SourceRange(
+ LoadSourceLocation(Offset),
+ LoadSourceLocation(Offset + sizeof(SourceLocation::UIntTy)));
}
-
- /// Retrieve the location of the end of this component of the
- /// nested-name-specifier.
- SourceLocation getLocalEndLoc() const {
- return getLocalSourceRange().getEnd();
+ case NestedNameSpecifier::Kind::Type: {
+ // The "void*" that points at the TypeLoc data.
+ // Note: the 'template' keyword is part of the TypeLoc.
+ void *TypeData = LoadPointer(/*Offset=*/0);
+ TypeLoc TL(Qualifier.getAsType(), TypeData);
+ return SourceRange(TL.getBeginLoc(), LoadSourceLocation(sizeof(void *)));
}
-
- /// Return the prefix of this nested-name-specifier.
- ///
- /// For example, if this instance refers to a nested-name-specifier
- /// \c \::std::vector<int>::, the prefix is \c \::std::. Note that the
- /// returned prefix may be empty, if this is the first component of
- /// the nested-name-specifier.
- NestedNameSpecifierLoc getPrefix() const {
- if (!Qualifier)
- return *this;
-
- return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data);
}
- /// For a nested-name-specifier that refers to a type,
- /// retrieve the type with source-location information.
- TypeLoc getTypeLoc() const;
+ llvm_unreachable("Invalid NNS Kind!");
+}
- /// Determines the data length for the entire
- /// nested-name-specifier.
- unsigned getDataLength() const { return getDataLength(Qualifier); }
+SourceRange NestedNameSpecifierLoc::getSourceRange() const {
+ return SourceRange(getBeginLoc(), getEndLoc());
+}
- friend bool operator==(NestedNameSpecifierLoc X,
- NestedNameSpecifierLoc Y) {
- return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
- }
+SourceLocation NestedNameSpecifierLoc::getEndLoc() const {
+ return getLocalSourceRange().getEnd();
+}
- friend bool operator!=(NestedNameSpecifierLoc X,
- NestedNameSpecifierLoc Y) {
- return !(X == Y);
- }
-};
+/// Retrieve the location of the beginning of this
+/// component of the nested-name-specifier.
+SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const {
+ return getLocalSourceRange().getBegin();
+}
-/// Class that aids in the construction of nested-name-specifiers along
-/// with source-location information for all of the components of the
+/// Retrieve the location of the end of this component of the
/// nested-name-specifier.
-class NestedNameSpecifierLocBuilder {
- /// The current representation of the nested-name-specifier we're
- /// building.
- NestedNameSpecifier *Representation = nullptr;
-
- /// Buffer used to store source-location information for the
- /// nested-name-specifier.
- ///
- /// Note that we explicitly manage the buffer (rather than using a
- /// SmallVector) because \c Declarator expects it to be possible to memcpy()
- /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
- char *Buffer = nullptr;
-
- /// The size of the buffer used to store source-location information
- /// for the nested-name-specifier.
- unsigned BufferSize = 0;
-
- /// The capacity of the buffer used to store source-location
- /// information for the nested-name-specifier.
- unsigned BufferCapacity = 0;
-
-public:
- NestedNameSpecifierLocBuilder() = default;
- NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
-
- NestedNameSpecifierLocBuilder &
- operator=(const NestedNameSpecifierLocBuilder &Other);
-
- ~NestedNameSpecifierLocBuilder() {
- if (BufferCapacity)
- free(Buffer);
- }
+SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const {
+ return getLocalSourceRange().getEnd();
+}
- /// Retrieve the representation of the nested-name-specifier.
- NestedNameSpecifier *getRepresentation() const { return Representation; }
-
- /// Extend the current nested-name-specifier by another
- /// nested-name-specifier component of the form 'type::'.
- ///
- /// \param Context The AST context in which this nested-name-specifier
- /// resides.
- ///
- /// \param TL The TypeLoc that describes the type preceding the '::'.
- ///
- /// \param ColonColonLoc The location of the trailing '::'.
- void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
-
- /// Extend the current nested-name-specifier by another
- /// nested-name-specifier component of the form 'identifier::'.
- ///
- /// \param Context The AST context in which this nested-name-specifier
- /// resides.
- ///
- /// \param Identifier The identifier.
- ///
- /// \param IdentifierLoc The location of the identifier.
- ///
- /// \param ColonColonLoc The location of the trailing '::'.
- void Extend(ASTContext &Context, IdentifierInfo *Identifier,
- SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
-
- /// Extend the current nested-name-specifier by another
- /// nested-name-specifier component of the form 'namespace::'.
- ///
- /// \param Context The AST context in which this nested-name-specifier
- /// resides.
- ///
- /// \param Namespace The namespace or namespace alias.
- ///
- /// \param NamespaceLoc The location of the namespace name or the namespace
- // alias.
- ///
- /// \param ColonColonLoc The location of the trailing '::'.
- void Extend(ASTContext &Context, NamespaceBaseDecl *Namespace,
- SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
-
- /// Turn this (empty) nested-name-specifier into the global
- /// nested-name-specifier '::'.
- void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
-
- /// Turns this (empty) nested-name-specifier into '__super'
- /// nested-name-specifier.
- ///
- /// \param Context The AST context in which this nested-name-specifier
- /// resides.
- ///
- /// \param RD The declaration of the class in which nested-name-specifier
- /// appeared.
- ///
- /// \param SuperLoc The location of the '__super' keyword.
- /// name.
- ///
- /// \param ColonColonLoc The location of the trailing '::'.
- void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
- SourceLocation SuperLoc, SourceLocation ColonColonLoc);
-
- /// Make a new nested-name-specifier from incomplete source-location
- /// information.
- ///
- /// This routine should be used very, very rarely, in cases where we
- /// need to synthesize a nested-name-specifier. Most code should instead use
- /// \c Adopt() with a proper \c NestedNameSpecifierLoc.
- void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
- SourceRange R);
-
- /// Adopt an existing nested-name-specifier (with source-range
- /// information).
- void Adopt(NestedNameSpecifierLoc Other);
-
- /// Retrieve the source range covered by this nested-name-specifier.
- SourceRange getSourceRange() const LLVM_READONLY {
- return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
- }
+SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const {
+ return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
+}
- /// Retrieve a nested-name-specifier with location information,
- /// copied into the given AST context.
- ///
- /// \param Context The context into which this nested-name-specifier will be
- /// copied.
- NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
-
- /// Retrieve a nested-name-specifier with location
- /// information based on the information in this builder.
- ///
- /// This loc will contain references to the builder's internal data and may
- /// be invalidated by any change to the builder.
- NestedNameSpecifierLoc getTemporary() const {
- return NestedNameSpecifierLoc(Representation, Buffer);
- }
+} // namespace clang
+
+namespace llvm {
+
+template <> struct DenseMapInfo<clang::NestedNameSpecifier> {
+ static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; }
- /// Clear out this builder, and prepare it to build another
- /// nested-name-specifier with source-location information.
- void Clear() {
- Representation = nullptr;
- BufferSize = 0;
+ static clang::NestedNameSpecifier getTombstoneKey() {
+ return clang::NestedNameSpecifier::getInvalid();
}
- /// Retrieve the underlying buffer.
- ///
- /// \returns A pair containing a pointer to the buffer of source-location
- /// data and the size of the source-location data that resides in that
- /// buffer.
- std::pair<char *, unsigned> getBuffer() const {
- return std::make_pair(Buffer, BufferSize);
+ static unsigned getHashValue(const clang::NestedNameSpecifier &V) {
+ return hash_combine(V.getAsVoidPointer());
}
};
-/// Insertion operator for diagnostics. This allows sending
-/// NestedNameSpecifiers into a diagnostic with <<.
-inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
- NestedNameSpecifier *NNS) {
- DB.AddTaggedVal(reinterpret_cast<uint64_t>(NNS),
- DiagnosticsEngine::ak_nestednamespec);
- return DB;
-}
-
-} // namespace clang
-
-namespace llvm {
-
template <> struct DenseMapInfo<clang::NestedNameSpecifierLoc> {
- using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier *>;
+ using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier>;
using SecondInfo = DenseMapInfo<void *>;
static clang::NestedNameSpecifierLoc getEmptyKey() {
diff --git a/clang/include/clang/AST/NestedNameSpecifierBase.h b/clang/include/clang/AST/NestedNameSpecifierBase.h
new file mode 100644
index 0000000..73c60ba
--- /dev/null
+++ b/clang/include/clang/AST/NestedNameSpecifierBase.h
@@ -0,0 +1,586 @@
+//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the NestedNameSpecifier class, which represents
+// a C++ nested-name-specifier.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
+#define LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
+
+#include "clang/AST/DependenceFlags.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include <cstdint>
+#include <cstdlib>
+#include <utility>
+
+namespace clang {
+
+class ASTContext;
+class CXXRecordDecl;
+class NamedDecl;
+class IdentifierInfo;
+class LangOptions;
+class NamespaceBaseDecl;
+struct PrintingPolicy;
+class Type;
+class TypeLoc;
+
+struct NamespaceAndPrefix;
+struct alignas(8) NamespaceAndPrefixStorage;
+
+/// Represents a C++ nested name specifier, such as
+/// "\::std::vector<int>::".
+///
+/// C++ nested name specifiers are the prefixes to qualified
+/// names. For example, "foo::" in "foo::x" is a nested name
+/// specifier. Nested name specifiers are made up of a sequence of
+/// specifiers, each of which can be a namespace, type, decltype specifier, or
+/// the global specifier ('::'). The last two specifiers can only appear at the
+/// start of a nested-namespace-specifier.
+class NestedNameSpecifier {
+ enum class FlagKind { Null, Global, Invalid };
+ enum class StoredKind {
+ Type,
+ NamespaceOrSuper,
+ NamespaceWithGlobal,
+ NamespaceWithNamespace
+ };
+ static constexpr uintptr_t FlagBits = 2, FlagMask = (1u << FlagBits) - 1u,
+ FlagOffset = 1, PtrOffset = FlagBits + FlagOffset,
+ PtrMask = (1u << PtrOffset) - 1u;
+
+ uintptr_t StoredOrFlag;
+
+ explicit NestedNameSpecifier(uintptr_t StoredOrFlag)
+ : StoredOrFlag(StoredOrFlag) {}
+ struct PtrKind {
+ StoredKind SK;
+ const void *Ptr;
+ };
+ explicit NestedNameSpecifier(PtrKind PK)
+ : StoredOrFlag(uintptr_t(PK.Ptr) | (uintptr_t(PK.SK) << FlagOffset)) {
+ assert(PK.Ptr != nullptr);
+ assert((uintptr_t(PK.Ptr) & ((1u << PtrOffset) - 1u)) == 0);
+ assert((uintptr_t(PK.Ptr) >> PtrOffset) != 0);
+ }
+
+ explicit constexpr NestedNameSpecifier(FlagKind K)
+ : StoredOrFlag(uintptr_t(K) << FlagOffset) {}
+
+ bool isStoredKind() const { return (StoredOrFlag >> PtrOffset) != 0; }
+
+ std::pair<StoredKind, const void *> getStored() const {
+ assert(isStoredKind());
+ return {StoredKind(StoredOrFlag >> FlagOffset & FlagMask),
+ reinterpret_cast<const void *>(StoredOrFlag & ~PtrMask)};
+ }
+
+ FlagKind getFlagKind() const {
+ assert(!isStoredKind());
+ return FlagKind(StoredOrFlag >> FlagOffset);
+ }
+
+ static const NamespaceAndPrefixStorage *
+ MakeNamespaceAndPrefixStorage(const ASTContext &Ctx,
+ const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix);
+ static inline PtrKind MakeNamespacePtrKind(const ASTContext &Ctx,
+ const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix);
+
+public:
+ static constexpr NestedNameSpecifier getInvalid() {
+ return NestedNameSpecifier(FlagKind::Invalid);
+ }
+
+ static constexpr NestedNameSpecifier getGlobal() {
+ return NestedNameSpecifier(FlagKind::Global);
+ }
+
+ NestedNameSpecifier() : NestedNameSpecifier(FlagKind::Invalid) {}
+
+ /// The kind of specifier that completes this nested name
+ /// specifier.
+ enum class Kind {
+ /// Empty.
+ Null,
+
+ /// The global specifier '::'. There is no stored value.
+ Global,
+
+ /// A type, stored as a Type*.
+ Type,
+
+ /// A namespace-like entity, stored as a NamespaceBaseDecl*.
+ Namespace,
+
+ /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
+ /// the class it appeared in.
+ MicrosoftSuper,
+ };
+
+ inline Kind getKind() const;
+
+ NestedNameSpecifier(std::nullopt_t) : StoredOrFlag(0) {}
+
+ explicit inline NestedNameSpecifier(const Type *T);
+
+ /// Builds a nested name specifier that names a namespace.
+ inline NestedNameSpecifier(const ASTContext &Ctx,
+ const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix);
+
+ /// Builds a nested name specifier that names a class through microsoft's
+ /// __super specifier.
+ explicit inline NestedNameSpecifier(CXXRecordDecl *RD);
+
+ explicit operator bool() const { return StoredOrFlag != 0; }
+
+ void *getAsVoidPointer() const {
+ return reinterpret_cast<void *>(StoredOrFlag);
+ }
+ static NestedNameSpecifier getFromVoidPointer(const void *Ptr) {
+ return NestedNameSpecifier(reinterpret_cast<uintptr_t>(Ptr));
+ }
+
+ const Type *getAsType() const {
+ auto [Kind, Ptr] = getStored();
+ assert(Kind == StoredKind::Type);
+ assert(Ptr != nullptr);
+ return static_cast<const Type *>(Ptr);
+ }
+
+ inline NamespaceAndPrefix getAsNamespaceAndPrefix() const;
+
+ CXXRecordDecl *getAsMicrosoftSuper() const {
+ auto [Kind, Ptr] = getStored();
+ assert(Kind == StoredKind::NamespaceOrSuper);
+ assert(Ptr != nullptr);
+ return static_cast<CXXRecordDecl *>(const_cast<void *>(Ptr));
+ }
+
+ /// Retrieve the record declaration stored in this nested name
+ /// specifier, or null.
+ inline CXXRecordDecl *getAsRecordDecl() const;
+
+ friend bool operator==(NestedNameSpecifier LHS, NestedNameSpecifier RHS) {
+ return LHS.StoredOrFlag == RHS.StoredOrFlag;
+ }
+ friend bool operator!=(NestedNameSpecifier LHS, NestedNameSpecifier RHS) {
+ return LHS.StoredOrFlag != RHS.StoredOrFlag;
+ }
+
+ /// Retrieves the "canonical" nested name specifier for a
+ /// given nested name specifier.
+ ///
+ /// The canonical nested name specifier is a nested name specifier
+ /// that uniquely identifies a type or namespace within the type
+ /// system. For example, given:
+ ///
+ /// \code
+ /// namespace N {
+ /// struct S {
+ /// template<typename T> struct X { typename T* type; };
+ /// };
+ /// }
+ ///
+ /// template<typename T> struct Y {
+ /// typename N::S::X<T>::type member;
+ /// };
+ /// \endcode
+ ///
+ /// Here, the nested-name-specifier for N::S::X<T>:: will be
+ /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
+ /// by declarations in the type system and the canonical type for
+ /// the template type parameter 'T' is template-param-0-0.
+ inline NestedNameSpecifier getCanonical() const;
+
+ /// Whether this nested name specifier is canonical.
+ inline bool isCanonical() const;
+
+ /// Whether this nested name specifier starts with a '::'.
+ bool isFullyQualified() const;
+
+ NestedNameSpecifierDependence getDependence() const;
+
+ /// Whether this nested name specifier refers to a dependent
+ /// type or not.
+ bool isDependent() const {
+ return getDependence() & NestedNameSpecifierDependence::Dependent;
+ }
+
+ /// Whether this nested name specifier involves a template
+ /// parameter.
+ bool isInstantiationDependent() const {
+ return getDependence() & NestedNameSpecifierDependence::Instantiation;
+ }
+
+ /// Whether this nested-name-specifier contains an unexpanded
+ /// parameter pack (for C++11 variadic templates).
+ bool containsUnexpandedParameterPack() const {
+ return getDependence() & NestedNameSpecifierDependence::UnexpandedPack;
+ }
+
+ /// Whether this nested name specifier contains an error.
+ bool containsErrors() const {
+ return getDependence() & NestedNameSpecifierDependence::Error;
+ }
+
+ /// Print this nested name specifier to the given output stream. If
+ /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
+ /// `ns::SomeTemplate<int, MyClass>` instead of
+ /// `ns::SomeTemplate<Container::value_type, T>`.
+ void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ bool ResolveTemplateArguments = false,
+ bool PrintFinalScopeResOp = true) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(StoredOrFlag);
+ }
+
+ /// Dump the nested name specifier to aid in debugging.
+ void dump(llvm::raw_ostream *OS = nullptr,
+ const LangOptions *LO = nullptr) const;
+ void dump(const LangOptions &LO) const;
+ void dump(llvm::raw_ostream &OS) const;
+ void dump(llvm::raw_ostream &OS, const LangOptions &LO) const;
+
+ static constexpr auto NumLowBitsAvailable = FlagOffset;
+};
+
+struct NamespaceAndPrefix {
+ const NamespaceBaseDecl *Namespace;
+ NestedNameSpecifier Prefix;
+};
+
+struct alignas(8) NamespaceAndPrefixStorage : NamespaceAndPrefix,
+ llvm::FoldingSetNode {
+ NamespaceAndPrefixStorage(const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix)
+ : NamespaceAndPrefix{Namespace, Prefix} {}
+ void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Namespace, Prefix); }
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix) {
+ ID.AddPointer(Namespace);
+ Prefix.Profile(ID);
+ }
+};
+
+NamespaceAndPrefix NestedNameSpecifier::getAsNamespaceAndPrefix() const {
+ auto [Kind, Ptr] = getStored();
+ switch (Kind) {
+ case StoredKind::NamespaceOrSuper:
+ case StoredKind::NamespaceWithGlobal:
+ return {static_cast<const NamespaceBaseDecl *>(Ptr),
+ Kind == StoredKind::NamespaceWithGlobal
+ ? NestedNameSpecifier::getGlobal()
+ : std::nullopt};
+ case StoredKind::NamespaceWithNamespace:
+ return *static_cast<const NamespaceAndPrefixStorage *>(Ptr);
+ case StoredKind::Type:;
+ }
+ llvm_unreachable("unexpected stored kind");
+}
+
+struct NamespaceAndPrefixLoc;
+
+/// A C++ nested-name-specifier augmented with source location
+/// information.
+class NestedNameSpecifierLoc {
+ NestedNameSpecifier Qualifier = std::nullopt;
+ void *Data = nullptr;
+
+ /// Load a (possibly unaligned) source location from a given address
+ /// and offset.
+ SourceLocation LoadSourceLocation(unsigned Offset) const {
+ SourceLocation::UIntTy Raw;
+ memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw));
+ return SourceLocation::getFromRawEncoding(Raw);
+ }
+
+ /// Load a (possibly unaligned) pointer from a given address and
+ /// offset.
+ void *LoadPointer(unsigned Offset) const {
+ void *Result;
+ memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void *));
+ return Result;
+ }
+
+ /// Determines the data length for the last component in the
+ /// given nested-name-specifier.
+ static inline unsigned getLocalDataLength(NestedNameSpecifier Qualifier);
+
+ /// Determines the data length for the entire
+ /// nested-name-specifier.
+ static inline unsigned getDataLength(NestedNameSpecifier Qualifier);
+
+public:
+ /// Construct an empty nested-name-specifier.
+ NestedNameSpecifierLoc() = default;
+
+ /// Construct a nested-name-specifier with source location information
+ /// from
+ NestedNameSpecifierLoc(NestedNameSpecifier Qualifier, void *Data)
+ : Qualifier(Qualifier), Data(Data) {}
+
+ /// Evaluates true when this nested-name-specifier location is
+ /// non-empty.
+ explicit operator bool() const { return bool(Qualifier); }
+
+ /// Evaluates true when this nested-name-specifier location is
+ /// non-empty.
+ bool hasQualifier() const { return bool(Qualifier); }
+
+ /// Retrieve the nested-name-specifier to which this instance
+ /// refers.
+ NestedNameSpecifier getNestedNameSpecifier() const { return Qualifier; }
+
+ /// Retrieve the opaque pointer that refers to source-location data.
+ void *getOpaqueData() const { return Data; }
+
+ /// Retrieve the source range covering the entirety of this
+ /// nested-name-specifier.
+ ///
+ /// For example, if this instance refers to a nested-name-specifier
+ /// \c \::std::vector<int>::, the returned source range would cover
+ /// from the initial '::' to the last '::'.
+ inline SourceRange getSourceRange() const LLVM_READONLY;
+
+ /// Retrieve the source range covering just the last part of
+ /// this nested-name-specifier, not including the prefix.
+ ///
+ /// For example, if this instance refers to a nested-name-specifier
+ /// \c \::std::vector<int>::, the returned source range would cover
+ /// from "vector" to the last '::'.
+ inline SourceRange getLocalSourceRange() const;
+
+ /// Retrieve the location of the beginning of this
+ /// nested-name-specifier.
+ SourceLocation getBeginLoc() const;
+
+ /// Retrieve the location of the end of this
+ /// nested-name-specifier.
+ inline SourceLocation getEndLoc() const;
+
+ /// Retrieve the location of the beginning of this
+ /// component of the nested-name-specifier.
+ inline SourceLocation getLocalBeginLoc() const;
+
+ /// Retrieve the location of the end of this component of the
+ /// nested-name-specifier.
+ inline SourceLocation getLocalEndLoc() const;
+
+ /// For a nested-name-specifier that refers to a namespace,
+ /// retrieve the namespace and its prefix.
+ ///
+ /// For example, if this instance refers to a nested-name-specifier
+ /// \c \::std::chrono::, the prefix is \c \::std::. Note that the
+ /// returned prefix may be empty, if this is the first component of
+ /// the nested-name-specifier.
+ inline NamespaceAndPrefixLoc castAsNamespaceAndPrefix() const;
+ inline NamespaceAndPrefixLoc getAsNamespaceAndPrefix() const;
+
+ /// For a nested-name-specifier that refers to a type,
+ /// retrieve the type with source-location information.
+ inline TypeLoc castAsTypeLoc() const;
+ inline TypeLoc getAsTypeLoc() const;
+
+ /// Determines the data length for the entire
+ /// nested-name-specifier.
+ inline unsigned getDataLength() const;
+
+ friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) {
+ return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
+ }
+
+ friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) {
+ return !(X == Y);
+ }
+};
+
+struct NamespaceAndPrefixLoc {
+ const NamespaceBaseDecl *Namespace = nullptr;
+ NestedNameSpecifierLoc Prefix;
+
+ explicit operator bool() const { return Namespace != nullptr; }
+};
+
+/// Class that aids in the construction of nested-name-specifiers along
+/// with source-location information for all of the components of the
+/// nested-name-specifier.
+class NestedNameSpecifierLocBuilder {
+ /// The current representation of the nested-name-specifier we're
+ /// building.
+ NestedNameSpecifier Representation = std::nullopt;
+
+ /// Buffer used to store source-location information for the
+ /// nested-name-specifier.
+ ///
+ /// Note that we explicitly manage the buffer (rather than using a
+ /// SmallVector) because \c Declarator expects it to be possible to memcpy()
+ /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
+ char *Buffer = nullptr;
+
+ /// The size of the buffer used to store source-location information
+ /// for the nested-name-specifier.
+ unsigned BufferSize = 0;
+
+ /// The capacity of the buffer used to store source-location
+ /// information for the nested-name-specifier.
+ unsigned BufferCapacity = 0;
+
+ void PushTrivial(ASTContext &Context, NestedNameSpecifier Qualifier,
+ SourceRange R);
+
+public:
+ NestedNameSpecifierLocBuilder() = default;
+ NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
+
+ NestedNameSpecifierLocBuilder &
+ operator=(const NestedNameSpecifierLocBuilder &Other);
+
+ ~NestedNameSpecifierLocBuilder() {
+ if (BufferCapacity)
+ free(Buffer);
+ }
+
+ /// Retrieve the representation of the nested-name-specifier.
+ NestedNameSpecifier getRepresentation() const { return Representation; }
+
+ /// Make a nested-name-specifier of the form 'type::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param TL The TypeLoc that describes the type preceding the '::'.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
+
+ /// Extend the current nested-name-specifier by another
+ /// nested-name-specifier component of the form 'namespace::'.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param Namespace The namespace.
+ ///
+ /// \param NamespaceLoc The location of the namespace name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void Extend(ASTContext &Context, const NamespaceBaseDecl *Namespace,
+ SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
+
+ /// Turn this (empty) nested-name-specifier into the global
+ /// nested-name-specifier '::'.
+ void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
+
+ /// Turns this (empty) nested-name-specifier into '__super'
+ /// nested-name-specifier.
+ ///
+ /// \param Context The AST context in which this nested-name-specifier
+ /// resides.
+ ///
+ /// \param RD The declaration of the class in which nested-name-specifier
+ /// appeared.
+ ///
+ /// \param SuperLoc The location of the '__super' keyword.
+ /// name.
+ ///
+ /// \param ColonColonLoc The location of the trailing '::'.
+ void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc);
+
+ /// Make a new nested-name-specifier from incomplete source-location
+ /// information.
+ ///
+ /// This routine should be used very, very rarely, in cases where we
+ /// need to synthesize a nested-name-specifier. Most code should instead use
+ /// \c Adopt() with a proper \c NestedNameSpecifierLoc.
+ void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier,
+ SourceRange R) {
+ Representation = Qualifier;
+ BufferSize = 0;
+ PushTrivial(Context, Qualifier, R);
+ }
+
+ /// Adopt an existing nested-name-specifier (with source-range
+ /// information).
+ void Adopt(NestedNameSpecifierLoc Other);
+
+ /// Retrieve the source range covered by this nested-name-specifier.
+ inline SourceRange getSourceRange() const LLVM_READONLY;
+
+ /// Retrieve a nested-name-specifier with location information,
+ /// copied into the given AST context.
+ ///
+ /// \param Context The context into which this nested-name-specifier will be
+ /// copied.
+ NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
+
+ /// Retrieve a nested-name-specifier with location
+ /// information based on the information in this builder.
+ ///
+ /// This loc will contain references to the builder's internal data and may
+ /// be invalidated by any change to the builder.
+ NestedNameSpecifierLoc getTemporary() const {
+ return NestedNameSpecifierLoc(Representation, Buffer);
+ }
+
+ /// Clear out this builder, and prepare it to build another
+ /// nested-name-specifier with source-location information.
+ void Clear() {
+ Representation = std::nullopt;
+ BufferSize = 0;
+ }
+
+ /// Retrieve the underlying buffer.
+ ///
+ /// \returns A pair containing a pointer to the buffer of source-location
+ /// data and the size of the source-location data that resides in that
+ /// buffer.
+ std::pair<char *, unsigned> getBuffer() const {
+ return std::make_pair(Buffer, BufferSize);
+ }
+};
+
+/// Insertion operator for diagnostics. This allows sending
+/// NestedNameSpecifiers into a diagnostic with <<.
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+ NestedNameSpecifier NNS) {
+ DB.AddTaggedVal(reinterpret_cast<uintptr_t>(NNS.getAsVoidPointer()),
+ DiagnosticsEngine::ak_nestednamespec);
+ return DB;
+}
+
+} // namespace clang
+
+namespace llvm {
+
+template <> struct PointerLikeTypeTraits<clang::NestedNameSpecifier> {
+ static void *getAsVoidPointer(clang::NestedNameSpecifier P) {
+ return P.getAsVoidPointer();
+ }
+ static clang::NestedNameSpecifier getFromVoidPointer(const void *P) {
+ return clang::NestedNameSpecifier::getFromVoidPointer(P);
+ }
+ static constexpr int NumLowBitsAvailable =
+ clang::NestedNameSpecifier::NumLowBitsAvailable;
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
diff --git a/clang/include/clang/AST/ODRHash.h b/clang/include/clang/AST/ODRHash.h
index 11f917a..ae3fab6 100644
--- a/clang/include/clang/AST/ODRHash.h
+++ b/clang/include/clang/AST/ODRHash.h
@@ -93,7 +93,7 @@ public:
void AddQualType(QualType T);
void AddStmt(const Stmt *S);
void AddIdentifierInfo(const IdentifierInfo *II);
- void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
+ void AddNestedNameSpecifier(NestedNameSpecifier NNS);
void AddDependentTemplateName(const DependentTemplateStorage &Name);
void AddTemplateName(TemplateName Name);
void AddDeclarationNameInfo(DeclarationNameInfo NameInfo,
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 8c848a1..2f4aba1 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -876,21 +876,32 @@ public:
}
};
+// A 'pair' to stand in for the recipe. RecipeDecl is the main declaration, and
+// InitFromTemporary is the 'temp' declaration we put in to be 'copied from'.
+struct OpenACCFirstPrivateRecipe {
+ VarDecl *RecipeDecl, *InitFromTemporary;
+ OpenACCFirstPrivateRecipe(VarDecl *R, VarDecl *T)
+ : RecipeDecl(R), InitFromTemporary(T) {}
+ OpenACCFirstPrivateRecipe(std::pair<VarDecl *, VarDecl *> p)
+ : RecipeDecl(p.first), InitFromTemporary(p.second) {}
+};
+
class OpenACCFirstPrivateClause final
: public OpenACCClauseWithVarList,
private llvm::TrailingObjects<OpenACCFirstPrivateClause, Expr *,
- VarDecl *> {
+ OpenACCFirstPrivateRecipe> {
friend TrailingObjects;
OpenACCFirstPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<OpenACCFirstPrivateRecipe> InitRecipes,
SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::FirstPrivate, BeginLoc,
LParenLoc, EndLoc) {
assert(VarList.size() == InitRecipes.size());
setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
- llvm::uninitialized_copy(InitRecipes, getTrailingObjects<VarDecl *>());
+ llvm::uninitialized_copy(InitRecipes,
+ getTrailingObjects<OpenACCFirstPrivateRecipe>());
}
public:
@@ -900,19 +911,20 @@ public:
// Gets a list of 'made up' `VarDecl` objects that can be used by codegen to
// ensure that we properly initialize each of these variables.
- ArrayRef<VarDecl *> getInitRecipes() {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCFirstPrivateRecipe> getInitRecipes() {
+ return ArrayRef<OpenACCFirstPrivateRecipe>{
+ getTrailingObjects<OpenACCFirstPrivateRecipe>(), getExprs().size()};
}
- ArrayRef<VarDecl *> getInitRecipes() const {
- return ArrayRef<VarDecl *>{getTrailingObjects<VarDecl *>(),
- getExprs().size()};
+ ArrayRef<OpenACCFirstPrivateRecipe> getInitRecipes() const {
+ return ArrayRef<OpenACCFirstPrivateRecipe>{
+ getTrailingObjects<OpenACCFirstPrivateRecipe>(), getExprs().size()};
}
static OpenACCFirstPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
- ArrayRef<Expr *> VarList, ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<Expr *> VarList,
+ ArrayRef<OpenACCFirstPrivateRecipe> InitRecipes,
SourceLocation EndLoc);
size_t numTrailingObjects(OverloadToken<Expr *>) const {
@@ -1238,19 +1250,32 @@ public:
SourceLocation EndLoc);
};
+// A structure to stand in for the recipe on a reduction. RecipeDecl is the
+// 'main' declaration used for initializaiton, which is fixed.
+struct OpenACCReductionRecipe {
+ VarDecl *RecipeDecl;
+ // TODO: OpenACC: this should eventually have the operations here too.
+};
+
class OpenACCReductionClause final
: public OpenACCClauseWithVarList,
- private llvm::TrailingObjects<OpenACCReductionClause, Expr *> {
+ private llvm::TrailingObjects<OpenACCReductionClause, Expr *,
+ OpenACCReductionRecipe> {
friend TrailingObjects;
OpenACCReductionOperator Op;
OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator,
- ArrayRef<Expr *> VarList, SourceLocation EndLoc)
+ ArrayRef<Expr *> VarList,
+ ArrayRef<OpenACCReductionRecipe> Recipes,
+ SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
LParenLoc, EndLoc),
Op(Operator) {
- setExprs(getTrailingObjects(VarList.size()), VarList);
+ assert(VarList.size() == Recipes.size());
+ setExprs(getTrailingObjects<Expr *>(VarList.size()), VarList);
+ llvm::uninitialized_copy(Recipes, getTrailingObjects<
+ OpenACCReductionRecipe > ());
}
public:
@@ -1258,12 +1283,26 @@ public:
return C->getClauseKind() == OpenACCClauseKind::Reduction;
}
+ ArrayRef<OpenACCReductionRecipe> getRecipes() {
+ return ArrayRef<OpenACCReductionRecipe>{
+ getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()};
+ }
+
+ ArrayRef<OpenACCReductionRecipe> getRecipes() const {
+ return ArrayRef<OpenACCReductionRecipe>{
+ getTrailingObjects<OpenACCReductionRecipe>(), getExprs().size()};
+ }
+
static OpenACCReductionClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
- SourceLocation EndLoc);
+ ArrayRef<OpenACCReductionRecipe> Recipes, SourceLocation EndLoc);
OpenACCReductionOperator getReductionOp() const { return Op; }
+
+ size_t numTrailingObjects(OverloadToken<Expr *>) const {
+ return getExprs().size();
+ }
};
class OpenACCLinkClause final
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 1118d3e..72effbc 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -1865,62 +1865,43 @@ public:
/// \endcode
/// In this example directive '#pragma omp error' has simple
/// 'message' clause with user error message of "GNU compiler required.".
-class OMPMessageClause final : public OMPClause {
+class OMPMessageClause final
+ : public OMPOneStmtClause<llvm::omp::OMPC_message, OMPClause>,
+ public OMPClauseWithPreInit {
friend class OMPClauseReader;
- /// Location of '('
- SourceLocation LParenLoc;
-
- // Expression of the 'message' clause.
- Stmt *MessageString = nullptr;
-
/// Set message string of the clause.
- void setMessageString(Expr *MS) { MessageString = MS; }
-
- /// Sets the location of '('.
- void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+ void setMessageString(Expr *MS) { setStmt(MS); }
public:
/// Build 'message' clause with message string argument
///
/// \param MS Argument of the clause (message string).
+ /// \param HelperMS Helper statement for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
- OMPMessageClause(Expr *MS, SourceLocation StartLoc, SourceLocation LParenLoc,
+ OMPMessageClause(Expr *MS, Stmt *HelperMS, OpenMPDirectiveKind CaptureRegion,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
- : OMPClause(llvm::omp::OMPC_message, StartLoc, EndLoc),
- LParenLoc(LParenLoc), MessageString(MS) {}
-
- /// Build an empty clause.
- OMPMessageClause()
- : OMPClause(llvm::omp::OMPC_message, SourceLocation(), SourceLocation()) {
+ : OMPOneStmtClause(MS, StartLoc, LParenLoc, EndLoc),
+ OMPClauseWithPreInit(this) {
+ setPreInitStmt(HelperMS, CaptureRegion);
}
- /// Returns the locaiton of '('.
- SourceLocation getLParenLoc() const { return LParenLoc; }
+ /// Build an empty clause.
+ OMPMessageClause() : OMPOneStmtClause(), OMPClauseWithPreInit(this) {}
/// Returns message string of the clause.
- Expr *getMessageString() const { return cast_or_null<Expr>(MessageString); }
-
- child_range children() {
- return child_range(&MessageString, &MessageString + 1);
- }
-
- const_child_range children() const {
- return const_child_range(&MessageString, &MessageString + 1);
- }
-
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
-
- const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
- }
+ Expr *getMessageString() const { return getStmtAs<Expr>(); }
- static bool classof(const OMPClause *T) {
- return T->getClauseKind() == llvm::omp::OMPC_message;
+ /// Try to evaluate the message string at compile time.
+ std::optional<std::string> tryEvaluateString(ASTContext &Ctx) const {
+ if (Expr *MessageExpr = getMessageString())
+ return MessageExpr->tryEvaluateString(Ctx);
+ return std::nullopt;
}
};
diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h
index 875769c..fd995a6 100644
--- a/clang/include/clang/AST/PrettyPrinter.h
+++ b/clang/include/clang/AST/PrettyPrinter.h
@@ -63,9 +63,9 @@ struct PrintingPolicy {
SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
SuppressScope(false), SuppressUnwrittenScope(false),
SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
- SuppressElaboration(false), SuppressInitializers(false),
- ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
- SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
+ SuppressInitializers(false), ConstantArraySizeAsWritten(false),
+ AnonymousTagLocations(true), SuppressStrongLifetime(false),
+ SuppressLifetimeQualifiers(false),
SuppressTemplateArgsInCXXConstructors(false),
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus),
@@ -150,11 +150,6 @@ struct PrintingPolicy {
LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode)
unsigned SuppressInlineNamespace : 2;
- /// Ignore qualifiers and tag keywords as specified by elaborated type sugar,
- /// instead letting the underlying type print as normal.
- LLVM_PREFERRED_TYPE(bool)
- unsigned SuppressElaboration : 1;
-
/// Suppress printing of variable initializers.
///
/// This flag is used when printing the loop variable in a for-range
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 0438e4d..5b10127 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -127,9 +127,8 @@ def LValuePathSerializationHelper :
PropertyType<"APValue::LValuePathSerializationHelper"> {
let BufferElementTypes = [ LValuePathEntry ];
}
-def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
-def NestedNameSpecifierKind :
- EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
+def NestedNameSpecifier : PropertyType<"NestedNameSpecifier">;
+def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::Kind">;
def OverloadedOperatorKind : EnumPropertyType;
def Qualifiers : PropertyType;
def QualType : DefaultValuePropertyType;
diff --git a/clang/include/clang/AST/QualTypeNames.h b/clang/include/clang/AST/QualTypeNames.h
index daa86cd..9f5cf04 100644
--- a/clang/include/clang/AST/QualTypeNames.h
+++ b/clang/include/clang/AST/QualTypeNames.h
@@ -87,6 +87,16 @@ std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx,
/// specifier "::" should be prepended or not.
QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
bool WithGlobalNsPrefix = false);
+
+/// Get the fully qualified name for the declared context of a declaration.
+///
+/// \param[in] Ctx - the ASTContext to be used.
+/// \param[in] Decl - the declaration for which to get the fully qualified name.
+/// \param[in] WithGlobalNsPrefix - If true, then the global namespace
+/// specifier "::" will be prepended to the fully qualified name.
+NestedNameSpecifier
+getFullyQualifiedDeclaredContext(const ASTContext &Ctx, const Decl *Decl,
+ bool WithGlobalNsPrefix = false);
} // end namespace TypeName
} // end namespace clang
#endif // LLVM_CLANG_AST_QUALTYPENAMES_H
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 62991d9..02581c8 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -216,14 +216,14 @@ public:
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type).
- bool TraverseType(QualType T);
+ bool TraverseType(QualType T, bool TraverseQualifier = true);
/// Recursively visit a type with location, by dispatching to
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
///
/// \returns false if the visitation was terminated early, true
/// otherwise (including when the argument is a Null type location).
- bool TraverseTypeLoc(TypeLoc TL);
+ bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true);
/// Recursively visit an attribute, by dispatching to
/// Traverse*Attr() based on the argument's dynamic type.
@@ -242,7 +242,7 @@ public:
/// Recursively visit a C++ nested-name-specifier.
///
/// \returns false if the visitation was terminated early, true otherwise.
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
/// Recursively visit a C++ nested-name-specifier with location
/// information.
@@ -389,7 +389,8 @@ public:
// Declare Traverse*() for all concrete Type classes.
#define ABSTRACT_TYPE(CLASS, BASE)
-#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T);
+#define TYPE(CLASS, BASE) \
+ bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier);
#include "clang/AST/TypeNodes.inc"
// The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
@@ -410,7 +411,8 @@ public:
// Declare Traverse*() for all concrete TypeLoc classes.
#define ABSTRACT_TYPELOC(CLASS, BASE)
-#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
+#define TYPELOC(CLASS, BASE) \
+ bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier);
#include "clang/AST/TypeLocNodes.def"
// The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit.
@@ -490,6 +492,8 @@ private:
bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL,
unsigned Count);
bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL);
+ bool TraverseSubstPackTypeHelper(SubstPackType *T);
+ bool TraverseSubstPackTypeLocHelper(SubstPackTypeLoc TL);
bool TraverseRecordHelper(RecordDecl *D);
bool TraverseCXXRecordHelper(CXXRecordDecl *D);
bool TraverseDeclaratorHelper(DeclaratorDecl *D);
@@ -499,6 +503,8 @@ private:
bool TraverseOMPExecutableDirective(OMPExecutableDirective *S);
bool TraverseOMPLoopDirective(OMPLoopDirective *S);
bool TraverseOMPClause(OMPClause *C);
+ bool TraverseTagType(TagType *T, bool TraverseQualifier);
+ bool TraverseTagTypeLoc(TagTypeLoc TL, bool TraverseQualifier);
#define GEN_CLANG_CLAUSE_CLASS
#define CLAUSE_CLASS(Enum, Str, Class) bool Visit##Class(Class *C);
#include "llvm/Frontend/OpenMP/OMP.inc"
@@ -698,7 +704,8 @@ RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S, DataRecursionQueue *Queue) {
}
template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
+bool RecursiveASTVisitor<Derived>::TraverseType(QualType T,
+ bool TraverseQualifier) {
if (T.isNull())
return true;
@@ -707,7 +714,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
#define TYPE(CLASS, BASE) \
case Type::CLASS: \
return getDerived().Traverse##CLASS##Type( \
- static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr())));
+ static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr())), \
+ TraverseQualifier);
#include "clang/AST/TypeNodes.inc"
}
@@ -715,7 +723,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
}
template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
+bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL,
+ bool TraverseQualifier) {
if (TL.isNull())
return true;
@@ -723,7 +732,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
case TypeLoc::CLASS: \
- return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>());
+ return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>(), \
+ TraverseQualifier);
#include "clang/AST/TypeLocNodes.def"
}
@@ -779,46 +789,43 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
- NestedNameSpecifier *NNS) {
- if (!NNS)
+ NestedNameSpecifier NNS) {
+ switch (NNS.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
return true;
-
- if (NNS->getPrefix())
- TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix()));
-
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::Namespace:
+ TRY_TO(TraverseNestedNameSpecifier(NNS.getAsNamespaceAndPrefix().Prefix));
+ return true;
+ case NestedNameSpecifier::Kind::Type: {
+ auto *T = const_cast<Type *>(NNS.getAsType());
+ TRY_TO(TraverseNestedNameSpecifier(T->getPrefix()));
+ TRY_TO(TraverseType(QualType(T, 0), /*TraverseQualifier=*/false));
return true;
-
- case NestedNameSpecifier::TypeSpec:
- TRY_TO(TraverseType(QualType(NNS->getAsType(), 0)));
}
-
- return true;
+ }
+ llvm_unreachable("unhandled kind");
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
NestedNameSpecifierLoc NNS) {
- if (!NNS)
+ switch (NNS.getNestedNameSpecifier().getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
return true;
-
- if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
- TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
-
- switch (NNS.getNestedNameSpecifier()->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::Namespace:
+ TRY_TO(
+ TraverseNestedNameSpecifierLoc(NNS.castAsNamespaceAndPrefix().Prefix));
return true;
-
- case NestedNameSpecifier::TypeSpec:
- TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
- break;
+ case NestedNameSpecifier::Kind::Type: {
+ TypeLoc TL = NNS.castAsTypeLoc();
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getPrefix()));
+ TRY_TO(TraverseTypeLoc(TL, /*TraverseQualifier=*/false));
+ return true;
+ }
}
return true;
@@ -975,10 +982,13 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
// This macro makes available a variable T, the passed-in type.
#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T) { \
+ bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T, \
+ bool TraverseQualifier) { \
if (!getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFrom##TYPE(T)); \
- { CODE; } \
+ { \
+ CODE; \
+ } \
if (getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFrom##TYPE(T)); \
return true; \
@@ -1000,10 +1010,11 @@ DEF_TRAVERSE_TYPE(RValueReferenceType,
{ TRY_TO(TraverseType(T->getPointeeType())); })
DEF_TRAVERSE_TYPE(MemberPointerType, {
- TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
- if (T->isSugared())
- TRY_TO(TraverseType(
- QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0)));
+ NestedNameSpecifier Qualifier =
+ T->isSugared() ? cast<MemberPointerType>(T->getCanonicalTypeUnqualified())
+ ->getQualifier()
+ : T->getQualifier();
+ TRY_TO(TraverseNestedNameSpecifier(Qualifier));
TRY_TO(TraverseType(T->getPointeeType()));
})
@@ -1087,9 +1098,18 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
TRY_TO(TraverseStmt(NE));
})
-DEF_TRAVERSE_TYPE(UsingType, {})
-DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
-DEF_TRAVERSE_TYPE(TypedefType, {})
+DEF_TRAVERSE_TYPE(UsingType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+})
+DEF_TRAVERSE_TYPE(UnresolvedUsingType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+})
+DEF_TRAVERSE_TYPE(TypedefType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+})
DEF_TRAVERSE_TYPE(TypeOfExprType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
@@ -1115,27 +1135,15 @@ DEF_TRAVERSE_TYPE(AutoType, {
TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments()));
}
})
-DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(T->getTemplateName()));
- TRY_TO(TraverseType(T->getDeducedType()));
-})
-DEF_TRAVERSE_TYPE(RecordType, {})
-DEF_TRAVERSE_TYPE(EnumType, {})
DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
TRY_TO(TraverseType(T->getReplacementType()));
})
-DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
- TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
-})
-
-DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(T->getTemplateName()));
- TRY_TO(TraverseTemplateArguments(T->template_arguments()));
-})
-
-DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
+DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType,
+ { TRY_TO(TraverseSubstPackTypeHelper(T)); })
+DEF_TRAVERSE_TYPE(SubstBuiltinTemplatePackType,
+ { TRY_TO(TraverseSubstPackTypeHelper(T)); })
DEF_TRAVERSE_TYPE(AttributedType,
{ TRY_TO(TraverseType(T->getModifiedType())); })
@@ -1165,22 +1173,54 @@ DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); })
DEF_TRAVERSE_TYPE(MacroQualifiedType,
{ TRY_TO(TraverseType(T->getUnderlyingType())); })
-DEF_TRAVERSE_TYPE(ElaboratedType, {
- if (T->getQualifier()) {
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTagType(TagType *T,
+ bool TraverseQualifier) {
+ if (TraverseQualifier)
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
- }
- TRY_TO(TraverseType(T->getNamedType()));
-})
+ return true;
+}
-DEF_TRAVERSE_TYPE(DependentNameType,
- { TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); })
+DEF_TRAVERSE_TYPE(EnumType, { TRY_TO(TraverseTagType(T, TraverseQualifier)); })
+DEF_TRAVERSE_TYPE(RecordType,
+ { TRY_TO(TraverseTagType(T, TraverseQualifier)); })
+DEF_TRAVERSE_TYPE(InjectedClassNameType,
+ { TRY_TO(TraverseTagType(T, TraverseQualifier)); })
+
+DEF_TRAVERSE_TYPE(DependentNameType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
+})
DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
const DependentTemplateStorage &S = T->getDependentTemplateName();
- TRY_TO(TraverseNestedNameSpecifier(S.getQualifier()));
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifier(S.getQualifier()));
+ TRY_TO(TraverseTemplateArguments(T->template_arguments()));
+})
+
+DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
+ if (TraverseQualifier) {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ } else {
+ // FIXME: Try to preserve the rest of the template name.
+ TRY_TO(TraverseTemplateName(TemplateName(
+ T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true))));
+ }
TRY_TO(TraverseTemplateArguments(T->template_arguments()));
})
+DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
+ if (TraverseQualifier) {
+ TRY_TO(TraverseTemplateName(T->getTemplateName()));
+ } else {
+ // FIXME: Try to preserve the rest of the template name.
+ TRY_TO(TraverseTemplateName(TemplateName(
+ T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true))));
+ }
+ TRY_TO(TraverseType(T->getDeducedType()));
+})
+
DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); })
DEF_TRAVERSE_TYPE(ObjCTypeParamType, {})
@@ -1221,13 +1261,16 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {})
// continue to work.
#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
template <typename Derived> \
- bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \
+ bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc( \
+ TYPE##Loc TL, bool TraverseQualifier) { \
if (!getDerived().shouldTraversePostOrder()) { \
TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
if (getDerived().shouldWalkTypesOfTypeLocs()) \
TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE *>(TL.getTypePtr()))); \
} \
- { CODE; } \
+ { \
+ CODE; \
+ } \
if (getDerived().shouldTraversePostOrder()) { \
TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
if (getDerived().shouldWalkTypesOfTypeLocs()) \
@@ -1237,8 +1280,10 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {})
}
template <typename Derived>
-bool
-RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
+bool RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(
+ QualifiedTypeLoc TL, bool TraverseQualifier) {
+ assert(TraverseQualifier &&
+ "Qualifiers should never occur within NestedNameSpecifiers");
// Move this over to the 'main' typeloc tree. Note that this is a
// move -- we pretend that we were really looking at the unqualified
// typeloc all along -- rather than a recursion, so we don't follow
@@ -1391,9 +1436,21 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
TRY_TO(TraverseStmt(NE));
})
-DEF_TRAVERSE_TYPELOC(UsingType, {})
-DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
-DEF_TRAVERSE_TYPELOC(TypedefType, {})
+DEF_TRAVERSE_TYPELOC(UsingType, {
+ if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
+ TraverseQualifier && QualifierLoc)
+ TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
+})
+DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {
+ if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
+ TraverseQualifier && QualifierLoc)
+ TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
+})
+DEF_TRAVERSE_TYPELOC(TypedefType, {
+ if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
+ TraverseQualifier && QualifierLoc)
+ TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
+})
DEF_TRAVERSE_TYPELOC(TypeOfExprType,
{ TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); })
@@ -1423,30 +1480,30 @@ DEF_TRAVERSE_TYPELOC(AutoType, {
}
})
-DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
- TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
-})
-
-DEF_TRAVERSE_TYPELOC(RecordType, {})
-DEF_TRAVERSE_TYPELOC(EnumType, {})
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
})
-DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
+
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeLocHelper(
+ SubstPackTypeLoc TL) {
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
-})
+ return true;
+}
-// FIXME: use the loc for the template name?
-DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
- TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
- }
-})
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseSubstPackTypeHelper(
+ SubstPackType *T) {
+ TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
+ return true;
+}
+
+DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType,
+ { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
-DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {})
+DEF_TRAVERSE_TYPELOC(SubstBuiltinTemplatePackType,
+ { TRY_TO(TraverseSubstPackTypeLocHelper(TL)); })
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
@@ -1468,27 +1525,63 @@ DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType,
DEF_TRAVERSE_TYPELOC(HLSLInlineSpirvType,
{ TRY_TO(TraverseType(TL.getType())); })
-DEF_TRAVERSE_TYPELOC(ElaboratedType, {
- if (TL.getQualifierLoc()) {
- TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
- }
- TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc()));
-})
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseTagTypeLoc(TagTypeLoc TL,
+ bool TraverseQualifier) {
+ if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
+ TraverseQualifier && QualifierLoc)
+ TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
+ return true;
+}
+
+DEF_TRAVERSE_TYPELOC(EnumType,
+ { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
+DEF_TRAVERSE_TYPELOC(RecordType,
+ { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
+DEF_TRAVERSE_TYPELOC(InjectedClassNameType,
+ { TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
DEF_TRAVERSE_TYPELOC(DependentNameType, {
- TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
})
DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
- if (TL.getQualifierLoc()) {
+ if (TraverseQualifier)
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
+ TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
}
+})
+
+DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+
+ // FIXME: Try to preserve the rest of the template name.
+ TRY_TO(TraverseTemplateName(
+ TemplateName(TL.getTypePtr()->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true))));
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
}
})
+DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
+ if (TraverseQualifier)
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
+
+ const auto *T = TL.getTypePtr();
+ // FIXME: Try to preserve the rest of the template name.
+ TRY_TO(
+ TraverseTemplateName(TemplateName(T->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true))));
+
+ TRY_TO(TraverseType(T->getDeducedType()));
+})
+
DEF_TRAVERSE_TYPELOC(PackExpansionType,
{ TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); })
@@ -1631,8 +1724,9 @@ DEF_TRAVERSE_DECL(FriendDecl, {
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
// Traverse any CXXRecordDecl owned by this type, since
// it will not be in the parent context:
- if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>())
- TRY_TO(TraverseDecl(ET->getOwnedTagDecl()));
+ if (auto *TT = D->getFriendType()->getType()->getAs<TagType>();
+ TT && TT->isTagOwned())
+ TRY_TO(TraverseDecl(TT->getOriginalDecl()));
} else {
TRY_TO(TraverseDecl(D->getFriendDecl()));
}
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index eb384ea..de248ac 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -15,9 +15,9 @@
#define LLVM_CLANG_AST_TEMPLATEBASE_H
#include "clang/AST/DependenceFlags.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APInt.h"
@@ -478,31 +478,25 @@ public:
/// Location information for a TemplateArgument.
struct TemplateArgumentLocInfo {
-private:
struct TemplateTemplateArgLocInfo {
- // FIXME: We'd like to just use the qualifier in the TemplateName,
- // but template arguments get canonicalized too quickly.
- NestedNameSpecifier *Qualifier;
void *QualifierLocData;
+ SourceLocation TemplateKwLoc;
SourceLocation TemplateNameLoc;
SourceLocation EllipsisLoc;
};
- llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *>
- Pointer;
-
TemplateTemplateArgLocInfo *getTemplate() const {
return cast<TemplateTemplateArgLocInfo *>(Pointer);
}
-public:
TemplateArgumentLocInfo() {}
TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; }
TemplateArgumentLocInfo(Expr *E) { Pointer = E; }
// Ctx is used for allocation -- this case is unusually large and also rare,
// so we store the payload out-of-line.
- TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
+ TemplateArgumentLocInfo(ASTContext &Ctx, SourceLocation TemplateKwLoc,
+ NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateNameLoc,
SourceLocation EllipsisLoc);
@@ -512,10 +506,8 @@ public:
Expr *getAsExpr() const { return cast<Expr *>(Pointer); }
- NestedNameSpecifierLoc getTemplateQualifierLoc() const {
- const auto *Template = getTemplate();
- return NestedNameSpecifierLoc(Template->Qualifier,
- Template->QualifierLocData);
+ SourceLocation getTemplateKwLoc() const {
+ return getTemplate()->TemplateKwLoc;
}
SourceLocation getTemplateNameLoc() const {
@@ -525,6 +517,10 @@ public:
SourceLocation getTemplateEllipsisLoc() const {
return getTemplate()->EllipsisLoc;
}
+
+private:
+ llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *>
+ Pointer;
};
/// Location wrapper for a TemplateArgument. TemplateArgument is to
@@ -558,14 +554,10 @@ public:
}
TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument,
+ SourceLocation TemplateKWLoc,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateNameLoc,
- SourceLocation EllipsisLoc = SourceLocation())
- : Argument(Argument),
- LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) {
- assert(Argument.getKind() == TemplateArgument::Template ||
- Argument.getKind() == TemplateArgument::TemplateExpansion);
- }
+ SourceLocation EllipsisLoc = SourceLocation());
/// - Fetches the primary location of the argument.
SourceLocation getLocation() const {
@@ -614,13 +606,15 @@ public:
return LocInfo.getAsExpr();
}
- NestedNameSpecifierLoc getTemplateQualifierLoc() const {
+ SourceLocation getTemplateKWLoc() const {
if (Argument.getKind() != TemplateArgument::Template &&
Argument.getKind() != TemplateArgument::TemplateExpansion)
- return NestedNameSpecifierLoc();
- return LocInfo.getTemplateQualifierLoc();
+ return SourceLocation();
+ return LocInfo.getTemplateKwLoc();
}
+ NestedNameSpecifierLoc getTemplateQualifierLoc() const;
+
SourceLocation getTemplateNameLoc() const {
if (Argument.getKind() != TemplateArgument::Template &&
Argument.getKind() != TemplateArgument::TemplateExpansion)
diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h
index 63949f8..abb0669 100644
--- a/clang/include/clang/AST/TemplateName.h
+++ b/clang/include/clang/AST/TemplateName.h
@@ -14,7 +14,7 @@
#define LLVM_CLANG_AST_TEMPLATENAME_H
#include "clang/AST/DependenceFlags.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/UnsignedOrNone.h"
@@ -339,6 +339,14 @@ public:
/// structure, if any.
DependentTemplateName *getAsDependentTemplateName() const;
+ // Retrieve the qualifier and template keyword stored in either a underlying
+ // DependentTemplateName or QualifiedTemplateName.
+ std::tuple<NestedNameSpecifier, bool> getQualifierAndTemplateKeyword() const;
+
+ NestedNameSpecifier getQualifier() const {
+ return std::get<0>(getQualifierAndTemplateKeyword());
+ }
+
/// Retrieve the using shadow declaration through which the underlying
/// template declaration is introduced, if any.
UsingShadowDecl *getAsUsingShadowDecl() const;
@@ -503,7 +511,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
/// "template" keyword is always redundant in this case (otherwise,
/// the template name would be a dependent name and we would express
/// this name with DependentTemplateName).
- llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
+ llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier;
/// The underlying template name, it is either
/// 1) a Template -- a template declaration that this qualified name refers
@@ -512,7 +520,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
/// using-shadow declaration.
TemplateName UnderlyingTemplate;
- QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
+ QualifiedTemplateName(NestedNameSpecifier NNS, bool TemplateKeyword,
TemplateName Template)
: Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) {
assert(UnderlyingTemplate.getKind() == TemplateName::Template ||
@@ -521,7 +529,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
public:
/// Return the nested name specifier that qualifies this name.
- NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
+ NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); }
/// Whether the template name was prefixed by the "template"
/// keyword.
@@ -534,9 +542,9 @@ public:
Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate);
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS,
bool TemplateKeyword, TemplateName TN) {
- ID.AddPointer(NNS);
+ NNS.Profile(ID);
ID.AddBoolean(TemplateKeyword);
ID.AddPointer(TN.getAsVoidPointer());
}
@@ -585,18 +593,18 @@ class DependentTemplateStorage {
///
/// The bit stored in this qualifier describes whether the \c Name field
/// was preceeded by a template keyword.
- llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier;
+ llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier;
/// The dependent template name.
IdentifierOrOverloadedOperator Name;
public:
- DependentTemplateStorage(NestedNameSpecifier *Qualifier,
+ DependentTemplateStorage(NestedNameSpecifier Qualifier,
IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword);
/// Return the nested name specifier that qualifies this name.
- NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
+ NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); }
IdentifierOrOverloadedOperator getName() const { return Name; }
@@ -609,10 +617,10 @@ public:
Profile(ID, getQualifier(), getName(), hasTemplateKeyword());
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+ static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS,
IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword) {
- ID.AddPointer(NNS);
+ NNS.Profile(ID);
ID.AddBoolean(HasTemplateKeyword);
Name.Profile(ID);
}
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 1917a8a..6d279511 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -211,7 +211,7 @@ public:
void dumpAccessSpecifier(AccessSpecifier AS);
void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C);
void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK);
- void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS);
+ void dumpNestedNameSpecifier(NestedNameSpecifier NNS);
void dumpConceptReference(const ConceptReference *R);
void dumpTemplateArgument(const TemplateArgument &TA);
void dumpBareTemplateName(TemplateName TN);
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 12dce30..48575c1 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -9,8284 +9,67 @@
/// \file
/// C Language Family Type Representation
///
-/// This file defines the clang::Type interface and subclasses, used to
-/// represent types for languages in the C family.
+/// This file defines some inline methods for clang::Type which depend on
+/// Decl.h, avoiding a circular dependency.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_TYPE_H
#define LLVM_CLANG_AST_TYPE_H
-#include "clang/AST/DependenceFlags.h"
-#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/Basic/AddressSpaces.h"
-#include "clang/Basic/AttrKinds.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/ExceptionSpecificationType.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/Linkage.h"
-#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/PointerAuthOptions.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/Specifiers.h"
-#include "clang/Basic/Visibility.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/STLForwardCompat.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/DXILABI.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/PointerLikeTypeTraits.h"
-#include "llvm/Support/TrailingObjects.h"
-#include "llvm/Support/type_traits.h"
-#include <bitset>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <optional>
-#include <string>
-#include <type_traits>
-#include <utility>
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TypeBase.h"
namespace clang {
-class BTFTypeTagAttr;
-class ExtQuals;
-class QualType;
-class ConceptDecl;
-class ValueDecl;
-class TagDecl;
-class TemplateParameterList;
-class Type;
-class Attr;
-
-enum {
- TypeAlignmentInBits = 4,
- TypeAlignment = 1 << TypeAlignmentInBits
-};
-
-namespace serialization {
- template <class T> class AbstractTypeReader;
- template <class T> class AbstractTypeWriter;
-}
-
-} // namespace clang
-
-namespace llvm {
-
- template <typename T>
- struct PointerLikeTypeTraits;
- template<>
- struct PointerLikeTypeTraits< ::clang::Type*> {
- static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
-
- static inline ::clang::Type *getFromVoidPointer(void *P) {
- return static_cast< ::clang::Type*>(P);
- }
-
- static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
- };
-
- template<>
- struct PointerLikeTypeTraits< ::clang::ExtQuals*> {
- static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
-
- static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
- return static_cast< ::clang::ExtQuals*>(P);
- }
-
- static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
- };
-
-} // namespace llvm
-
-namespace clang {
-
-class ASTContext;
-template <typename> class CanQual;
-class CXXRecordDecl;
-class DeclContext;
-class EnumDecl;
-class Expr;
-class ExtQualsTypeCommonBase;
-class FunctionDecl;
-class FunctionEffectsRef;
-class FunctionEffectKindSet;
-class FunctionEffectSet;
-class IdentifierInfo;
-class NamedDecl;
-class ObjCInterfaceDecl;
-class ObjCProtocolDecl;
-class ObjCTypeParamDecl;
-struct PrintingPolicy;
-class RecordDecl;
-class Stmt;
-class TagDecl;
-class TemplateArgument;
-class TemplateArgumentListInfo;
-class TemplateArgumentLoc;
-class TemplateTypeParmDecl;
-class TypedefNameDecl;
-class UnresolvedUsingTypenameDecl;
-class UsingShadowDecl;
-
-using CanQualType = CanQual<Type>;
-
-// Provide forward declarations for all of the *Type classes.
-#define TYPE(Class, Base) class Class##Type;
-#include "clang/AST/TypeNodes.inc"
-
-/// Pointer-authentication qualifiers.
-class PointerAuthQualifier {
- enum : uint32_t {
- EnabledShift = 0,
- EnabledBits = 1,
- EnabledMask = 1 << EnabledShift,
- AddressDiscriminatedShift = EnabledShift + EnabledBits,
- AddressDiscriminatedBits = 1,
- AddressDiscriminatedMask = 1 << AddressDiscriminatedShift,
- AuthenticationModeShift =
- AddressDiscriminatedShift + AddressDiscriminatedBits,
- AuthenticationModeBits = 2,
- AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1)
- << AuthenticationModeShift,
- IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits,
- IsaPointerBits = 1,
- IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift,
- AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits,
- AuthenticatesNullValuesBits = 1,
- AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
- << AuthenticatesNullValuesShift,
- KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
- KeyBits = 10,
- KeyMask = ((1 << KeyBits) - 1) << KeyShift,
- DiscriminatorShift = KeyShift + KeyBits,
- DiscriminatorBits = 16,
- DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift,
- };
-
- // bits: |0 |1 |2..3 |4 |
- // |Enabled|Address|AuthenticationMode|ISA pointer|
- // bits: |5 |6..15| 16...31 |
- // |AuthenticatesNull|Key |Discriminator|
- uint32_t Data = 0;
-
- // The following static assertions check that each of the 32 bits is present
- // exactly in one of the constants.
- static_assert((EnabledBits + AddressDiscriminatedBits +
- AuthenticationModeBits + IsaPointerBits +
- AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
- 32,
- "PointerAuthQualifier should be exactly 32 bits");
- static_assert((EnabledMask + AddressDiscriminatedMask +
- AuthenticationModeMask + IsaPointerMask +
- AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
- 0xFFFFFFFF,
- "All masks should cover the entire bits");
- static_assert((EnabledMask ^ AddressDiscriminatedMask ^
- AuthenticationModeMask ^ IsaPointerMask ^
- AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
- 0xFFFFFFFF,
- "All masks should cover the entire bits");
-
- PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated,
- unsigned ExtraDiscriminator,
- PointerAuthenticationMode AuthenticationMode,
- bool IsIsaPointer, bool AuthenticatesNullValues)
- : Data(EnabledMask |
- (IsAddressDiscriminated
- ? llvm::to_underlying(AddressDiscriminatedMask)
- : 0) |
- (Key << KeyShift) |
- (llvm::to_underlying(AuthenticationMode)
- << AuthenticationModeShift) |
- (ExtraDiscriminator << DiscriminatorShift) |
- (IsIsaPointer << IsaPointerShift) |
- (AuthenticatesNullValues << AuthenticatesNullValuesShift)) {
- assert(Key <= KeyNoneInternal);
- assert(ExtraDiscriminator <= MaxDiscriminator);
- assert((Data == 0) ==
- (getAuthenticationMode() == PointerAuthenticationMode::None));
- }
-
-public:
- enum {
- KeyNoneInternal = (1u << KeyBits) - 1,
-
- /// The maximum supported pointer-authentication key.
- MaxKey = KeyNoneInternal - 1,
-
- /// The maximum supported pointer-authentication discriminator.
- MaxDiscriminator = (1u << DiscriminatorBits) - 1
- };
-
-public:
- PointerAuthQualifier() = default;
-
- static PointerAuthQualifier
- Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator,
- PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer,
- bool AuthenticatesNullValues) {
- if (Key == PointerAuthKeyNone)
- Key = KeyNoneInternal;
- assert(Key <= KeyNoneInternal && "out-of-range key value");
- return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator,
- AuthenticationMode, IsIsaPointer,
- AuthenticatesNullValues);
- }
-
- bool isPresent() const {
- assert((Data == 0) ==
- (getAuthenticationMode() == PointerAuthenticationMode::None));
- return Data != 0;
- }
-
- explicit operator bool() const { return isPresent(); }
-
- unsigned getKey() const {
- assert(isPresent());
- return (Data & KeyMask) >> KeyShift;
- }
-
- bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; }
-
- bool isAddressDiscriminated() const {
- assert(isPresent());
- return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift;
- }
-
- unsigned getExtraDiscriminator() const {
- assert(isPresent());
- return (Data >> DiscriminatorShift);
- }
-
- PointerAuthenticationMode getAuthenticationMode() const {
- return PointerAuthenticationMode((Data & AuthenticationModeMask) >>
- AuthenticationModeShift);
- }
-
- bool isIsaPointer() const {
- assert(isPresent());
- return (Data & IsaPointerMask) >> IsaPointerShift;
- }
-
- bool authenticatesNullValues() const {
- assert(isPresent());
- return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift;
- }
-
- PointerAuthQualifier withoutKeyNone() const {
- return hasKeyNone() ? PointerAuthQualifier() : *this;
- }
-
- friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
- return Lhs.Data == Rhs.Data;
- }
- friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
- return Lhs.Data != Rhs.Data;
- }
-
- bool isEquivalent(PointerAuthQualifier Other) const {
- return withoutKeyNone() == Other.withoutKeyNone();
- }
-
- uint32_t getAsOpaqueValue() const { return Data; }
-
- // Deserialize pointer-auth qualifiers from an opaque representation.
- static PointerAuthQualifier fromOpaqueValue(uint32_t Opaque) {
- PointerAuthQualifier Result;
- Result.Data = Opaque;
- assert((Result.Data == 0) ==
- (Result.getAuthenticationMode() == PointerAuthenticationMode::None));
- return Result;
- }
-
- std::string getAsString() const;
- std::string getAsString(const PrintingPolicy &Policy) const;
-
- bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
- void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
-
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); }
-};
-
-/// The collection of all-type qualifiers we support.
-/// Clang supports five independent qualifiers:
-/// * C99: const, volatile, and restrict
-/// * MS: __unaligned
-/// * Embedded C (TR18037): address spaces
-/// * Objective C: the GC attributes (none, weak, or strong)
-class Qualifiers {
-public:
- Qualifiers() = default;
- enum TQ : uint64_t {
- // NOTE: These flags must be kept in sync with DeclSpec::TQ.
- Const = 0x1,
- Restrict = 0x2,
- Volatile = 0x4,
- CVRMask = Const | Volatile | Restrict
- };
-
- enum GC {
- GCNone = 0,
- Weak,
- Strong
- };
-
- enum ObjCLifetime {
- /// There is no lifetime qualification on this type.
- OCL_None,
-
- /// This object can be modified without requiring retains or
- /// releases.
- OCL_ExplicitNone,
-
- /// Assigning into this object requires the old value to be
- /// released and the new value to be retained. The timing of the
- /// release of the old value is inexact: it may be moved to
- /// immediately after the last known point where the value is
- /// live.
- OCL_Strong,
-
- /// Reading or writing from this object requires a barrier call.
- OCL_Weak,
-
- /// Assigning into this object requires a lifetime extension.
- OCL_Autoreleasing
- };
-
- enum : uint64_t {
- /// The maximum supported address space number.
- /// 23 bits should be enough for anyone.
- MaxAddressSpace = 0x7fffffu,
-
- /// The width of the "fast" qualifier mask.
- FastWidth = 3,
-
- /// The fast qualifier mask.
- FastMask = (1 << FastWidth) - 1
- };
-
- /// Returns the common set of qualifiers while removing them from
- /// the given sets.
- static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
- Qualifiers Q;
- PointerAuthQualifier LPtrAuth = L.getPointerAuth();
- if (LPtrAuth.isPresent() &&
- LPtrAuth.getKey() != PointerAuthQualifier::KeyNoneInternal &&
- LPtrAuth == R.getPointerAuth()) {
- Q.setPointerAuth(LPtrAuth);
- PointerAuthQualifier Empty;
- L.setPointerAuth(Empty);
- R.setPointerAuth(Empty);
- }
-
- // If both are only CVR-qualified, bit operations are sufficient.
- if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
- Q.Mask = L.Mask & R.Mask;
- L.Mask &= ~Q.Mask;
- R.Mask &= ~Q.Mask;
- return Q;
- }
-
- unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
- Q.addCVRQualifiers(CommonCRV);
- L.removeCVRQualifiers(CommonCRV);
- R.removeCVRQualifiers(CommonCRV);
-
- if (L.getObjCGCAttr() == R.getObjCGCAttr()) {
- Q.setObjCGCAttr(L.getObjCGCAttr());
- L.removeObjCGCAttr();
- R.removeObjCGCAttr();
- }
-
- if (L.getObjCLifetime() == R.getObjCLifetime()) {
- Q.setObjCLifetime(L.getObjCLifetime());
- L.removeObjCLifetime();
- R.removeObjCLifetime();
- }
-
- if (L.getAddressSpace() == R.getAddressSpace()) {
- Q.setAddressSpace(L.getAddressSpace());
- L.removeAddressSpace();
- R.removeAddressSpace();
- }
- return Q;
- }
-
- static Qualifiers fromFastMask(unsigned Mask) {
- Qualifiers Qs;
- Qs.addFastQualifiers(Mask);
- return Qs;
- }
-
- static Qualifiers fromCVRMask(unsigned CVR) {
- Qualifiers Qs;
- Qs.addCVRQualifiers(CVR);
- return Qs;
- }
-
- static Qualifiers fromCVRUMask(unsigned CVRU) {
- Qualifiers Qs;
- Qs.addCVRUQualifiers(CVRU);
- return Qs;
- }
-
- // Deserialize qualifiers from an opaque representation.
- static Qualifiers fromOpaqueValue(uint64_t opaque) {
- Qualifiers Qs;
- Qs.Mask = opaque;
- return Qs;
- }
-
- // Serialize these qualifiers into an opaque representation.
- uint64_t getAsOpaqueValue() const { return Mask; }
-
- bool hasConst() const { return Mask & Const; }
- bool hasOnlyConst() const { return Mask == Const; }
- void removeConst() { Mask &= ~Const; }
- void addConst() { Mask |= Const; }
- Qualifiers withConst() const {
- Qualifiers Qs = *this;
- Qs.addConst();
- return Qs;
- }
-
- bool hasVolatile() const { return Mask & Volatile; }
- bool hasOnlyVolatile() const { return Mask == Volatile; }
- void removeVolatile() { Mask &= ~Volatile; }
- void addVolatile() { Mask |= Volatile; }
- Qualifiers withVolatile() const {
- Qualifiers Qs = *this;
- Qs.addVolatile();
- return Qs;
- }
-
- bool hasRestrict() const { return Mask & Restrict; }
- bool hasOnlyRestrict() const { return Mask == Restrict; }
- void removeRestrict() { Mask &= ~Restrict; }
- void addRestrict() { Mask |= Restrict; }
- Qualifiers withRestrict() const {
- Qualifiers Qs = *this;
- Qs.addRestrict();
- return Qs;
- }
-
- bool hasCVRQualifiers() const { return getCVRQualifiers(); }
- unsigned getCVRQualifiers() const { return Mask & CVRMask; }
- unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); }
-
- void setCVRQualifiers(unsigned mask) {
- assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
- Mask = (Mask & ~CVRMask) | mask;
- }
- void removeCVRQualifiers(unsigned mask) {
- assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
- Mask &= ~static_cast<uint64_t>(mask);
- }
- void removeCVRQualifiers() {
- removeCVRQualifiers(CVRMask);
- }
- void addCVRQualifiers(unsigned mask) {
- assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
- Mask |= mask;
- }
- void addCVRUQualifiers(unsigned mask) {
- assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits");
- Mask |= mask;
- }
-
- bool hasUnaligned() const { return Mask & UMask; }
- void setUnaligned(bool flag) {
- Mask = (Mask & ~UMask) | (flag ? UMask : 0);
- }
- void removeUnaligned() { Mask &= ~UMask; }
- void addUnaligned() { Mask |= UMask; }
-
- bool hasObjCGCAttr() const { return Mask & GCAttrMask; }
- GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); }
- void setObjCGCAttr(GC type) {
- Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift);
- }
- void removeObjCGCAttr() { setObjCGCAttr(GCNone); }
- void addObjCGCAttr(GC type) {
- assert(type);
- setObjCGCAttr(type);
- }
- Qualifiers withoutObjCGCAttr() const {
- Qualifiers qs = *this;
- qs.removeObjCGCAttr();
- return qs;
- }
- Qualifiers withoutObjCLifetime() const {
- Qualifiers qs = *this;
- qs.removeObjCLifetime();
- return qs;
- }
- Qualifiers withoutAddressSpace() const {
- Qualifiers qs = *this;
- qs.removeAddressSpace();
- return qs;
- }
-
- bool hasObjCLifetime() const { return Mask & LifetimeMask; }
- ObjCLifetime getObjCLifetime() const {
- return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift);
- }
- void setObjCLifetime(ObjCLifetime type) {
- Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift);
- }
- void removeObjCLifetime() { setObjCLifetime(OCL_None); }
- void addObjCLifetime(ObjCLifetime type) {
- assert(type);
- assert(!hasObjCLifetime());
- Mask |= (type << LifetimeShift);
- }
-
- /// True if the lifetime is neither None or ExplicitNone.
- bool hasNonTrivialObjCLifetime() const {
- ObjCLifetime lifetime = getObjCLifetime();
- return (lifetime > OCL_ExplicitNone);
- }
-
- /// True if the lifetime is either strong or weak.
- bool hasStrongOrWeakObjCLifetime() const {
- ObjCLifetime lifetime = getObjCLifetime();
- return (lifetime == OCL_Strong || lifetime == OCL_Weak);
- }
-
- bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
- LangAS getAddressSpace() const {
- return static_cast<LangAS>((Mask & AddressSpaceMask) >> AddressSpaceShift);
- }
- bool hasTargetSpecificAddressSpace() const {
- return isTargetAddressSpace(getAddressSpace());
- }
- /// Get the address space attribute value to be printed by diagnostics.
- unsigned getAddressSpaceAttributePrintValue() const {
- auto Addr = getAddressSpace();
- // This function is not supposed to be used with language specific
- // address spaces. If that happens, the diagnostic message should consider
- // printing the QualType instead of the address space value.
- assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace());
- if (Addr != LangAS::Default)
- return toTargetAddressSpace(Addr);
- // TODO: The diagnostic messages where Addr may be 0 should be fixed
- // since it cannot differentiate the situation where 0 denotes the default
- // address space or user specified __attribute__((address_space(0))).
- return 0;
- }
- void setAddressSpace(LangAS space) {
- assert((unsigned)space <= MaxAddressSpace);
- Mask = (Mask & ~AddressSpaceMask)
- | (((uint32_t) space) << AddressSpaceShift);
- }
- void removeAddressSpace() { setAddressSpace(LangAS::Default); }
- void addAddressSpace(LangAS space) {
- assert(space != LangAS::Default);
- setAddressSpace(space);
- }
-
- bool hasPointerAuth() const { return Mask & PtrAuthMask; }
- PointerAuthQualifier getPointerAuth() const {
- return PointerAuthQualifier::fromOpaqueValue(Mask >> PtrAuthShift);
- }
- void setPointerAuth(PointerAuthQualifier Q) {
- Mask = (Mask & ~PtrAuthMask) |
- (uint64_t(Q.getAsOpaqueValue()) << PtrAuthShift);
- }
- void removePointerAuth() { Mask &= ~PtrAuthMask; }
- void addPointerAuth(PointerAuthQualifier Q) {
- assert(Q.isPresent());
- setPointerAuth(Q);
- }
-
- // Fast qualifiers are those that can be allocated directly
- // on a QualType object.
- bool hasFastQualifiers() const { return getFastQualifiers(); }
- unsigned getFastQualifiers() const { return Mask & FastMask; }
- void setFastQualifiers(unsigned mask) {
- assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
- Mask = (Mask & ~FastMask) | mask;
- }
- void removeFastQualifiers(unsigned mask) {
- assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
- Mask &= ~static_cast<uint64_t>(mask);
- }
- void removeFastQualifiers() {
- removeFastQualifiers(FastMask);
- }
- void addFastQualifiers(unsigned mask) {
- assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
- Mask |= mask;
- }
-
- /// Return true if the set contains any qualifiers which require an ExtQuals
- /// node to be allocated.
- bool hasNonFastQualifiers() const { return Mask & ~FastMask; }
- Qualifiers getNonFastQualifiers() const {
- Qualifiers Quals = *this;
- Quals.setFastQualifiers(0);
- return Quals;
- }
-
- /// Return true if the set contains any qualifiers.
- bool hasQualifiers() const { return Mask; }
- bool empty() const { return !Mask; }
-
- /// Add the qualifiers from the given set to this set.
- void addQualifiers(Qualifiers Q) {
- // If the other set doesn't have any non-boolean qualifiers, just
- // bit-or it in.
- if (!(Q.Mask & ~CVRMask))
- Mask |= Q.Mask;
- else {
- Mask |= (Q.Mask & CVRMask);
- if (Q.hasAddressSpace())
- addAddressSpace(Q.getAddressSpace());
- if (Q.hasObjCGCAttr())
- addObjCGCAttr(Q.getObjCGCAttr());
- if (Q.hasObjCLifetime())
- addObjCLifetime(Q.getObjCLifetime());
- if (Q.hasPointerAuth())
- addPointerAuth(Q.getPointerAuth());
- }
- }
-
- /// Remove the qualifiers from the given set from this set.
- void removeQualifiers(Qualifiers Q) {
- // If the other set doesn't have any non-boolean qualifiers, just
- // bit-and the inverse in.
- if (!(Q.Mask & ~CVRMask))
- Mask &= ~Q.Mask;
- else {
- Mask &= ~(Q.Mask & CVRMask);
- if (getObjCGCAttr() == Q.getObjCGCAttr())
- removeObjCGCAttr();
- if (getObjCLifetime() == Q.getObjCLifetime())
- removeObjCLifetime();
- if (getAddressSpace() == Q.getAddressSpace())
- removeAddressSpace();
- if (getPointerAuth() == Q.getPointerAuth())
- removePointerAuth();
- }
- }
-
- /// Add the qualifiers from the given set to this set, given that
- /// they don't conflict.
- void addConsistentQualifiers(Qualifiers qs) {
- assert(getAddressSpace() == qs.getAddressSpace() ||
- !hasAddressSpace() || !qs.hasAddressSpace());
- assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
- !hasObjCGCAttr() || !qs.hasObjCGCAttr());
- assert(getObjCLifetime() == qs.getObjCLifetime() ||
- !hasObjCLifetime() || !qs.hasObjCLifetime());
- assert(!hasPointerAuth() || !qs.hasPointerAuth() ||
- getPointerAuth() == qs.getPointerAuth());
- Mask |= qs.Mask;
- }
-
- /// Returns true if address space A is equal to or a superset of B.
- /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
- /// overlapping address spaces.
- /// CL1.1 or CL1.2:
- /// every address space is a superset of itself.
- /// CL2.0 adds:
- /// __generic is a superset of any address space except for __constant.
- static bool isAddressSpaceSupersetOf(LangAS A, LangAS B,
- const ASTContext &Ctx) {
- // Address spaces must match exactly.
- return A == B || isTargetAddressSpaceSupersetOf(A, B, Ctx);
- }
-
- static bool isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
- const ASTContext &Ctx);
-
- /// Returns true if the address space in these qualifiers is equal to or
- /// a superset of the address space in the argument qualifiers.
- bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const {
- return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(),
- Ctx);
- }
-
- /// Determines if these qualifiers compatibly include another set.
- /// Generally this answers the question of whether an object with the other
- /// qualifiers can be safely used as an object with these qualifiers.
- bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const {
- return isAddressSpaceSupersetOf(other, Ctx) &&
- // ObjC GC qualifiers can match, be added, or be removed, but can't
- // be changed.
- (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
- !other.hasObjCGCAttr()) &&
- // Pointer-auth qualifiers must match exactly.
- getPointerAuth() == other.getPointerAuth() &&
- // ObjC lifetime qualifiers must match exactly.
- getObjCLifetime() == other.getObjCLifetime() &&
- // CVR qualifiers may subset.
- (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) &&
- // U qualifier may superset.
- (!other.hasUnaligned() || hasUnaligned());
- }
-
- /// Determines if these qualifiers compatibly include another set of
- /// qualifiers from the narrow perspective of Objective-C ARC lifetime.
- ///
- /// One set of Objective-C lifetime qualifiers compatibly includes the other
- /// if the lifetime qualifiers match, or if both are non-__weak and the
- /// including set also contains the 'const' qualifier, or both are non-__weak
- /// and one is None (which can only happen in non-ARC modes).
- bool compatiblyIncludesObjCLifetime(Qualifiers other) const {
- if (getObjCLifetime() == other.getObjCLifetime())
- return true;
-
- if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak)
- return false;
-
- if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None)
- return true;
-
- return hasConst();
- }
-
- /// Determine whether this set of qualifiers is a strict superset of
- /// another set of qualifiers, not considering qualifier compatibility.
- bool isStrictSupersetOf(Qualifiers Other) const;
-
- bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
- bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
-
- explicit operator bool() const { return hasQualifiers(); }
-
- Qualifiers &operator+=(Qualifiers R) {
- addQualifiers(R);
- return *this;
- }
-
- // Union two qualifier sets. If an enumerated qualifier appears
- // in both sets, use the one from the right.
- friend Qualifiers operator+(Qualifiers L, Qualifiers R) {
- L += R;
- return L;
- }
-
- Qualifiers &operator-=(Qualifiers R) {
- removeQualifiers(R);
- return *this;
- }
-
- /// Compute the difference between two qualifier sets.
- friend Qualifiers operator-(Qualifiers L, Qualifiers R) {
- L -= R;
- return L;
- }
-
- std::string getAsString() const;
- std::string getAsString(const PrintingPolicy &Policy) const;
-
- static std::string getAddrSpaceAsString(LangAS AS);
-
- bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
- void print(raw_ostream &OS, const PrintingPolicy &Policy,
- bool appendSpaceIfNonEmpty = false) const;
-
- void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); }
-
-private:
- // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63|
- // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth |
- uint64_t Mask = 0;
- static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t),
- "PointerAuthQualifier must be 32 bits");
-
- static constexpr uint64_t PtrAuthShift = 32;
- static constexpr uint64_t PtrAuthMask = UINT64_C(0xffffffff) << PtrAuthShift;
-
- static constexpr uint64_t UMask = 0x8;
- static constexpr uint64_t UShift = 3;
- static constexpr uint64_t GCAttrMask = 0x30;
- static constexpr uint64_t GCAttrShift = 4;
- static constexpr uint64_t LifetimeMask = 0x1C0;
- static constexpr uint64_t LifetimeShift = 6;
- static constexpr uint64_t AddressSpaceMask =
- ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask);
- static constexpr uint64_t AddressSpaceShift = 9;
-};
-
-class QualifiersAndAtomic {
- Qualifiers Quals;
- bool HasAtomic;
-
-public:
- QualifiersAndAtomic() : HasAtomic(false) {}
- QualifiersAndAtomic(Qualifiers Quals, bool HasAtomic)
- : Quals(Quals), HasAtomic(HasAtomic) {}
-
- operator Qualifiers() const { return Quals; }
-
- bool hasVolatile() const { return Quals.hasVolatile(); }
- bool hasConst() const { return Quals.hasConst(); }
- bool hasRestrict() const { return Quals.hasRestrict(); }
- bool hasAtomic() const { return HasAtomic; }
-
- void addVolatile() { Quals.addVolatile(); }
- void addConst() { Quals.addConst(); }
- void addRestrict() { Quals.addRestrict(); }
- void addAtomic() { HasAtomic = true; }
-
- void removeVolatile() { Quals.removeVolatile(); }
- void removeConst() { Quals.removeConst(); }
- void removeRestrict() { Quals.removeRestrict(); }
- void removeAtomic() { HasAtomic = false; }
-
- QualifiersAndAtomic withVolatile() {
- return {Quals.withVolatile(), HasAtomic};
- }
- QualifiersAndAtomic withConst() { return {Quals.withConst(), HasAtomic}; }
- QualifiersAndAtomic withRestrict() {
- return {Quals.withRestrict(), HasAtomic};
- }
- QualifiersAndAtomic withAtomic() { return {Quals, true}; }
-
- QualifiersAndAtomic &operator+=(Qualifiers RHS) {
- Quals += RHS;
- return *this;
- }
-};
-
-/// A std::pair-like structure for storing a qualified type split
-/// into its local qualifiers and its locally-unqualified type.
-struct SplitQualType {
- /// The locally-unqualified type.
- const Type *Ty = nullptr;
-
- /// The local qualifiers.
- Qualifiers Quals;
-
- SplitQualType() = default;
- SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {}
-
- SplitQualType getSingleStepDesugaredType() const; // end of this file
-
- // Make std::tie work.
- std::pair<const Type *,Qualifiers> asPair() const {
- return std::pair<const Type *, Qualifiers>(Ty, Quals);
- }
-
- friend bool operator==(SplitQualType a, SplitQualType b) {
- return a.Ty == b.Ty && a.Quals == b.Quals;
- }
- friend bool operator!=(SplitQualType a, SplitQualType b) {
- return a.Ty != b.Ty || a.Quals != b.Quals;
- }
-};
-
-/// The kind of type we are substituting Objective-C type arguments into.
-///
-/// The kind of substitution affects the replacement of type parameters when
-/// no concrete type information is provided, e.g., when dealing with an
-/// unspecialized type.
-enum class ObjCSubstitutionContext {
- /// An ordinary type.
- Ordinary,
-
- /// The result type of a method or function.
- Result,
-
- /// The parameter type of a method or function.
- Parameter,
-
- /// The type of a property.
- Property,
-
- /// The superclass of a type.
- Superclass,
-};
-
-/// The kind of 'typeof' expression we're after.
-enum class TypeOfKind : uint8_t {
- Qualified,
- Unqualified,
-};
-
-/// A (possibly-)qualified type.
-///
-/// For efficiency, we don't store CV-qualified types as nodes on their
-/// own: instead each reference to a type stores the qualifiers. This
-/// greatly reduces the number of nodes we need to allocate for types (for
-/// example we only need one for 'int', 'const int', 'volatile int',
-/// 'const volatile int', etc).
-///
-/// As an added efficiency bonus, instead of making this a pair, we
-/// just store the two bits we care about in the low bits of the
-/// pointer. To handle the packing/unpacking, we make QualType be a
-/// simple wrapper class that acts like a smart pointer. A third bit
-/// indicates whether there are extended qualifiers present, in which
-/// case the pointer points to a special structure.
-class QualType {
- friend class QualifierCollector;
-
- // Thankfully, these are efficiently composable.
- llvm::PointerIntPair<llvm::PointerUnion<const Type *, const ExtQuals *>,
- Qualifiers::FastWidth> Value;
-
- const ExtQuals *getExtQualsUnsafe() const {
- return cast<const ExtQuals *>(Value.getPointer());
- }
-
- const Type *getTypePtrUnsafe() const {
- return cast<const Type *>(Value.getPointer());
- }
-
- const ExtQualsTypeCommonBase *getCommonPtr() const {
- assert(!isNull() && "Cannot retrieve a NULL type pointer");
- auto CommonPtrVal = reinterpret_cast<uintptr_t>(Value.getOpaqueValue());
- CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1);
- return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal);
- }
-
-public:
- QualType() = default;
- QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {}
- QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {}
-
- unsigned getLocalFastQualifiers() const { return Value.getInt(); }
- void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); }
-
- bool UseExcessPrecision(const ASTContext &Ctx);
-
- /// Retrieves a pointer to the underlying (unqualified) type.
- ///
- /// This function requires that the type not be NULL. If the type might be
- /// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
- const Type *getTypePtr() const;
-
- const Type *getTypePtrOrNull() const;
-
- /// Retrieves a pointer to the name of the base type.
- const IdentifierInfo *getBaseTypeIdentifier() const;
-
- /// Divides a QualType into its unqualified type and a set of local
- /// qualifiers.
- SplitQualType split() const;
-
- void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
-
- static QualType getFromOpaquePtr(const void *Ptr) {
- QualType T;
- T.Value.setFromOpaqueValue(const_cast<void*>(Ptr));
- return T;
- }
-
- const Type &operator*() const {
- return *getTypePtr();
- }
-
- const Type *operator->() const {
- return getTypePtr();
- }
-
- bool isCanonical() const;
- bool isCanonicalAsParam() const;
-
- /// Return true if this QualType doesn't point to a type yet.
- bool isNull() const {
- return Value.getPointer().isNull();
- }
-
- // Determines if a type can form `T&`.
- bool isReferenceable() const;
-
- /// Determine whether this particular QualType instance has the
- /// "const" qualifier set, without looking through typedefs that may have
- /// added "const" at a different level.
- bool isLocalConstQualified() const {
- return (getLocalFastQualifiers() & Qualifiers::Const);
- }
-
- /// Determine whether this type is const-qualified.
- bool isConstQualified() const;
-
- enum class NonConstantStorageReason {
- MutableField,
- NonConstNonReferenceType,
- NonTrivialCtor,
- NonTrivialDtor,
- };
- /// Determine whether instances of this type can be placed in immutable
- /// storage.
- /// If ExcludeCtor is true, the duration when the object's constructor runs
- /// will not be considered. The caller will need to verify that the object is
- /// not written to during its construction. ExcludeDtor works similarly.
- std::optional<NonConstantStorageReason>
- isNonConstantStorage(const ASTContext &Ctx, bool ExcludeCtor,
- bool ExcludeDtor);
-
- bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor,
- bool ExcludeDtor) {
- return !isNonConstantStorage(Ctx, ExcludeCtor, ExcludeDtor);
- }
-
- /// Determine whether this particular QualType instance has the
- /// "restrict" qualifier set, without looking through typedefs that may have
- /// added "restrict" at a different level.
- bool isLocalRestrictQualified() const {
- return (getLocalFastQualifiers() & Qualifiers::Restrict);
- }
-
- /// Determine whether this type is restrict-qualified.
- bool isRestrictQualified() const;
-
- /// Determine whether this particular QualType instance has the
- /// "volatile" qualifier set, without looking through typedefs that may have
- /// added "volatile" at a different level.
- bool isLocalVolatileQualified() const {
- return (getLocalFastQualifiers() & Qualifiers::Volatile);
- }
-
- /// Determine whether this type is volatile-qualified.
- bool isVolatileQualified() const;
-
- /// Determine whether this particular QualType instance has any
- /// qualifiers, without looking through any typedefs that might add
- /// qualifiers at a different level.
- bool hasLocalQualifiers() const {
- return getLocalFastQualifiers() || hasLocalNonFastQualifiers();
- }
-
- /// Determine whether this type has any qualifiers.
- bool hasQualifiers() const;
-
- /// Determine whether this particular QualType instance has any
- /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType
- /// instance.
- bool hasLocalNonFastQualifiers() const {
- return isa<const ExtQuals *>(Value.getPointer());
- }
-
- /// Retrieve the set of qualifiers local to this particular QualType
- /// instance, not including any qualifiers acquired through typedefs or
- /// other sugar.
- Qualifiers getLocalQualifiers() const;
-
- /// Retrieve the set of qualifiers applied to this type.
- Qualifiers getQualifiers() const;
-
- /// Retrieve the set of CVR (const-volatile-restrict) qualifiers
- /// local to this particular QualType instance, not including any qualifiers
- /// acquired through typedefs or other sugar.
- unsigned getLocalCVRQualifiers() const {
- return getLocalFastQualifiers();
- }
-
- /// Retrieve the set of CVR (const-volatile-restrict) qualifiers
- /// applied to this type.
- unsigned getCVRQualifiers() const;
-
- bool isConstant(const ASTContext& Ctx) const {
- return QualType::isConstant(*this, Ctx);
- }
-
- /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
- bool isPODType(const ASTContext &Context) const;
-
- /// Return true if this is a POD type according to the rules of the C++98
- /// standard, regardless of the current compilation's language.
- bool isCXX98PODType(const ASTContext &Context) const;
-
- /// Return true if this is a POD type according to the more relaxed rules
- /// of the C++11 standard, regardless of the current compilation's language.
- /// (C++0x [basic.types]p9). Note that, unlike
- /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account.
- bool isCXX11PODType(const ASTContext &Context) const;
-
- /// Return true if this is a trivial type per (C++0x [basic.types]p9)
- bool isTrivialType(const ASTContext &Context) const;
-
- /// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
- bool isTriviallyCopyableType(const ASTContext &Context) const;
-
- /// Return true if the type is safe to bitwise copy using memcpy/memmove.
- ///
- /// This is an extension in clang: bitwise cloneable types act as trivially
- /// copyable types, meaning their underlying bytes can be safely copied by
- /// memcpy or memmove. After the copy, the destination object has the same
- /// object representation.
- ///
- /// However, there are cases where it is not safe to copy:
- /// - When sanitizers, such as AddressSanitizer, add padding with poison,
- /// which can cause issues if those poisoned padding bits are accessed.
- /// - Types with Objective-C lifetimes, where specific runtime
- /// semantics may not be preserved during a bitwise copy.
- bool isBitwiseCloneableType(const ASTContext &Context) const;
-
- /// Return true if this is a trivially copyable type
- bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;
-
- /// Returns true if it is a class and it might be dynamic.
- bool mayBeDynamicClass() const;
-
- /// Returns true if it is not a class or if the class might not be dynamic.
- bool mayBeNotDynamicClass() const;
-
- /// Returns true if it is a WebAssembly Reference Type.
- bool isWebAssemblyReferenceType() const;
-
- /// Returns true if it is a WebAssembly Externref Type.
- bool isWebAssemblyExternrefType() const;
-
- /// Returns true if it is a WebAssembly Funcref Type.
- bool isWebAssemblyFuncrefType() const;
-
- // Don't promise in the API that anything besides 'const' can be
- // easily added.
-
- /// Add the `const` type qualifier to this QualType.
- void addConst() {
- addFastQualifiers(Qualifiers::Const);
- }
- QualType withConst() const {
- return withFastQualifiers(Qualifiers::Const);
- }
-
- /// Add the `volatile` type qualifier to this QualType.
- void addVolatile() {
- addFastQualifiers(Qualifiers::Volatile);
- }
- QualType withVolatile() const {
- return withFastQualifiers(Qualifiers::Volatile);
- }
-
- /// Add the `restrict` qualifier to this QualType.
- void addRestrict() {
- addFastQualifiers(Qualifiers::Restrict);
- }
- QualType withRestrict() const {
- return withFastQualifiers(Qualifiers::Restrict);
- }
-
- QualType withCVRQualifiers(unsigned CVR) const {
- return withFastQualifiers(CVR);
- }
-
- void addFastQualifiers(unsigned TQs) {
- assert(!(TQs & ~Qualifiers::FastMask)
- && "non-fast qualifier bits set in mask!");
- Value.setInt(Value.getInt() | TQs);
- }
-
- void removeLocalConst();
- void removeLocalVolatile();
- void removeLocalRestrict();
-
- void removeLocalFastQualifiers() { Value.setInt(0); }
- void removeLocalFastQualifiers(unsigned Mask) {
- assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers");
- Value.setInt(Value.getInt() & ~Mask);
- }
-
- // Creates a type with the given qualifiers in addition to any
- // qualifiers already on this type.
- QualType withFastQualifiers(unsigned TQs) const {
- QualType T = *this;
- T.addFastQualifiers(TQs);
- return T;
- }
-
- // Creates a type with exactly the given fast qualifiers, removing
- // any existing fast qualifiers.
- QualType withExactLocalFastQualifiers(unsigned TQs) const {
- return withoutLocalFastQualifiers().withFastQualifiers(TQs);
- }
-
- // Removes fast qualifiers, but leaves any extended qualifiers in place.
- QualType withoutLocalFastQualifiers() const {
- QualType T = *this;
- T.removeLocalFastQualifiers();
- return T;
- }
-
- QualType getCanonicalType() const;
-
- /// Return this type with all of the instance-specific qualifiers
- /// removed, but without removing any qualifiers that may have been applied
- /// through typedefs.
- QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); }
-
- /// Retrieve the unqualified variant of the given type,
- /// removing as little sugar as possible.
- ///
- /// This routine looks through various kinds of sugar to find the
- /// least-desugared type that is unqualified. For example, given:
- ///
- /// \code
- /// typedef int Integer;
- /// typedef const Integer CInteger;
- /// typedef CInteger DifferenceType;
- /// \endcode
- ///
- /// Executing \c getUnqualifiedType() on the type \c DifferenceType will
- /// desugar until we hit the type \c Integer, which has no qualifiers on it.
- ///
- /// The resulting type might still be qualified if it's sugar for an array
- /// type. To strip qualifiers even from within a sugared array type, use
- /// ASTContext::getUnqualifiedArrayType.
- ///
- /// Note: In C, the _Atomic qualifier is special (see C23 6.2.5p32 for
- /// details), and it is not stripped by this function. Use
- /// getAtomicUnqualifiedType() to strip qualifiers including _Atomic.
- inline QualType getUnqualifiedType() const;
-
- /// Retrieve the unqualified variant of the given type, removing as little
- /// sugar as possible.
- ///
- /// Like getUnqualifiedType(), but also returns the set of
- /// qualifiers that were built up.
- ///
- /// The resulting type might still be qualified if it's sugar for an array
- /// type. To strip qualifiers even from within a sugared array type, use
- /// ASTContext::getUnqualifiedArrayType.
- inline SplitQualType getSplitUnqualifiedType() const;
-
- /// Determine whether this type is more qualified than the other
- /// given type, requiring exact equality for non-CVR qualifiers.
- bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const;
-
- /// Determine whether this type is at least as qualified as the other
- /// given type, requiring exact equality for non-CVR qualifiers.
- bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const;
-
- QualType getNonReferenceType() const;
-
- /// Determine the type of a (typically non-lvalue) expression with the
- /// specified result type.
- ///
- /// This routine should be used for expressions for which the return type is
- /// explicitly specified (e.g., in a cast or call) and isn't necessarily
- /// an lvalue. It removes a top-level reference (since there are no
- /// expressions of reference type) and deletes top-level cvr-qualifiers
- /// from non-class types (in C++) or all types (in C).
- QualType getNonLValueExprType(const ASTContext &Context) const;
-
- /// Remove an outer pack expansion type (if any) from this type. Used as part
- /// of converting the type of a declaration to the type of an expression that
- /// references that expression. It's meaningless for an expression to have a
- /// pack expansion type.
- QualType getNonPackExpansionType() const;
-
- /// Return the specified type with any "sugar" removed from
- /// the type. This takes off typedefs, typeof's etc. If the outer level of
- /// the type is already concrete, it returns it unmodified. This is similar
- /// to getting the canonical type, but it doesn't remove *all* typedefs. For
- /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
- /// concrete.
- ///
- /// Qualifiers are left in place.
- QualType getDesugaredType(const ASTContext &Context) const {
- return getDesugaredType(*this, Context);
- }
-
- SplitQualType getSplitDesugaredType() const {
- return getSplitDesugaredType(*this);
- }
-
- /// Return the specified type with one level of "sugar" removed from
- /// the type.
- ///
- /// This routine takes off the first typedef, typeof, etc. If the outer level
- /// of the type is already concrete, it returns it unmodified.
- QualType getSingleStepDesugaredType(const ASTContext &Context) const {
- return getSingleStepDesugaredTypeImpl(*this, Context);
- }
-
- /// Returns the specified type after dropping any
- /// outer-level parentheses.
- QualType IgnoreParens() const {
- if (isa<ParenType>(*this))
- return QualType::IgnoreParens(*this);
- return *this;
- }
-
- /// Indicate whether the specified types and qualifiers are identical.
- friend bool operator==(const QualType &LHS, const QualType &RHS) {
- return LHS.Value == RHS.Value;
- }
- friend bool operator!=(const QualType &LHS, const QualType &RHS) {
- return LHS.Value != RHS.Value;
- }
- friend bool operator<(const QualType &LHS, const QualType &RHS) {
- return LHS.Value < RHS.Value;
- }
-
- static std::string getAsString(SplitQualType split,
- const PrintingPolicy &Policy) {
- return getAsString(split.Ty, split.Quals, Policy);
- }
- static std::string getAsString(const Type *ty, Qualifiers qs,
- const PrintingPolicy &Policy);
-
- std::string getAsString() const;
- std::string getAsString(const PrintingPolicy &Policy) const;
-
- void print(raw_ostream &OS, const PrintingPolicy &Policy,
- const Twine &PlaceHolder = Twine(),
- unsigned Indentation = 0) const;
-
- static void print(SplitQualType split, raw_ostream &OS,
- const PrintingPolicy &policy, const Twine &PlaceHolder,
- unsigned Indentation = 0) {
- return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation);
- }
-
- static void print(const Type *ty, Qualifiers qs,
- raw_ostream &OS, const PrintingPolicy &policy,
- const Twine &PlaceHolder,
- unsigned Indentation = 0);
-
- void getAsStringInternal(std::string &Str,
- const PrintingPolicy &Policy) const;
-
- static void getAsStringInternal(SplitQualType split, std::string &out,
- const PrintingPolicy &policy) {
- return getAsStringInternal(split.Ty, split.Quals, out, policy);
- }
-
- static void getAsStringInternal(const Type *ty, Qualifiers qs,
- std::string &out,
- const PrintingPolicy &policy);
-
- class StreamedQualTypeHelper {
- const QualType &T;
- const PrintingPolicy &Policy;
- const Twine &PlaceHolder;
- unsigned Indentation;
-
- public:
- StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy,
- const Twine &PlaceHolder, unsigned Indentation)
- : T(T), Policy(Policy), PlaceHolder(PlaceHolder),
- Indentation(Indentation) {}
-
- friend raw_ostream &operator<<(raw_ostream &OS,
- const StreamedQualTypeHelper &SQT) {
- SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation);
- return OS;
- }
- };
-
- StreamedQualTypeHelper stream(const PrintingPolicy &Policy,
- const Twine &PlaceHolder = Twine(),
- unsigned Indentation = 0) const {
- return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation);
- }
-
- void dump(const char *s) const;
- void dump() const;
- void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(getAsOpaquePtr());
- }
-
- /// Check if this type has any address space qualifier.
- inline bool hasAddressSpace() const;
-
- /// Return the address space of this type.
- inline LangAS getAddressSpace() const;
-
- /// Returns true if address space qualifiers overlap with T address space
- /// qualifiers.
- /// OpenCL C defines conversion rules for pointers to different address spaces
- /// and notion of overlapping address spaces.
- /// CL1.1 or CL1.2:
- /// address spaces overlap iff they are they same.
- /// OpenCL C v2.0 s6.5.5 adds:
- /// __generic overlaps with any address space except for __constant.
- bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const {
- Qualifiers Q = getQualifiers();
- Qualifiers TQ = T.getQualifiers();
- // Address spaces overlap if at least one of them is a superset of another
- return Q.isAddressSpaceSupersetOf(TQ, Ctx) ||
- TQ.isAddressSpaceSupersetOf(Q, Ctx);
- }
-
- /// Returns gc attribute of this type.
- inline Qualifiers::GC getObjCGCAttr() const;
-
- /// true when Type is objc's weak.
- bool isObjCGCWeak() const {
- return getObjCGCAttr() == Qualifiers::Weak;
- }
-
- /// true when Type is objc's strong.
- bool isObjCGCStrong() const {
- return getObjCGCAttr() == Qualifiers::Strong;
- }
-
- /// Returns lifetime attribute of this type.
- Qualifiers::ObjCLifetime getObjCLifetime() const {
- return getQualifiers().getObjCLifetime();
- }
-
- bool hasNonTrivialObjCLifetime() const {
- return getQualifiers().hasNonTrivialObjCLifetime();
- }
-
- bool hasStrongOrWeakObjCLifetime() const {
- return getQualifiers().hasStrongOrWeakObjCLifetime();
- }
-
- // true when Type is objc's weak and weak is enabled but ARC isn't.
- bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
-
- PointerAuthQualifier getPointerAuth() const {
- return getQualifiers().getPointerAuth();
- }
-
- bool hasAddressDiscriminatedPointerAuth() const {
- if (PointerAuthQualifier PtrAuth = getPointerAuth())
- return PtrAuth.isAddressDiscriminated();
- return false;
- }
-
- enum PrimitiveDefaultInitializeKind {
- /// The type does not fall into any of the following categories. Note that
- /// this case is zero-valued so that values of this enum can be used as a
- /// boolean condition for non-triviality.
- PDIK_Trivial,
-
- /// The type is an Objective-C retainable pointer type that is qualified
- /// with the ARC __strong qualifier.
- PDIK_ARCStrong,
-
- /// The type is an Objective-C retainable pointer type that is qualified
- /// with the ARC __weak qualifier.
- PDIK_ARCWeak,
-
- /// The type is a struct containing a field whose type is not PCK_Trivial.
- PDIK_Struct
- };
-
- /// Functions to query basic properties of non-trivial C struct types.
-
- /// Check if this is a non-trivial type that would cause a C struct
- /// transitively containing this type to be non-trivial to default initialize
- /// and return the kind.
- PrimitiveDefaultInitializeKind
- isNonTrivialToPrimitiveDefaultInitialize() const;
-
- enum PrimitiveCopyKind {
- /// The type does not fall into any of the following categories. Note that
- /// this case is zero-valued so that values of this enum can be used as a
- /// boolean condition for non-triviality.
- PCK_Trivial,
-
- /// The type would be trivial except that it is volatile-qualified. Types
- /// that fall into one of the other non-trivial cases may additionally be
- /// volatile-qualified.
- PCK_VolatileTrivial,
-
- /// The type is an Objective-C retainable pointer type that is qualified
- /// with the ARC __strong qualifier.
- PCK_ARCStrong,
-
- /// The type is an Objective-C retainable pointer type that is qualified
- /// with the ARC __weak qualifier.
- PCK_ARCWeak,
-
- /// The type is an address-discriminated signed pointer type.
- PCK_PtrAuth,
-
- /// The type is a struct containing a field whose type is neither
- /// PCK_Trivial nor PCK_VolatileTrivial.
- /// Note that a C++ struct type does not necessarily match this; C++ copying
- /// semantics are too complex to express here, in part because they depend
- /// on the exact constructor or assignment operator that is chosen by
- /// overload resolution to do the copy.
- PCK_Struct
- };
-
- /// Check if this is a non-trivial type that would cause a C struct
- /// transitively containing this type to be non-trivial to copy and return the
- /// kind.
- PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const;
-
- /// Check if this is a non-trivial type that would cause a C struct
- /// transitively containing this type to be non-trivial to destructively
- /// move and return the kind. Destructive move in this context is a C++-style
- /// move in which the source object is placed in a valid but unspecified state
- /// after it is moved, as opposed to a truly destructive move in which the
- /// source object is placed in an uninitialized state.
- PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const;
-
- enum DestructionKind {
- DK_none,
- DK_cxx_destructor,
- DK_objc_strong_lifetime,
- DK_objc_weak_lifetime,
- DK_nontrivial_c_struct
- };
-
- /// Returns a nonzero value if objects of this type require
- /// non-trivial work to clean up after. Non-zero because it's
- /// conceivable that qualifiers (objc_gc(weak)?) could make
- /// something require destruction.
- DestructionKind isDestructedType() const {
- return isDestructedTypeImpl(*this);
- }
-
- /// Check if this is or contains a C union that is non-trivial to
- /// default-initialize, which is a union that has a member that is non-trivial
- /// to default-initialize. If this returns true,
- /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct.
- bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const;
-
- /// Check if this is or contains a C union that is non-trivial to destruct,
- /// which is a union that has a member that is non-trivial to destruct. If
- /// this returns true, isDestructedType returns DK_nontrivial_c_struct.
- bool hasNonTrivialToPrimitiveDestructCUnion() const;
-
- /// Check if this is or contains a C union that is non-trivial to copy, which
- /// is a union that has a member that is non-trivial to copy. If this returns
- /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct.
- bool hasNonTrivialToPrimitiveCopyCUnion() const;
-
- /// Determine whether expressions of the given type are forbidden
- /// from being lvalues in C.
- ///
- /// The expression types that are forbidden to be lvalues are:
- /// - 'void', but not qualified void
- /// - function types
- ///
- /// The exact rule here is C99 6.3.2.1:
- /// An lvalue is an expression with an object type or an incomplete
- /// type other than void.
- bool isCForbiddenLValueType() const;
-
- /// Substitute type arguments for the Objective-C type parameters used in the
- /// subject type.
- ///
- /// \param ctx ASTContext in which the type exists.
- ///
- /// \param typeArgs The type arguments that will be substituted for the
- /// Objective-C type parameters in the subject type, which are generally
- /// computed via \c Type::getObjCSubstitutions. If empty, the type
- /// parameters will be replaced with their bounds or id/Class, as appropriate
- /// for the context.
- ///
- /// \param context The context in which the subject type was written.
- ///
- /// \returns the resulting type.
- QualType substObjCTypeArgs(ASTContext &ctx,
- ArrayRef<QualType> typeArgs,
- ObjCSubstitutionContext context) const;
-
- /// Substitute type arguments from an object type for the Objective-C type
- /// parameters used in the subject type.
- ///
- /// This operation combines the computation of type arguments for
- /// substitution (\c Type::getObjCSubstitutions) with the actual process of
- /// substitution (\c QualType::substObjCTypeArgs) for the convenience of
- /// callers that need to perform a single substitution in isolation.
- ///
- /// \param objectType The type of the object whose member type we're
- /// substituting into. For example, this might be the receiver of a message
- /// or the base of a property access.
- ///
- /// \param dc The declaration context from which the subject type was
- /// retrieved, which indicates (for example) which type parameters should
- /// be substituted.
- ///
- /// \param context The context in which the subject type was written.
- ///
- /// \returns the subject type after replacing all of the Objective-C type
- /// parameters with their corresponding arguments.
- QualType substObjCMemberType(QualType objectType,
- const DeclContext *dc,
- ObjCSubstitutionContext context) const;
-
- /// Strip Objective-C "__kindof" types from the given type.
- QualType stripObjCKindOfType(const ASTContext &ctx) const;
-
- /// Remove all qualifiers including _Atomic.
- ///
- /// Like getUnqualifiedType(), the type may still be qualified if it is a
- /// sugared array type. To strip qualifiers even from within a sugared array
- /// type, use in conjunction with ASTContext::getUnqualifiedArrayType.
- QualType getAtomicUnqualifiedType() const;
-
-private:
- // These methods are implemented in a separate translation unit;
- // "static"-ize them to avoid creating temporary QualTypes in the
- // caller.
- static bool isConstant(QualType T, const ASTContext& Ctx);
- static QualType getDesugaredType(QualType T, const ASTContext &Context);
- static SplitQualType getSplitDesugaredType(QualType T);
- static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
- static QualType getSingleStepDesugaredTypeImpl(QualType type,
- const ASTContext &C);
- static QualType IgnoreParens(QualType T);
- static DestructionKind isDestructedTypeImpl(QualType type);
-
- /// Check if \param RD is or contains a non-trivial C union.
- static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD);
- static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD);
- static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD);
-};
-
-raw_ostream &operator<<(raw_ostream &OS, QualType QT);
-
-} // namespace clang
-
-namespace llvm {
-
-/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
-/// to a specific Type class.
-template<> struct simplify_type< ::clang::QualType> {
- using SimpleType = const ::clang::Type *;
-
- static SimpleType getSimplifiedValue(::clang::QualType Val) {
- return Val.getTypePtr();
- }
-};
-
-// Teach SmallPtrSet that QualType is "basically a pointer".
-template<>
-struct PointerLikeTypeTraits<clang::QualType> {
- static inline void *getAsVoidPointer(clang::QualType P) {
- return P.getAsOpaquePtr();
- }
-
- static inline clang::QualType getFromVoidPointer(void *P) {
- return clang::QualType::getFromOpaquePtr(P);
- }
-
- // Various qualifiers go in low bits.
- static constexpr int NumLowBitsAvailable = 0;
-};
-
-} // namespace llvm
-
-namespace clang {
-
-/// Base class that is common to both the \c ExtQuals and \c Type
-/// classes, which allows \c QualType to access the common fields between the
-/// two.
-class ExtQualsTypeCommonBase {
- friend class ExtQuals;
- friend class QualType;
- friend class Type;
- friend class ASTReader;
-
- /// The "base" type of an extended qualifiers type (\c ExtQuals) or
- /// a self-referential pointer (for \c Type).
- ///
- /// This pointer allows an efficient mapping from a QualType to its
- /// underlying type pointer.
- const Type *const BaseType;
-
- /// The canonical type of this type. A QualType.
- QualType CanonicalType;
-
- ExtQualsTypeCommonBase(const Type *baseType, QualType canon)
- : BaseType(baseType), CanonicalType(canon) {}
-};
-
-/// We can encode up to four bits in the low bits of a
-/// type pointer, but there are many more type qualifiers that we want
-/// to be able to apply to an arbitrary type. Therefore we have this
-/// struct, intended to be heap-allocated and used by QualType to
-/// store qualifiers.
-///
-/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers
-/// in three low bits on the QualType pointer; a fourth bit records whether
-/// the pointer is an ExtQuals node. The extended qualifiers (address spaces,
-/// Objective-C GC attributes) are much more rare.
-class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase,
- public llvm::FoldingSetNode {
- // NOTE: changing the fast qualifiers should be straightforward as
- // long as you don't make 'const' non-fast.
- // 1. Qualifiers:
- // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ).
- // Fast qualifiers must occupy the low-order bits.
- // b) Update Qualifiers::FastWidth and FastMask.
- // 2. QualType:
- // a) Update is{Volatile,Restrict}Qualified(), defined inline.
- // b) Update remove{Volatile,Restrict}, defined near the end of
- // this header.
- // 3. ASTContext:
- // a) Update get{Volatile,Restrict}Type.
-
- /// The immutable set of qualifiers applied by this node. Always contains
- /// extended qualifiers.
- Qualifiers Quals;
-
- ExtQuals *this_() { return this; }
-
-public:
- ExtQuals(const Type *baseType, QualType canon, Qualifiers quals)
- : ExtQualsTypeCommonBase(baseType,
- canon.isNull() ? QualType(this_(), 0) : canon),
- Quals(quals) {
- assert(Quals.hasNonFastQualifiers()
- && "ExtQuals created with no fast qualifiers");
- assert(!Quals.hasFastQualifiers()
- && "ExtQuals created with fast qualifiers");
- }
-
- Qualifiers getQualifiers() const { return Quals; }
-
- bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
- Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
-
- bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); }
- Qualifiers::ObjCLifetime getObjCLifetime() const {
- return Quals.getObjCLifetime();
- }
-
- bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
- LangAS getAddressSpace() const { return Quals.getAddressSpace(); }
-
- const Type *getBaseType() const { return BaseType; }
-
-public:
- void Profile(llvm::FoldingSetNodeID &ID) const {
- Profile(ID, getBaseType(), Quals);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID,
- const Type *BaseType,
- Qualifiers Quals) {
- assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!");
- ID.AddPointer(BaseType);
- Quals.Profile(ID);
- }
-};
-
-/// The kind of C++11 ref-qualifier associated with a function type.
-/// This determines whether a member function's "this" object can be an
-/// lvalue, rvalue, or neither.
-enum RefQualifierKind {
- /// No ref-qualifier was provided.
- RQ_None = 0,
-
- /// An lvalue ref-qualifier was provided (\c &).
- RQ_LValue,
-
- /// An rvalue ref-qualifier was provided (\c &&).
- RQ_RValue
-};
-
-/// Which keyword(s) were used to create an AutoType.
-enum class AutoTypeKeyword {
- /// auto
- Auto,
-
- /// decltype(auto)
- DecltypeAuto,
-
- /// __auto_type (GNU extension)
- GNUAutoType
-};
-
-enum class ArraySizeModifier;
-enum class ElaboratedTypeKeyword;
-enum class VectorKind;
-
-/// The base class of the type hierarchy.
-///
-/// A central concept with types is that each type always has a canonical
-/// type. A canonical type is the type with any typedef names stripped out
-/// of it or the types it references. For example, consider:
-///
-/// typedef int foo;
-/// typedef foo* bar;
-/// 'int *' 'foo *' 'bar'
-///
-/// There will be a Type object created for 'int'. Since int is canonical, its
-/// CanonicalType pointer points to itself. There is also a Type for 'foo' (a
-/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next
-/// there is a PointerType that represents 'int*', which, like 'int', is
-/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical
-/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type
-/// is also 'int*'.
-///
-/// Non-canonical types are useful for emitting diagnostics, without losing
-/// information about typedefs being used. Canonical types are useful for type
-/// comparisons (they allow by-pointer equality tests) and useful for reasoning
-/// about whether something has a particular form (e.g. is a function type),
-/// because they implicitly, recursively, strip all typedefs out of a type.
-///
-/// Types, once created, are immutable.
-///
-class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
-public:
- enum TypeClass {
-#define TYPE(Class, Base) Class,
-#define LAST_TYPE(Class) TypeLast = Class
-#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.inc"
- };
-
-private:
- /// Bitfields required by the Type class.
- class TypeBitfields {
- friend class Type;
- template <class T> friend class TypePropertyCache;
-
- /// TypeClass bitfield - Enum that specifies what subclass this belongs to.
- LLVM_PREFERRED_TYPE(TypeClass)
- unsigned TC : 8;
-
- /// Store information on the type dependency.
- LLVM_PREFERRED_TYPE(TypeDependence)
- unsigned Dependence : llvm::BitWidth<TypeDependence>;
-
- /// True if the cache (i.e. the bitfields here starting with
- /// 'Cache') is valid.
- LLVM_PREFERRED_TYPE(bool)
- mutable unsigned CacheValid : 1;
-
- /// Linkage of this type.
- LLVM_PREFERRED_TYPE(Linkage)
- mutable unsigned CachedLinkage : 3;
-
- /// Whether this type involves and local or unnamed types.
- LLVM_PREFERRED_TYPE(bool)
- mutable unsigned CachedLocalOrUnnamed : 1;
-
- /// Whether this type comes from an AST file.
- LLVM_PREFERRED_TYPE(bool)
- mutable unsigned FromAST : 1;
-
- bool isCacheValid() const {
- return CacheValid;
- }
-
- Linkage getLinkage() const {
- assert(isCacheValid() && "getting linkage from invalid cache");
- return static_cast<Linkage>(CachedLinkage);
- }
-
- bool hasLocalOrUnnamedType() const {
- assert(isCacheValid() && "getting linkage from invalid cache");
- return CachedLocalOrUnnamed;
- }
- };
- enum { NumTypeBits = 8 + llvm::BitWidth<TypeDependence> + 6 };
-
-protected:
- // These classes allow subclasses to somewhat cleanly pack bitfields
- // into Type.
-
- class ArrayTypeBitfields {
- friend class ArrayType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// CVR qualifiers from declarations like
- /// 'int X[static restrict 4]'. For function parameters only.
- LLVM_PREFERRED_TYPE(Qualifiers)
- unsigned IndexTypeQuals : 3;
-
- /// Storage class qualifiers from declarations like
- /// 'int X[static restrict 4]'. For function parameters only.
- LLVM_PREFERRED_TYPE(ArraySizeModifier)
- unsigned SizeModifier : 3;
- };
- enum { NumArrayTypeBits = NumTypeBits + 6 };
-
- class ConstantArrayTypeBitfields {
- friend class ConstantArrayType;
-
- LLVM_PREFERRED_TYPE(ArrayTypeBitfields)
- unsigned : NumArrayTypeBits;
-
- /// Whether we have a stored size expression.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasExternalSize : 1;
-
- LLVM_PREFERRED_TYPE(unsigned)
- unsigned SizeWidth : 5;
- };
-
- class BuiltinTypeBitfields {
- friend class BuiltinType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The kind (BuiltinType::Kind) of builtin type this is.
- static constexpr unsigned NumOfBuiltinTypeBits = 9;
- unsigned Kind : NumOfBuiltinTypeBits;
- };
-
-public:
- static constexpr int FunctionTypeNumParamsWidth = 16;
- static constexpr int FunctionTypeNumParamsLimit = (1 << 16) - 1;
-
-protected:
- /// FunctionTypeBitfields store various bits belonging to FunctionProtoType.
- /// Only common bits are stored here. Additional uncommon bits are stored
- /// in a trailing object after FunctionProtoType.
- class FunctionTypeBitfields {
- friend class FunctionProtoType;
- friend class FunctionType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The ref-qualifier associated with a \c FunctionProtoType.
- ///
- /// This is a value of type \c RefQualifierKind.
- LLVM_PREFERRED_TYPE(RefQualifierKind)
- unsigned RefQualifier : 2;
-
- /// Used only by FunctionProtoType, put here to pack with the
- /// other bitfields.
- /// The qualifiers are part of FunctionProtoType because...
- ///
- /// C++ 8.3.5p4: The return type, the parameter type list and the
- /// cv-qualifier-seq, [...], are part of the function type.
- LLVM_PREFERRED_TYPE(Qualifiers)
- unsigned FastTypeQuals : Qualifiers::FastWidth;
- /// Whether this function has extended Qualifiers.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasExtQuals : 1;
-
- /// The type of exception specification this function has.
- LLVM_PREFERRED_TYPE(ExceptionSpecificationType)
- unsigned ExceptionSpecType : 4;
-
- /// Whether this function has extended parameter information.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasExtParameterInfos : 1;
-
- /// Whether this function has extra bitfields for the prototype.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasExtraBitfields : 1;
-
- /// Whether the function is variadic.
- LLVM_PREFERRED_TYPE(bool)
- unsigned Variadic : 1;
-
- /// Whether this function has a trailing return type.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasTrailingReturn : 1;
-
- /// Whether this function has is a cfi unchecked callee.
- LLVM_PREFERRED_TYPE(bool)
- unsigned CFIUncheckedCallee : 1;
-
- /// Extra information which affects how the function is called, like
- /// regparm and the calling convention.
- LLVM_PREFERRED_TYPE(CallingConv)
- unsigned ExtInfo : 14;
-
- /// The number of parameters this function has, not counting '...'.
- /// According to [implimits] 8 bits should be enough here but this is
- /// somewhat easy to exceed with metaprogramming and so we would like to
- /// keep NumParams as wide as reasonably possible.
- unsigned NumParams : FunctionTypeNumParamsWidth;
- };
-
- class ObjCObjectTypeBitfields {
- friend class ObjCObjectType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The number of type arguments stored directly on this object type.
- unsigned NumTypeArgs : 7;
-
- /// The number of protocols stored directly on this object type.
- unsigned NumProtocols : 6;
-
- /// Whether this is a "kindof" type.
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsKindOf : 1;
- };
-
- class ReferenceTypeBitfields {
- friend class ReferenceType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// True if the type was originally spelled with an lvalue sigil.
- /// This is never true of rvalue references but can also be false
- /// on lvalue references because of C++0x [dcl.typedef]p9,
- /// as follows:
- ///
- /// typedef int &ref; // lvalue, spelled lvalue
- /// typedef int &&rvref; // rvalue
- /// ref &a; // lvalue, inner ref, spelled lvalue
- /// ref &&a; // lvalue, inner ref
- /// rvref &a; // lvalue, inner ref, spelled lvalue
- /// rvref &&a; // rvalue, inner ref
- LLVM_PREFERRED_TYPE(bool)
- unsigned SpelledAsLValue : 1;
-
- /// True if the inner type is a reference type. This only happens
- /// in non-canonical forms.
- LLVM_PREFERRED_TYPE(bool)
- unsigned InnerRef : 1;
- };
-
- class TypeWithKeywordBitfields {
- friend class TypeWithKeyword;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// An ElaboratedTypeKeyword. 8 bits for efficient access.
- LLVM_PREFERRED_TYPE(ElaboratedTypeKeyword)
- unsigned Keyword : 8;
- };
-
- enum { NumTypeWithKeywordBits = NumTypeBits + 8 };
-
- class ElaboratedTypeBitfields {
- friend class ElaboratedType;
-
- LLVM_PREFERRED_TYPE(TypeWithKeywordBitfields)
- unsigned : NumTypeWithKeywordBits;
-
- /// Whether the ElaboratedType has a trailing OwnedTagDecl.
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasOwnedTagDecl : 1;
- };
-
- class VectorTypeBitfields {
- friend class VectorType;
- friend class DependentVectorType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The kind of vector, either a generic vector type or some
- /// target-specific vector type such as for AltiVec or Neon.
- LLVM_PREFERRED_TYPE(VectorKind)
- unsigned VecKind : 4;
- /// The number of elements in the vector.
- uint32_t NumElements;
- };
-
- class AttributedTypeBitfields {
- friend class AttributedType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- LLVM_PREFERRED_TYPE(attr::Kind)
- unsigned AttrKind : 32 - NumTypeBits;
- };
-
- class AutoTypeBitfields {
- friend class AutoType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// Was this placeholder type spelled as 'auto', 'decltype(auto)',
- /// or '__auto_type'? AutoTypeKeyword value.
- LLVM_PREFERRED_TYPE(AutoTypeKeyword)
- unsigned Keyword : 2;
-
- /// The number of template arguments in the type-constraints, which is
- /// expected to be able to hold at least 1024 according to [implimits].
- /// However as this limit is somewhat easy to hit with template
- /// metaprogramming we'd prefer to keep it as large as possible.
- /// At the moment it has been left as a non-bitfield since this type
- /// safely fits in 64 bits as an unsigned, so there is no reason to
- /// introduce the performance impact of a bitfield.
- unsigned NumArgs;
- };
-
- class TypeOfBitfields {
- friend class TypeOfType;
- friend class TypeOfExprType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
- LLVM_PREFERRED_TYPE(TypeOfKind)
- unsigned Kind : 1;
- };
-
- class UsingBitfields {
- friend class UsingType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// True if the underlying type is different from the declared one.
- LLVM_PREFERRED_TYPE(bool)
- unsigned hasTypeDifferentFromDecl : 1;
- };
-
- class TypedefBitfields {
- friend class TypedefType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// True if the underlying type is different from the declared one.
- LLVM_PREFERRED_TYPE(bool)
- unsigned hasTypeDifferentFromDecl : 1;
- };
-
- class TemplateTypeParmTypeBitfields {
- friend class TemplateTypeParmType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The depth of the template parameter.
- unsigned Depth : 15;
-
- /// Whether this is a template parameter pack.
- LLVM_PREFERRED_TYPE(bool)
- unsigned ParameterPack : 1;
-
- /// The index of the template parameter.
- unsigned Index : 16;
- };
-
- class SubstTemplateTypeParmTypeBitfields {
- friend class SubstTemplateTypeParmType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasNonCanonicalUnderlyingType : 1;
-
- // The index of the template parameter this substitution represents.
- unsigned Index : 15;
-
- LLVM_PREFERRED_TYPE(bool)
- unsigned Final : 1;
-
- /// Represents the index within a pack if this represents a substitution
- /// from a pack expansion. This index starts at the end of the pack and
- /// increments towards the beginning.
- /// Positive non-zero number represents the index + 1.
- /// Zero means this is not substituted from an expansion.
- unsigned PackIndex : 15;
- };
-
- class SubstTemplateTypeParmPackTypeBitfields {
- friend class SubstTemplateTypeParmPackType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- // The index of the template parameter this substitution represents.
- unsigned Index : 16;
-
- /// The number of template arguments in \c Arguments, which is
- /// expected to be able to hold at least 1024 according to [implimits].
- /// However as this limit is somewhat easy to hit with template
- /// metaprogramming we'd prefer to keep it as large as possible.
- unsigned NumArgs : 16;
- };
-
- class TemplateSpecializationTypeBitfields {
- friend class TemplateSpecializationType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// Whether this template specialization type is a substituted type alias.
- LLVM_PREFERRED_TYPE(bool)
- unsigned TypeAlias : 1;
-
- /// The number of template arguments named in this class template
- /// specialization, which is expected to be able to hold at least 1024
- /// according to [implimits]. However, as this limit is somewhat easy to
- /// hit with template metaprogramming we'd prefer to keep it as large
- /// as possible. At the moment it has been left as a non-bitfield since
- /// this type safely fits in 64 bits as an unsigned, so there is no reason
- /// to introduce the performance impact of a bitfield.
- unsigned NumArgs;
- };
-
- class DependentTemplateSpecializationTypeBitfields {
- friend class DependentTemplateSpecializationType;
-
- LLVM_PREFERRED_TYPE(TypeWithKeywordBitfields)
- unsigned : NumTypeWithKeywordBits;
-
- /// The number of template arguments named in this class template
- /// specialization, which is expected to be able to hold at least 1024
- /// according to [implimits]. However, as this limit is somewhat easy to
- /// hit with template metaprogramming we'd prefer to keep it as large
- /// as possible. At the moment it has been left as a non-bitfield since
- /// this type safely fits in 64 bits as an unsigned, so there is no reason
- /// to introduce the performance impact of a bitfield.
- unsigned NumArgs;
- };
-
- class PackExpansionTypeBitfields {
- friend class PackExpansionType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- /// The number of expansions that this pack expansion will
- /// generate when substituted (+1), which is expected to be able to
- /// hold at least 1024 according to [implimits]. However, as this limit
- /// is somewhat easy to hit with template metaprogramming we'd prefer to
- /// keep it as large as possible. At the moment it has been left as a
- /// non-bitfield since this type safely fits in 64 bits as an unsigned, so
- /// there is no reason to introduce the performance impact of a bitfield.
- ///
- /// This field will only have a non-zero value when some of the parameter
- /// packs that occur within the pattern have been substituted but others
- /// have not.
- unsigned NumExpansions;
- };
-
- enum class PredefinedSugarKind {
- /// The "size_t" type.
- SizeT,
-
- /// The signed integer type corresponding to "size_t".
- SignedSizeT,
-
- /// The "ptrdiff_t" type.
- PtrdiffT,
-
- // Indicates how many items the enum has.
- Last = PtrdiffT
- };
-
- class PresefinedSugarTypeBitfields {
- friend class PredefinedSugarType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- LLVM_PREFERRED_TYPE(PredefinedSugarKind)
- unsigned Kind : 8;
- };
-
- class CountAttributedTypeBitfields {
- friend class CountAttributedType;
-
- LLVM_PREFERRED_TYPE(TypeBitfields)
- unsigned : NumTypeBits;
-
- static constexpr unsigned NumCoupledDeclsBits = 4;
- unsigned NumCoupledDecls : NumCoupledDeclsBits;
- LLVM_PREFERRED_TYPE(bool)
- unsigned CountInBytes : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned OrNull : 1;
- };
- static_assert(sizeof(CountAttributedTypeBitfields) <= sizeof(unsigned));
-
- union {
- TypeBitfields TypeBits;
- ArrayTypeBitfields ArrayTypeBits;
- ConstantArrayTypeBitfields ConstantArrayTypeBits;
- AttributedTypeBitfields AttributedTypeBits;
- AutoTypeBitfields AutoTypeBits;
- TypeOfBitfields TypeOfBits;
- TypedefBitfields TypedefBits;
- UsingBitfields UsingBits;
- BuiltinTypeBitfields BuiltinTypeBits;
- FunctionTypeBitfields FunctionTypeBits;
- ObjCObjectTypeBitfields ObjCObjectTypeBits;
- ReferenceTypeBitfields ReferenceTypeBits;
- TypeWithKeywordBitfields TypeWithKeywordBits;
- ElaboratedTypeBitfields ElaboratedTypeBits;
- VectorTypeBitfields VectorTypeBits;
- TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
- SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
- SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits;
- TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
- DependentTemplateSpecializationTypeBitfields
- DependentTemplateSpecializationTypeBits;
- PackExpansionTypeBitfields PackExpansionTypeBits;
- CountAttributedTypeBitfields CountAttributedTypeBits;
- PresefinedSugarTypeBitfields PredefinedSugarTypeBits;
- };
-
-private:
- template <class T> friend class TypePropertyCache;
-
- /// Set whether this type comes from an AST file.
- void setFromAST(bool V = true) const {
- TypeBits.FromAST = V;
- }
-
-protected:
- friend class ASTContext;
-
- Type(TypeClass tc, QualType canon, TypeDependence Dependence)
- : ExtQualsTypeCommonBase(this,
- canon.isNull() ? QualType(this_(), 0) : canon) {
- static_assert(sizeof(*this) <=
- alignof(decltype(*this)) + sizeof(ExtQualsTypeCommonBase),
- "changing bitfields changed sizeof(Type)!");
- static_assert(alignof(decltype(*this)) % TypeAlignment == 0,
- "Insufficient alignment!");
- TypeBits.TC = tc;
- TypeBits.Dependence = static_cast<unsigned>(Dependence);
- TypeBits.CacheValid = false;
- TypeBits.CachedLocalOrUnnamed = false;
- TypeBits.CachedLinkage = llvm::to_underlying(Linkage::Invalid);
- TypeBits.FromAST = false;
- }
-
- // silence VC++ warning C4355: 'this' : used in base member initializer list
- Type *this_() { return this; }
-
- void setDependence(TypeDependence D) {
- TypeBits.Dependence = static_cast<unsigned>(D);
- }
-
- void addDependence(TypeDependence D) { setDependence(getDependence() | D); }
-
-public:
- friend class ASTReader;
- friend class ASTWriter;
- template <class T> friend class serialization::AbstractTypeReader;
- template <class T> friend class serialization::AbstractTypeWriter;
-
- Type(const Type &) = delete;
- Type(Type &&) = delete;
- Type &operator=(const Type &) = delete;
- Type &operator=(Type &&) = delete;
-
- TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); }
-
- /// Whether this type comes from an AST file.
- bool isFromAST() const { return TypeBits.FromAST; }
-
- /// Whether this type is or contains an unexpanded parameter
- /// pack, used to support C++0x variadic templates.
- ///
- /// A type that contains a parameter pack shall be expanded by the
- /// ellipsis operator at some point. For example, the typedef in the
- /// following example contains an unexpanded parameter pack 'T':
- ///
- /// \code
- /// template<typename ...T>
- /// struct X {
- /// typedef T* pointer_types; // ill-formed; T is a parameter pack.
- /// };
- /// \endcode
- ///
- /// Note that this routine does not specify which
- bool containsUnexpandedParameterPack() const {
- return getDependence() & TypeDependence::UnexpandedPack;
- }
-
- /// Determines if this type would be canonical if it had no further
- /// qualification.
- bool isCanonicalUnqualified() const {
- return CanonicalType == QualType(this, 0);
- }
-
- /// Pull a single level of sugar off of this locally-unqualified type.
- /// Users should generally prefer SplitQualType::getSingleStepDesugaredType()
- /// or QualType::getSingleStepDesugaredType(const ASTContext&).
- QualType getLocallyUnqualifiedSingleStepDesugaredType() const;
-
- /// As an extension, we classify types as one of "sized" or "sizeless";
- /// every type is one or the other. Standard types are all sized;
- /// sizeless types are purely an extension.
- ///
- /// Sizeless types contain data with no specified size, alignment,
- /// or layout.
- bool isSizelessType() const;
- bool isSizelessBuiltinType() const;
-
- /// Returns true for all scalable vector types.
- bool isSizelessVectorType() const;
-
- /// Returns true for SVE scalable vector types.
- bool isSVESizelessBuiltinType() const;
-
- /// Returns true for RVV scalable vector types.
- bool isRVVSizelessBuiltinType() const;
-
- /// Check if this is a WebAssembly Externref Type.
- bool isWebAssemblyExternrefType() const;
-
- /// Returns true if this is a WebAssembly table type: either an array of
- /// reference types, or a pointer to a reference type (which can only be
- /// created by array to pointer decay).
- bool isWebAssemblyTableType() const;
-
- /// Determines if this is a sizeless type supported by the
- /// 'arm_sve_vector_bits' type attribute, which can be applied to a single
- /// SVE vector or predicate, excluding tuple types such as svint32x4_t.
- bool isSveVLSBuiltinType() const;
-
- /// Returns the representative type for the element of an SVE builtin type.
- /// This is used to represent fixed-length SVE vectors created with the
- /// 'arm_sve_vector_bits' type attribute as VectorType.
- QualType getSveEltType(const ASTContext &Ctx) const;
-
- /// Determines if this is a sizeless type supported by the
- /// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single
- /// RVV vector or mask.
- bool isRVVVLSBuiltinType() const;
-
- /// Returns the representative type for the element of an RVV builtin type.
- /// This is used to represent fixed-length RVV vectors created with the
- /// 'riscv_rvv_vector_bits' type attribute as VectorType.
- QualType getRVVEltType(const ASTContext &Ctx) const;
-
- /// Returns the representative type for the element of a sizeless vector
- /// builtin type.
- QualType getSizelessVectorEltType(const ASTContext &Ctx) const;
-
- /// Types are partitioned into 3 broad categories (C99 6.2.5p1):
- /// object types, function types, and incomplete types.
-
- /// Return true if this is an incomplete type.
- /// A type that can describe objects, but which lacks information needed to
- /// determine its size (e.g. void, or a fwd declared struct). Clients of this
- /// routine will need to determine if the size is actually required.
- ///
- /// Def If non-null, and the type refers to some kind of declaration
- /// that can be completed (such as a C struct, C++ class, or Objective-C
- /// class), will be set to the declaration.
- bool isIncompleteType(NamedDecl **Def = nullptr) const;
-
- /// Return true if this is an incomplete or object
- /// type, in other words, not a function type.
- bool isIncompleteOrObjectType() const {
- return !isFunctionType();
- }
-
- /// \returns True if the type is incomplete and it is also a type that
- /// cannot be completed by a later type definition.
- ///
- /// E.g. For `void` this is true but for `struct ForwardDecl;` this is false
- /// because a definition for `ForwardDecl` could be provided later on in the
- /// translation unit.
- ///
- /// Note even for types that this function returns true for it is still
- /// possible for the declarations that contain this type to later have a
- /// complete type in a translation unit. E.g.:
- ///
- /// \code{.c}
- /// // This decl has type 'char[]' which is incomplete and cannot be later
- /// // completed by another by another type declaration.
- /// extern char foo[];
- /// // This decl now has complete type 'char[5]'.
- /// char foo[5]; // foo has a complete type
- /// \endcode
- bool isAlwaysIncompleteType() const;
-
- /// Determine whether this type is an object type.
- bool isObjectType() const {
- // C++ [basic.types]p8:
- // An object type is a (possibly cv-qualified) type that is not a
- // function type, not a reference type, and not a void type.
- return !isReferenceType() && !isFunctionType() && !isVoidType();
- }
-
- /// Return true if this is a literal type
- /// (C++11 [basic.types]p10)
- bool isLiteralType(const ASTContext &Ctx) const;
-
- /// Determine if this type is a structural type, per C++20 [temp.param]p7.
- bool isStructuralType() const;
-
- /// Test if this type is a standard-layout type.
- /// (C++0x [basic.type]p9)
- bool isStandardLayoutType() const;
-
- /// Helper methods to distinguish type categories. All type predicates
- /// operate on the canonical type, ignoring typedefs and qualifiers.
-
- /// Returns true if the type is a builtin type.
- bool isBuiltinType() const;
-
- /// Test for a particular builtin type.
- bool isSpecificBuiltinType(unsigned K) const;
-
- /// Test for a type which does not represent an actual type-system type but
- /// is instead used as a placeholder for various convenient purposes within
- /// Clang. All such types are BuiltinTypes.
- bool isPlaceholderType() const;
- const BuiltinType *getAsPlaceholderType() const;
-
- /// Test for a specific placeholder type.
- bool isSpecificPlaceholderType(unsigned K) const;
-
- /// Test for a placeholder type other than Overload; see
- /// BuiltinType::isNonOverloadPlaceholderType.
- bool isNonOverloadPlaceholderType() const;
-
- /// isIntegerType() does *not* include complex integers (a GCC extension).
- /// isComplexIntegerType() can be used to test for complex integers.
- bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
- bool isEnumeralType() const;
-
- /// Determine whether this type is a scoped enumeration type.
- bool isScopedEnumeralType() const;
- bool isBooleanType() const;
- bool isCharType() const;
- bool isWideCharType() const;
- bool isChar8Type() const;
- bool isChar16Type() const;
- bool isChar32Type() const;
- bool isAnyCharacterType() const;
- bool isUnicodeCharacterType() const;
- bool isIntegralType(const ASTContext &Ctx) const;
-
- /// Determine whether this type is an integral or enumeration type.
- bool isIntegralOrEnumerationType() const;
-
- /// Determine whether this type is an integral or unscoped enumeration type.
- bool isIntegralOrUnscopedEnumerationType() const;
- bool isUnscopedEnumerationType() const;
-
- /// Floating point categories.
- bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
- /// isComplexType() does *not* include complex integers (a GCC extension).
- /// isComplexIntegerType() can be used to test for complex integers.
- bool isComplexType() const; // C99 6.2.5p11 (complex)
- bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
- bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
- bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
- bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
- bool isFloat32Type() const;
- bool isDoubleType() const;
- bool isBFloat16Type() const;
- bool isMFloat8Type() const;
- bool isFloat128Type() const;
- bool isIbm128Type() const;
- bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
- bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
- bool isVoidType() const; // C99 6.2.5p19
- bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
- bool isAggregateType() const;
- bool isFundamentalType() const;
- bool isCompoundType() const;
-
- // Type Predicates: Check to see if this type is structurally the specified
- // type, ignoring typedefs and qualifiers.
- bool isFunctionType() const;
- bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
- bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
- bool isPointerType() const;
- bool isPointerOrReferenceType() const;
- bool isSignableType(const ASTContext &Ctx) const;
- bool isSignablePointerType() const;
- bool isSignableIntegerType(const ASTContext &Ctx) const;
- bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
- bool isCountAttributedType() const;
- bool isCFIUncheckedCalleeFunctionType() const;
- bool hasPointeeToToCFIUncheckedCalleeFunctionType() const;
- bool isBlockPointerType() const;
- bool isVoidPointerType() const;
- bool isReferenceType() const;
- bool isLValueReferenceType() const;
- bool isRValueReferenceType() const;
- bool isObjectPointerType() const;
- bool isFunctionPointerType() const;
- bool isFunctionReferenceType() const;
- bool isMemberPointerType() const;
- bool isMemberFunctionPointerType() const;
- bool isMemberDataPointerType() const;
- bool isArrayType() const;
- bool isConstantArrayType() const;
- bool isIncompleteArrayType() const;
- bool isVariableArrayType() const;
- bool isArrayParameterType() const;
- bool isDependentSizedArrayType() const;
- bool isRecordType() const;
- bool isClassType() const;
- bool isStructureType() const;
- bool isStructureTypeWithFlexibleArrayMember() const;
- bool isObjCBoxableRecordType() const;
- bool isInterfaceType() const;
- bool isStructureOrClassType() const;
- bool isUnionType() const;
- bool isComplexIntegerType() const; // GCC _Complex integer type.
- bool isVectorType() const; // GCC vector type.
- bool isExtVectorType() const; // Extended vector type.
- bool isExtVectorBoolType() const; // Extended vector type with bool element.
- // Extended vector type with bool element that is packed. HLSL doesn't pack
- // its bool vectors.
- bool isPackedVectorBoolType(const ASTContext &ctx) const;
- bool isSubscriptableVectorType() const;
- bool isMatrixType() const; // Matrix type.
- bool isConstantMatrixType() const; // Constant matrix type.
- bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
- bool isObjCObjectPointerType() const; // pointer to ObjC object
- bool isObjCRetainableType() const; // ObjC object or block pointer
- bool isObjCLifetimeType() const; // (array of)* retainable type
- bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
- bool isObjCNSObjectType() const; // __attribute__((NSObject))
- bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class))
- // FIXME: change this to 'raw' interface type, so we can used 'interface' type
- // for the common case.
- bool isObjCObjectType() const; // NSString or typeof(*(id)0)
- bool isObjCQualifiedInterfaceType() const; // NSString<foo>
- bool isObjCQualifiedIdType() const; // id<foo>
- bool isObjCQualifiedClassType() const; // Class<foo>
- bool isObjCObjectOrInterfaceType() const;
- bool isObjCIdType() const; // id
- bool isDecltypeType() const;
- /// Was this type written with the special inert-in-ARC __unsafe_unretained
- /// qualifier?
- ///
- /// This approximates the answer to the following question: if this
- /// translation unit were compiled in ARC, would this type be qualified
- /// with __unsafe_unretained?
- bool isObjCInertUnsafeUnretainedType() const {
- return hasAttr(attr::ObjCInertUnsafeUnretained);
- }
-
- /// Whether the type is Objective-C 'id' or a __kindof type of an
- /// object type, e.g., __kindof NSView * or __kindof id
- /// <NSCopying>.
- ///
- /// \param bound Will be set to the bound on non-id subtype types,
- /// which will be (possibly specialized) Objective-C class type, or
- /// null for 'id.
- bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
- const ObjCObjectType *&bound) const;
-
- bool isObjCClassType() const; // Class
-
- /// Whether the type is Objective-C 'Class' or a __kindof type of an
- /// Class type, e.g., __kindof Class <NSCopying>.
- ///
- /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound
- /// here because Objective-C's type system cannot express "a class
- /// object for a subclass of NSFoo".
- bool isObjCClassOrClassKindOfType() const;
-
- bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
- bool isObjCSelType() const; // Class
- bool isObjCBuiltinType() const; // 'id' or 'Class'
- bool isObjCARCBridgableType() const;
- bool isCARCBridgableType() const;
- bool isTemplateTypeParmType() const; // C++ template type parameter
- bool isNullPtrType() const; // C++11 std::nullptr_t or
- // C23 nullptr_t
- bool isNothrowT() const; // C++ std::nothrow_t
- bool isAlignValT() const; // C++17 std::align_val_t
- bool isStdByteType() const; // C++17 std::byte
- bool isAtomicType() const; // C11 _Atomic()
- bool isUndeducedAutoType() const; // C++11 auto or
- // C++14 decltype(auto)
- bool isTypedefNameType() const; // typedef or alias template
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- bool is##Id##Type() const;
-#include "clang/Basic/OpenCLImageTypes.def"
-
- bool isImageType() const; // Any OpenCL image type
-
- bool isSamplerT() const; // OpenCL sampler_t
- bool isEventT() const; // OpenCL event_t
- bool isClkEventT() const; // OpenCL clk_event_t
- bool isQueueT() const; // OpenCL queue_t
- bool isReserveIDT() const; // OpenCL reserve_id_t
-
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- bool is##Id##Type() const;
-#include "clang/Basic/OpenCLExtensionTypes.def"
- // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension
- bool isOCLIntelSubgroupAVCType() const;
- bool isOCLExtOpaqueType() const; // Any OpenCL extension type
-
- bool isPipeType() const; // OpenCL pipe type
- bool isBitIntType() const; // Bit-precise integer type
- bool isOpenCLSpecificType() const; // Any OpenCL specific type
-
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
-#include "clang/Basic/HLSLIntangibleTypes.def"
- bool isHLSLSpecificType() const; // Any HLSL specific type
- bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type
- bool isHLSLAttributedResourceType() const;
- bool isHLSLInlineSpirvType() const;
- bool isHLSLResourceRecord() const;
- bool isHLSLIntangibleType()
- const; // Any HLSL intangible type (builtin, array, class)
-
- /// Determines if this type, which must satisfy
- /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
- /// than implicitly __strong.
- bool isObjCARCImplicitlyUnretainedType() const;
-
- /// Check if the type is the CUDA device builtin surface type.
- bool isCUDADeviceBuiltinSurfaceType() const;
- /// Check if the type is the CUDA device builtin texture type.
- bool isCUDADeviceBuiltinTextureType() const;
-
- /// Return the implicit lifetime for this type, which must not be dependent.
- Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
-
- enum ScalarTypeKind {
- STK_CPointer,
- STK_BlockPointer,
- STK_ObjCObjectPointer,
- STK_MemberPointer,
- STK_Bool,
- STK_Integral,
- STK_Floating,
- STK_IntegralComplex,
- STK_FloatingComplex,
- STK_FixedPoint
- };
-
- /// Given that this is a scalar type, classify it.
- ScalarTypeKind getScalarTypeKind() const;
-
- TypeDependence getDependence() const {
- return static_cast<TypeDependence>(TypeBits.Dependence);
- }
-
- /// Whether this type is an error type.
- bool containsErrors() const {
- return getDependence() & TypeDependence::Error;
- }
-
- /// Whether this type is a dependent type, meaning that its definition
- /// somehow depends on a template parameter (C++ [temp.dep.type]).
- bool isDependentType() const {
- return getDependence() & TypeDependence::Dependent;
- }
-
- /// Determine whether this type is an instantiation-dependent type,
- /// meaning that the type involves a template parameter (even if the
- /// definition does not actually depend on the type substituted for that
- /// template parameter).
- bool isInstantiationDependentType() const {
- return getDependence() & TypeDependence::Instantiation;
- }
-
- /// Determine whether this type is an undeduced type, meaning that
- /// it somehow involves a C++11 'auto' type or similar which has not yet been
- /// deduced.
- bool isUndeducedType() const;
-
- /// Whether this type is a variably-modified type (C99 6.7.5).
- bool isVariablyModifiedType() const {
- return getDependence() & TypeDependence::VariablyModified;
- }
-
- /// Whether this type involves a variable-length array type
- /// with a definite size.
- bool hasSizedVLAType() const;
-
- /// Whether this type is or contains a local or unnamed type.
- bool hasUnnamedOrLocalType() const;
-
- bool isOverloadableType() const;
-
- /// Determine wither this type is a C++ elaborated-type-specifier.
- bool isElaboratedTypeSpecifier() const;
-
- bool canDecayToPointerType() const;
-
- /// Whether this type is represented natively as a pointer. This includes
- /// pointers, references, block pointers, and Objective-C interface,
- /// qualified id, and qualified interface types, as well as nullptr_t.
- bool hasPointerRepresentation() const;
-
- /// Whether this type can represent an objective pointer type for the
- /// purpose of GC'ability
- bool hasObjCPointerRepresentation() const;
-
- /// Determine whether this type has an integer representation
- /// of some sort, e.g., it is an integer type or a vector.
- bool hasIntegerRepresentation() const;
-
- /// Determine whether this type has an signed integer representation
- /// of some sort, e.g., it is an signed integer type or a vector.
- bool hasSignedIntegerRepresentation() const;
-
- /// Determine whether this type has an unsigned integer representation
- /// of some sort, e.g., it is an unsigned integer type or a vector.
- bool hasUnsignedIntegerRepresentation() const;
-
- /// Determine whether this type has a floating-point representation
- /// of some sort, e.g., it is a floating-point type or a vector thereof.
- bool hasFloatingRepresentation() const;
-
- /// Determine whether this type has a boolean representation -- i.e., it is a
- /// boolean type, an enum type whose underlying type is a boolean type, or a
- /// vector of booleans.
- bool hasBooleanRepresentation() const;
-
- // Type Checking Functions: Check to see if this type is structurally the
- // specified type, ignoring typedefs and qualifiers, and return a pointer to
- // the best type we can.
- const RecordType *getAsStructureType() const;
- /// NOTE: getAs*ArrayType are methods on ASTContext.
- const RecordType *getAsUnionType() const;
- const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
- const ObjCObjectType *getAsObjCInterfaceType() const;
-
- // The following is a convenience method that returns an ObjCObjectPointerType
- // for object declared using an interface.
- const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
- const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
- const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
- const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
-
- /// Retrieves the CXXRecordDecl that this type refers to, either
- /// because the type is a RecordType or because it is the injected-class-name
- /// type of a class template or class template partial specialization.
- CXXRecordDecl *getAsCXXRecordDecl() const;
-
- /// Retrieves the RecordDecl this type refers to.
- RecordDecl *getAsRecordDecl() const;
-
- /// Retrieves the TagDecl that this type refers to, either
- /// because the type is a TagType or because it is the injected-class-name
- /// type of a class template or class template partial specialization.
- TagDecl *getAsTagDecl() const;
-
- /// If this is a pointer or reference to a RecordType, return the
- /// CXXRecordDecl that the type refers to.
- ///
- /// If this is not a pointer or reference, or the type being pointed to does
- /// not refer to a CXXRecordDecl, returns NULL.
- const CXXRecordDecl *getPointeeCXXRecordDecl() const;
-
- /// Get the DeducedType whose type will be deduced for a variable with
- /// an initializer of this type. This looks through declarators like pointer
- /// types, but not through decltype or typedefs.
- DeducedType *getContainedDeducedType() const;
-
- /// Get the AutoType whose type will be deduced for a variable with
- /// an initializer of this type. This looks through declarators like pointer
- /// types, but not through decltype or typedefs.
- AutoType *getContainedAutoType() const {
- return dyn_cast_or_null<AutoType>(getContainedDeducedType());
- }
-
- /// Determine whether this type was written with a leading 'auto'
- /// corresponding to a trailing return type (possibly for a nested
- /// function type within a pointer to function type or similar).
- bool hasAutoForTrailingReturnType() const;
-
- /// Member-template getAs<specific type>'. Look through sugar for
- /// an instance of \<specific type>. This scheme will eventually
- /// replace the specific getAsXXXX methods above.
- ///
- /// There are some specializations of this member template listed
- /// immediately following this class.
- template <typename T> const T *getAs() const;
-
- /// Look through sugar for an instance of TemplateSpecializationType which
- /// is not a type alias, or null if there is no such type.
- /// This is used when you want as-written template arguments or the template
- /// name for a class template specialization.
- const TemplateSpecializationType *
- getAsNonAliasTemplateSpecializationType() const;
-
- const TemplateSpecializationType *
- castAsNonAliasTemplateSpecializationType() const {
- const auto *TST = getAsNonAliasTemplateSpecializationType();
- assert(TST && "not a TemplateSpecializationType");
- return TST;
- }
-
- /// Member-template getAsAdjusted<specific type>. Look through specific kinds
- /// of sugar (parens, attributes, etc) for an instance of \<specific type>.
- /// This is used when you need to walk over sugar nodes that represent some
- /// kind of type adjustment from a type that was written as a \<specific type>
- /// to another type that is still canonically a \<specific type>.
- template <typename T> const T *getAsAdjusted() const;
-
- /// A variant of getAs<> for array types which silently discards
- /// qualifiers from the outermost type.
- const ArrayType *getAsArrayTypeUnsafe() const;
-
- /// Member-template castAs<specific type>. Look through sugar for
- /// the underlying instance of \<specific type>.
- ///
- /// This method has the same relationship to getAs<T> as cast<T> has
- /// to dyn_cast<T>; which is to say, the underlying type *must*
- /// have the intended type, and this method will never return null.
- template <typename T> const T *castAs() const;
-
- /// A variant of castAs<> for array type which silently discards
- /// qualifiers from the outermost type.
- const ArrayType *castAsArrayTypeUnsafe() const;
-
- /// Determine whether this type had the specified attribute applied to it
- /// (looking through top-level type sugar).
- bool hasAttr(attr::Kind AK) const;
-
- /// Get the base element type of this type, potentially discarding type
- /// qualifiers. This should never be used when type qualifiers
- /// are meaningful.
- const Type *getBaseElementTypeUnsafe() const;
-
- /// If this is an array type, return the element type of the array,
- /// potentially with type qualifiers missing.
- /// This should never be used when type qualifiers are meaningful.
- const Type *getArrayElementTypeNoTypeQual() const;
-
- /// If this is a pointer type, return the pointee type.
- /// If this is an array type, return the array element type.
- /// This should never be used when type qualifiers are meaningful.
- const Type *getPointeeOrArrayElementType() const;
-
- /// If this is a pointer, ObjC object pointer, or block
- /// pointer, this returns the respective pointee.
- QualType getPointeeType() const;
-
- /// Return the specified type with any "sugar" removed from the type,
- /// removing any typedefs, typeofs, etc., as well as any qualifiers.
- const Type *getUnqualifiedDesugaredType() const;
-
- /// Return true if this is an integer type that is
- /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
- /// or an enum decl which has a signed representation.
- bool isSignedIntegerType() const;
-
- /// Return true if this is an integer type that is
- /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool],
- /// or an enum decl which has an unsigned representation.
- bool isUnsignedIntegerType() const;
-
- /// Determines whether this is an integer type that is signed or an
- /// enumeration types whose underlying type is a signed integer type.
- bool isSignedIntegerOrEnumerationType() const;
-
- /// Determines whether this is an integer type that is unsigned or an
- /// enumeration types whose underlying type is a unsigned integer type.
- bool isUnsignedIntegerOrEnumerationType() const;
-
- /// Return true if this is a fixed point type according to
- /// ISO/IEC JTC1 SC22 WG14 N1169.
- bool isFixedPointType() const;
-
- /// Return true if this is a fixed point or integer type.
- bool isFixedPointOrIntegerType() const;
-
- /// Return true if this can be converted to (or from) a fixed point type.
- bool isConvertibleToFixedPointType() const;
-
- /// Return true if this is a saturated fixed point type according to
- /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned.
- bool isSaturatedFixedPointType() const;
-
- /// Return true if this is a saturated fixed point type according to
- /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned.
- bool isUnsaturatedFixedPointType() const;
-
- /// Return true if this is a fixed point type that is signed according
- /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated.
- bool isSignedFixedPointType() const;
-
- /// Return true if this is a fixed point type that is unsigned according
- /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated.
- bool isUnsignedFixedPointType() const;
-
- /// Return true if this is not a variable sized type,
- /// according to the rules of C99 6.7.5p3. It is not legal to call this on
- /// incomplete types.
- bool isConstantSizeType() const;
-
- /// Returns true if this type can be represented by some
- /// set of type specifiers.
- bool isSpecifierType() const;
-
- /// Determine the linkage of this type.
- Linkage getLinkage() const;
-
- /// Determine the visibility of this type.
- Visibility getVisibility() const {
- return getLinkageAndVisibility().getVisibility();
- }
-
- /// Return true if the visibility was explicitly set is the code.
- bool isVisibilityExplicit() const {
- return getLinkageAndVisibility().isVisibilityExplicit();
- }
-
- /// Determine the linkage and visibility of this type.
- LinkageInfo getLinkageAndVisibility() const;
-
- /// True if the computed linkage is valid. Used for consistency
- /// checking. Should always return true.
- bool isLinkageValid() const;
-
- /// Determine the nullability of the given type.
- ///
- /// Note that nullability is only captured as sugar within the type
- /// system, not as part of the canonical type, so nullability will
- /// be lost by canonicalization and desugaring.
- std::optional<NullabilityKind> getNullability() const;
-
- /// Determine whether the given type can have a nullability
- /// specifier applied to it, i.e., if it is any kind of pointer type.
- ///
- /// \param ResultIfUnknown The value to return if we don't yet know whether
- /// this type can have nullability because it is dependent.
- bool canHaveNullability(bool ResultIfUnknown = true) const;
-
- /// Retrieve the set of substitutions required when accessing a member
- /// of the Objective-C receiver type that is declared in the given context.
- ///
- /// \c *this is the type of the object we're operating on, e.g., the
- /// receiver for a message send or the base of a property access, and is
- /// expected to be of some object or object pointer type.
- ///
- /// \param dc The declaration context for which we are building up a
- /// substitution mapping, which should be an Objective-C class, extension,
- /// category, or method within.
- ///
- /// \returns an array of type arguments that can be substituted for
- /// the type parameters of the given declaration context in any type described
- /// within that context, or an empty optional to indicate that no
- /// substitution is required.
- std::optional<ArrayRef<QualType>>
- getObjCSubstitutions(const DeclContext *dc) const;
-
- /// Determines if this is an ObjC interface type that may accept type
- /// parameters.
- bool acceptsObjCTypeParams() const;
-
- const char *getTypeClassName() const;
-
- QualType getCanonicalTypeInternal() const {
- return CanonicalType;
- }
-
- CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
- void dump() const;
- void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
-};
-
-/// This will check for a TypedefType by removing any existing sugar
-/// until it reaches a TypedefType or a non-sugared type.
-template <> const TypedefType *Type::getAs() const;
-template <> const UsingType *Type::getAs() const;
-
-/// This will check for a TemplateSpecializationType by removing any
-/// existing sugar until it reaches a TemplateSpecializationType or a
-/// non-sugared type.
-template <> const TemplateSpecializationType *Type::getAs() const;
-
-/// This will check for an AttributedType by removing any existing sugar
-/// until it reaches an AttributedType or a non-sugared type.
-template <> const AttributedType *Type::getAs() const;
-
-/// This will check for a BoundsAttributedType by removing any existing
-/// sugar until it reaches an BoundsAttributedType or a non-sugared type.
-template <> const BoundsAttributedType *Type::getAs() const;
-
-/// This will check for a CountAttributedType by removing any existing
-/// sugar until it reaches an CountAttributedType or a non-sugared type.
-template <> const CountAttributedType *Type::getAs() const;
-
-// We can do canonical leaf types faster, because we don't have to
-// worry about preserving child type decoration.
-#define TYPE(Class, Base)
-#define LEAF_TYPE(Class) \
-template <> inline const Class##Type *Type::getAs() const { \
- return dyn_cast<Class##Type>(CanonicalType); \
-} \
-template <> inline const Class##Type *Type::castAs() const { \
- return cast<Class##Type>(CanonicalType); \
+inline CXXRecordDecl *Type::getAsCXXRecordDecl() const {
+ const auto *TT = dyn_cast<TagType>(CanonicalType);
+ if (!isa_and_present<RecordType, InjectedClassNameType>(TT))
+ return nullptr;
+ auto *TD = TT->getOriginalDecl();
+ if (isa<RecordType>(TT) && !isa<CXXRecordDecl>(TD))
+ return nullptr;
+ return cast<CXXRecordDecl>(TD)->getDefinitionOrSelf();
}
-#include "clang/AST/TypeNodes.inc"
-
-/// This class is used for builtin types like 'int'. Builtin
-/// types are always canonical and have a literal name field.
-class BuiltinType : public Type {
-public:
- enum Kind {
-// OpenCL image types
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id,
-#include "clang/Basic/OpenCLImageTypes.def"
-// OpenCL extension types
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id,
-#include "clang/Basic/OpenCLExtensionTypes.def"
-// SVE Types
-#define SVE_TYPE(Name, Id, SingletonId) Id,
-#include "clang/Basic/AArch64ACLETypes.def"
-// PPC MMA Types
-#define PPC_VECTOR_TYPE(Name, Id, Size) Id,
-#include "clang/Basic/PPCTypes.def"
-// RVV Types
-#define RVV_TYPE(Name, Id, SingletonId) Id,
-#include "clang/Basic/RISCVVTypes.def"
-// WebAssembly reference types
-#define WASM_TYPE(Name, Id, SingletonId) Id,
-#include "clang/Basic/WebAssemblyReferenceTypes.def"
-// AMDGPU types
-#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) Id,
-#include "clang/Basic/AMDGPUTypes.def"
-// HLSL intangible Types
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id,
-#include "clang/Basic/HLSLIntangibleTypes.def"
-// All other builtin types
-#define BUILTIN_TYPE(Id, SingletonId) Id,
-#define LAST_BUILTIN_TYPE(Id) LastKind = Id
-#include "clang/AST/BuiltinTypes.def"
- };
-
-private:
- friend class ASTContext; // ASTContext creates these.
-
- BuiltinType(Kind K)
- : Type(Builtin, QualType(),
- K == Dependent ? TypeDependence::DependentInstantiation
- : TypeDependence::None) {
- static_assert(Kind::LastKind <
- (1 << BuiltinTypeBitfields::NumOfBuiltinTypeBits) &&
- "Defined builtin type exceeds the allocated space for serial "
- "numbering");
- BuiltinTypeBits.Kind = K;
- }
-
-public:
- Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); }
- StringRef getName(const PrintingPolicy &Policy) const;
-
- const char *getNameAsCString(const PrintingPolicy &Policy) const {
- // The StringRef is null-terminated.
- StringRef str = getName(Policy);
- assert(!str.empty() && str.data()[str.size()] == '\0');
- return str.data();
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- bool isInteger() const {
- return getKind() >= Bool && getKind() <= Int128;
- }
-
- bool isSignedInteger() const {
- return getKind() >= Char_S && getKind() <= Int128;
- }
-
- bool isUnsignedInteger() const {
- return getKind() >= Bool && getKind() <= UInt128;
- }
-
- bool isFloatingPoint() const {
- return getKind() >= Half && getKind() <= Ibm128;
- }
-
- bool isSVEBool() const { return getKind() == Kind::SveBool; }
-
- bool isSVECount() const { return getKind() == Kind::SveCount; }
-
- /// Determines whether the given kind corresponds to a placeholder type.
- static bool isPlaceholderTypeKind(Kind K) {
- return K >= Overload;
- }
-
- /// Determines whether this type is a placeholder type, i.e. a type
- /// which cannot appear in arbitrary positions in a fully-formed
- /// expression.
- bool isPlaceholderType() const {
- return isPlaceholderTypeKind(getKind());
- }
-
- /// Determines whether this type is a placeholder type other than
- /// Overload. Most placeholder types require only syntactic
- /// information about their context in order to be resolved (e.g.
- /// whether it is a call expression), which means they can (and
- /// should) be resolved in an earlier "phase" of analysis.
- /// Overload expressions sometimes pick up further information
- /// from their context, like whether the context expects a
- /// specific function-pointer type, and so frequently need
- /// special treatment.
- bool isNonOverloadPlaceholderType() const {
- return getKind() > Overload;
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
-};
-
-/// Complex values, per C99 6.2.5p11. This supports the C99 complex
-/// types (_Complex float etc) as well as the GCC integer complex extensions.
-class ComplexType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType ElementType;
-
- ComplexType(QualType Element, QualType CanonicalPtr)
- : Type(Complex, CanonicalPtr, Element->getDependence()),
- ElementType(Element) {}
-
-public:
- QualType getElementType() const { return ElementType; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) {
- ID.AddPointer(Element.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
-};
-
-/// Sugar for parentheses used when specifying types.
-class ParenType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType Inner;
-
- ParenType(QualType InnerType, QualType CanonType)
- : Type(Paren, CanonType, InnerType->getDependence()), Inner(InnerType) {}
-
-public:
- QualType getInnerType() const { return Inner; }
-
- bool isSugared() const { return true; }
- QualType desugar() const { return getInnerType(); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getInnerType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) {
- Inner.Profile(ID);
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Paren; }
-};
-
-/// PointerType - C99 6.7.5.1 - Pointer Declarators.
-class PointerType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType PointeeType;
-
- PointerType(QualType Pointee, QualType CanonicalPtr)
- : Type(Pointer, CanonicalPtr, Pointee->getDependence()),
- PointeeType(Pointee) {}
-
-public:
- QualType getPointeeType() const { return PointeeType; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
- ID.AddPointer(Pointee.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
-};
-
-/// [BoundsSafety] Represents information of declarations referenced by the
-/// arguments of the `counted_by` attribute and the likes.
-class TypeCoupledDeclRefInfo {
-public:
- using BaseTy = llvm::PointerIntPair<ValueDecl *, 1, unsigned>;
-
-private:
- enum {
- DerefShift = 0,
- DerefMask = 1,
- };
- BaseTy Data;
-
-public:
- /// \p D is to a declaration referenced by the argument of attribute. \p Deref
- /// indicates whether \p D is referenced as a dereferenced form, e.g., \p
- /// Deref is true for `*n` in `int *__counted_by(*n)`.
- TypeCoupledDeclRefInfo(ValueDecl *D = nullptr, bool Deref = false);
-
- bool isDeref() const;
- ValueDecl *getDecl() const;
- unsigned getInt() const;
- void *getOpaqueValue() const;
- bool operator==(const TypeCoupledDeclRefInfo &Other) const;
- void setFromOpaqueValue(void *V);
-};
-
-/// [BoundsSafety] Represents a parent type class for CountAttributedType and
-/// similar sugar types that will be introduced to represent a type with a
-/// bounds attribute.
-///
-/// Provides a common interface to navigate declarations referred to by the
-/// bounds expression.
-
-class BoundsAttributedType : public Type, public llvm::FoldingSetNode {
- QualType WrappedTy;
-
-protected:
- ArrayRef<TypeCoupledDeclRefInfo> Decls; // stored in trailing objects
-
- BoundsAttributedType(TypeClass TC, QualType Wrapped, QualType Canon);
-
-public:
- bool isSugared() const { return true; }
- QualType desugar() const { return WrappedTy; }
-
- using decl_iterator = const TypeCoupledDeclRefInfo *;
- using decl_range = llvm::iterator_range<decl_iterator>;
-
- decl_iterator dependent_decl_begin() const { return Decls.begin(); }
- decl_iterator dependent_decl_end() const { return Decls.end(); }
-
- unsigned getNumCoupledDecls() const { return Decls.size(); }
-
- decl_range dependent_decls() const {
- return decl_range(dependent_decl_begin(), dependent_decl_end());
- }
-
- ArrayRef<TypeCoupledDeclRefInfo> getCoupledDecls() const {
- return {dependent_decl_begin(), dependent_decl_end()};
- }
-
- bool referencesFieldDecls() const;
-
- static bool classof(const Type *T) {
- // Currently, only `class CountAttributedType` inherits
- // `BoundsAttributedType` but the subclass will grow as we add more bounds
- // annotations.
- switch (T->getTypeClass()) {
- case CountAttributed:
- return true;
- default:
- return false;
- }
- }
-};
-
-/// Represents a sugar type with `__counted_by` or `__sized_by` annotations,
-/// including their `_or_null` variants.
-class CountAttributedType final
- : public BoundsAttributedType,
- public llvm::TrailingObjects<CountAttributedType,
- TypeCoupledDeclRefInfo> {
- friend class ASTContext;
-
- Expr *CountExpr;
- /// \p CountExpr represents the argument of __counted_by or the likes. \p
- /// CountInBytes indicates that \p CountExpr is a byte count (i.e.,
- /// __sized_by(_or_null)) \p OrNull means it's an or_null variant (i.e.,
- /// __counted_by_or_null or __sized_by_or_null) \p CoupledDecls contains the
- /// list of declarations referenced by \p CountExpr, which the type depends on
- /// for the bounds information.
- CountAttributedType(QualType Wrapped, QualType Canon, Expr *CountExpr,
- bool CountInBytes, bool OrNull,
- ArrayRef<TypeCoupledDeclRefInfo> CoupledDecls);
-
- unsigned numTrailingObjects(OverloadToken<TypeCoupledDeclRefInfo>) const {
- return CountAttributedTypeBits.NumCoupledDecls;
- }
-
-public:
- enum DynamicCountPointerKind {
- CountedBy = 0,
- SizedBy,
- CountedByOrNull,
- SizedByOrNull,
- };
-
- Expr *getCountExpr() const { return CountExpr; }
- bool isCountInBytes() const { return CountAttributedTypeBits.CountInBytes; }
- bool isOrNull() const { return CountAttributedTypeBits.OrNull; }
-
- DynamicCountPointerKind getKind() const {
- if (isOrNull())
- return isCountInBytes() ? SizedByOrNull : CountedByOrNull;
- return isCountInBytes() ? SizedBy : CountedBy;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, desugar(), CountExpr, isCountInBytes(), isOrNull());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType WrappedTy,
- Expr *CountExpr, bool CountInBytes, bool Nullable);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == CountAttributed;
- }
-
- StringRef getAttributeName(bool WithMacroPrefix) const;
-};
-
-/// Represents a type which was implicitly adjusted by the semantic
-/// engine for arbitrary reasons. For example, array and function types can
-/// decay, and function types can have their calling conventions adjusted.
-class AdjustedType : public Type, public llvm::FoldingSetNode {
- QualType OriginalTy;
- QualType AdjustedTy;
-
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy,
- QualType CanonicalPtr)
- : Type(TC, CanonicalPtr, OriginalTy->getDependence()),
- OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {}
-
-public:
- QualType getOriginalType() const { return OriginalTy; }
- QualType getAdjustedType() const { return AdjustedTy; }
-
- bool isSugared() const { return true; }
- QualType desugar() const { return AdjustedTy; }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, OriginalTy, AdjustedTy);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) {
- ID.AddPointer(Orig.getAsOpaquePtr());
- ID.AddPointer(New.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed;
- }
-};
-
-/// Represents a pointer type decayed from an array or function type.
-class DecayedType : public AdjustedType {
- friend class ASTContext; // ASTContext creates these.
-
- inline
- DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical);
-
-public:
- QualType getDecayedType() const { return getAdjustedType(); }
-
- inline QualType getPointeeType() const;
-
- static bool classof(const Type *T) { return T->getTypeClass() == Decayed; }
-};
-
-/// Pointer to a block type.
-/// This type is to represent types syntactically represented as
-/// "void (^)(int)", etc. Pointee is required to always be a function type.
-class BlockPointerType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- // Block is some kind of pointer type
- QualType PointeeType;
-
- BlockPointerType(QualType Pointee, QualType CanonicalCls)
- : Type(BlockPointer, CanonicalCls, Pointee->getDependence()),
- PointeeType(Pointee) {}
-
-public:
- // Get the pointee type. Pointee is required to always be a function type.
- QualType getPointeeType() const { return PointeeType; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
- ID.AddPointer(Pointee.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == BlockPointer;
- }
-};
-
-/// Base for LValueReferenceType and RValueReferenceType
-class ReferenceType : public Type, public llvm::FoldingSetNode {
- QualType PointeeType;
-
-protected:
- ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef,
- bool SpelledAsLValue)
- : Type(tc, CanonicalRef, Referencee->getDependence()),
- PointeeType(Referencee) {
- ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue;
- ReferenceTypeBits.InnerRef = Referencee->isReferenceType();
- }
-
-public:
- bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; }
- bool isInnerRef() const { return ReferenceTypeBits.InnerRef; }
-
- QualType getPointeeTypeAsWritten() const { return PointeeType; }
-
- QualType getPointeeType() const {
- // FIXME: this might strip inner qualifiers; okay?
- const ReferenceType *T = this;
- while (T->isInnerRef())
- T = T->PointeeType->castAs<ReferenceType>();
- return T->PointeeType;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, PointeeType, isSpelledAsLValue());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID,
- QualType Referencee,
- bool SpelledAsLValue) {
- ID.AddPointer(Referencee.getAsOpaquePtr());
- ID.AddBoolean(SpelledAsLValue);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == LValueReference ||
- T->getTypeClass() == RValueReference;
- }
-};
-
-/// An lvalue reference type, per C++11 [dcl.ref].
-class LValueReferenceType : public ReferenceType {
- friend class ASTContext; // ASTContext creates these
-
- LValueReferenceType(QualType Referencee, QualType CanonicalRef,
- bool SpelledAsLValue)
- : ReferenceType(LValueReference, Referencee, CanonicalRef,
- SpelledAsLValue) {}
-
-public:
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == LValueReference;
- }
-};
-
-/// An rvalue reference type, per C++11 [dcl.ref].
-class RValueReferenceType : public ReferenceType {
- friend class ASTContext; // ASTContext creates these
-
- RValueReferenceType(QualType Referencee, QualType CanonicalRef)
- : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {}
-
-public:
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == RValueReference;
- }
-};
-
-/// A pointer to member type per C++ 8.3.3 - Pointers to members.
-///
-/// This includes both pointers to data members and pointer to member functions.
-class MemberPointerType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType PointeeType;
-
- /// The class of which the pointee is a member. Must ultimately be a
- /// CXXRecordType, but could be a typedef or a template parameter too.
- NestedNameSpecifier *Qualifier;
-
- MemberPointerType(QualType Pointee, NestedNameSpecifier *Qualifier,
- QualType CanonicalPtr)
- : Type(MemberPointer, CanonicalPtr,
- (toTypeDependence(Qualifier->getDependence()) &
- ~TypeDependence::VariablyModified) |
- Pointee->getDependence()),
- PointeeType(Pointee), Qualifier(Qualifier) {}
-
-public:
- QualType getPointeeType() const { return PointeeType; }
-
- /// Returns true if the member type (i.e. the pointee type) is a
- /// function type rather than a data-member type.
- bool isMemberFunctionPointer() const {
- return PointeeType->isFunctionProtoType();
- }
-
- /// Returns true if the member type (i.e. the pointee type) is a
- /// data type rather than a function type.
- bool isMemberDataPointer() const {
- return !PointeeType->isFunctionProtoType();
- }
-
- NestedNameSpecifier *getQualifier() const { return Qualifier; }
- /// Note: this can trigger extra deserialization when external AST sources are
- /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent
- /// decl.
- CXXRecordDecl *getMostRecentCXXRecordDecl() const;
-
- bool isSugared() const;
- QualType desugar() const {
- return isSugared() ? getCanonicalTypeInternal() : QualType(this, 0);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- // FIXME: `getMostRecentCXXRecordDecl()` should be possible to use here,
- // however when external AST sources are used it causes nondeterminism
- // issues (see https://github.com/llvm/llvm-project/pull/137910).
- Profile(ID, getPointeeType(), getQualifier(), getCXXRecordDecl());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
- const NestedNameSpecifier *Qualifier,
- const CXXRecordDecl *Cls);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == MemberPointer;
- }
-
-private:
- CXXRecordDecl *getCXXRecordDecl() const;
-};
-
-/// Capture whether this is a normal array (e.g. int X[4])
-/// an array with a static size (e.g. int X[static 4]), or an array
-/// with a star size (e.g. int X[*]).
-/// 'static' is only allowed on function parameters.
-enum class ArraySizeModifier { Normal, Static, Star };
-
-/// Represents an array type, per C99 6.7.5.2 - Array Declarators.
-class ArrayType : public Type, public llvm::FoldingSetNode {
-private:
- /// The element type of the array.
- QualType ElementType;
-
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm,
- unsigned tq, const Expr *sz = nullptr);
-
-public:
- QualType getElementType() const { return ElementType; }
-
- ArraySizeModifier getSizeModifier() const {
- return ArraySizeModifier(ArrayTypeBits.SizeModifier);
- }
-
- Qualifiers getIndexTypeQualifiers() const {
- return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers());
- }
-
- unsigned getIndexTypeCVRQualifiers() const {
- return ArrayTypeBits.IndexTypeQuals;
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ConstantArray ||
- T->getTypeClass() == VariableArray ||
- T->getTypeClass() == IncompleteArray ||
- T->getTypeClass() == DependentSizedArray ||
- T->getTypeClass() == ArrayParameter;
- }
-};
-
-/// Represents the canonical version of C arrays with a specified constant size.
-/// For example, the canonical type for 'int A[4 + 4*100]' is a
-/// ConstantArrayType where the element type is 'int' and the size is 404.
-class ConstantArrayType : public ArrayType {
- friend class ASTContext; // ASTContext creates these.
-
- struct ExternalSize {
- ExternalSize(const llvm::APInt &Sz, const Expr *SE)
- : Size(Sz), SizeExpr(SE) {}
- llvm::APInt Size; // Allows us to unique the type.
- const Expr *SizeExpr;
- };
-
- union {
- uint64_t Size;
- ExternalSize *SizePtr;
- };
-
- ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz,
- ArraySizeModifier SM, unsigned TQ)
- : ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) {
- ConstantArrayTypeBits.HasExternalSize = false;
- ConstantArrayTypeBits.SizeWidth = Width / 8;
- // The in-structure size stores the size in bytes rather than bits so we
- // drop the three least significant bits since they're always zero anyways.
- assert(Width < 0xFF && "Type width in bits must be less than 8 bits");
- }
-
- ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr,
- ArraySizeModifier SM, unsigned TQ)
- : ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr),
- SizePtr(SzPtr) {
- ConstantArrayTypeBits.HasExternalSize = true;
- ConstantArrayTypeBits.SizeWidth = 0;
-
- assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) &&
- "canonical constant array should not have size expression");
- }
-
- static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET,
- QualType Can, const llvm::APInt &Sz,
- const Expr *SzExpr, ArraySizeModifier SzMod,
- unsigned Qual);
-
-protected:
- ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can)
- : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(),
- ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) {
- ConstantArrayTypeBits.HasExternalSize =
- ATy->ConstantArrayTypeBits.HasExternalSize;
- if (!ConstantArrayTypeBits.HasExternalSize) {
- ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth;
- Size = ATy->Size;
- } else
- SizePtr = ATy->SizePtr;
- }
-
-public:
- /// Return the constant array size as an APInt.
- llvm::APInt getSize() const {
- return ConstantArrayTypeBits.HasExternalSize
- ? SizePtr->Size
- : llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size);
- }
-
- /// Return the bit width of the size type.
- unsigned getSizeBitWidth() const {
- return ConstantArrayTypeBits.HasExternalSize
- ? SizePtr->Size.getBitWidth()
- : static_cast<unsigned>(ConstantArrayTypeBits.SizeWidth * 8);
- }
-
- /// Return true if the size is zero.
- bool isZeroSize() const {
- return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero()
- : 0 == Size;
- }
-
- /// Return the size zero-extended as a uint64_t.
- uint64_t getZExtSize() const {
- return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue()
- : Size;
- }
-
- /// Return the size sign-extended as a uint64_t.
- int64_t getSExtSize() const {
- return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue()
- : static_cast<int64_t>(Size);
- }
-
- /// Return the size zero-extended to uint64_t or UINT64_MAX if the value is
- /// larger than UINT64_MAX.
- uint64_t getLimitedSize() const {
- return ConstantArrayTypeBits.HasExternalSize
- ? SizePtr->Size.getLimitedValue()
- : Size;
- }
-
- /// Return a pointer to the size expression.
- const Expr *getSizeExpr() const {
- return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- /// Determine the number of bits required to address a member of
- // an array with the given element type and number of elements.
- static unsigned getNumAddressingBits(const ASTContext &Context,
- QualType ElementType,
- const llvm::APInt &NumElements);
-
- unsigned getNumAddressingBits(const ASTContext &Context) const;
-
- /// Determine the maximum number of active bits that an array's size
- /// can require, which limits the maximum size of the array.
- static unsigned getMaxSizeBits(const ASTContext &Context);
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
- Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(),
- getSizeModifier(), getIndexTypeCVRQualifiers());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
- QualType ET, uint64_t ArraySize, const Expr *SizeExpr,
- ArraySizeModifier SizeMod, unsigned TypeQuals);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ConstantArray ||
- T->getTypeClass() == ArrayParameter;
- }
-};
-
-/// Represents a constant array type that does not decay to a pointer when used
-/// as a function parameter.
-class ArrayParameterType : public ConstantArrayType {
- friend class ASTContext; // ASTContext creates these.
-
- ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy)
- : ConstantArrayType(ArrayParameter, ATy, CanTy) {}
-
-public:
- static bool classof(const Type *T) {
- return T->getTypeClass() == ArrayParameter;
- }
-
- QualType getConstantArrayType(const ASTContext &Ctx) const;
-};
-
-/// Represents a C array with an unspecified size. For example 'int A[]' has
-/// an IncompleteArrayType where the element type is 'int' and the size is
-/// unspecified.
-class IncompleteArrayType : public ArrayType {
- friend class ASTContext; // ASTContext creates these.
-
- IncompleteArrayType(QualType et, QualType can,
- ArraySizeModifier sm, unsigned tq)
- : ArrayType(IncompleteArray, et, can, sm, tq) {}
-
-public:
- friend class StmtIteratorBase;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == IncompleteArray;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getSizeModifier(),
- getIndexTypeCVRQualifiers());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
- ArraySizeModifier SizeMod, unsigned TypeQuals) {
- ID.AddPointer(ET.getAsOpaquePtr());
- ID.AddInteger(llvm::to_underlying(SizeMod));
- ID.AddInteger(TypeQuals);
- }
-};
-
-/// Represents a C array with a specified size that is not an
-/// integer-constant-expression. For example, 'int s[x+foo()]'.
-/// Since the size expression is an arbitrary expression, we store it as such.
-///
-/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and
-/// should not be: two lexically equivalent variable array types could mean
-/// different things, for example, these variables do not have the same type
-/// dynamically:
-///
-/// void foo(int x) {
-/// int Y[x];
-/// ++x;
-/// int Z[x];
-/// }
-///
-/// FIXME: Even constant array types might be represented by a
-/// VariableArrayType, as in:
-///
-/// void func(int n) {
-/// int array[7][n];
-/// }
-///
-/// Even though 'array' is a constant-size array of seven elements of type
-/// variable-length array of size 'n', it will be represented as a
-/// VariableArrayType whose 'SizeExpr' is an IntegerLiteral whose value is 7.
-/// Instead, this should be a ConstantArrayType whose element is a
-/// VariableArrayType, which models the type better.
-class VariableArrayType : public ArrayType {
- friend class ASTContext; // ASTContext creates these.
-
- /// An assignment-expression. VLA's are only permitted within
- /// a function block.
- Stmt *SizeExpr;
-
- VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm,
- unsigned tq)
- : ArrayType(VariableArray, et, can, sm, tq, e), SizeExpr((Stmt *)e) {}
-
-public:
- friend class StmtIteratorBase;
-
- Expr *getSizeExpr() const {
- // We use C-style casts instead of cast<> here because we do not wish
- // to have a dependency of Type.h on Stmt.h/Expr.h.
- return (Expr*) SizeExpr;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == VariableArray;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- llvm_unreachable("Cannot unique VariableArrayTypes.");
- }
-};
-
-/// Represents an array type in C++ whose size is a value-dependent expression.
-///
-/// For example:
-/// \code
-/// template<typename T, int Size>
-/// class array {
-/// T data[Size];
-/// };
-/// \endcode
-///
-/// For these types, we won't actually know what the array bound is
-/// until template instantiation occurs, at which point this will
-/// become either a ConstantArrayType or a VariableArrayType.
-class DependentSizedArrayType : public ArrayType {
- friend class ASTContext; // ASTContext creates these.
-
- /// An assignment expression that will instantiate to the
- /// size of the array.
- ///
- /// The expression itself might be null, in which case the array
- /// type will have its size deduced from an initializer.
- Stmt *SizeExpr;
-
- DependentSizedArrayType(QualType et, QualType can, Expr *e,
- ArraySizeModifier sm, unsigned tq);
-
-public:
- friend class StmtIteratorBase;
-
- Expr *getSizeExpr() const {
- // We use C-style casts instead of cast<> here because we do not wish
- // to have a dependency of Type.h on Stmt.h/Expr.h.
- return (Expr*) SizeExpr;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentSizedArray;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getElementType(),
- getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType ET, ArraySizeModifier SizeMod,
- unsigned TypeQuals, Expr *E);
-};
-
-/// Represents an extended address space qualifier where the input address space
-/// value is dependent. Non-dependent address spaces are not represented with a
-/// special Type subclass; they are stored on an ExtQuals node as part of a QualType.
-///
-/// For example:
-/// \code
-/// template<typename T, int AddrSpace>
-/// class AddressSpace {
-/// typedef T __attribute__((address_space(AddrSpace))) type;
-/// }
-/// \endcode
-class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
-
- Expr *AddrSpaceExpr;
- QualType PointeeType;
- SourceLocation loc;
-
- DependentAddressSpaceType(QualType PointeeType, QualType can,
- Expr *AddrSpaceExpr, SourceLocation loc);
-
-public:
- Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; }
- QualType getPointeeType() const { return PointeeType; }
- SourceLocation getAttributeLoc() const { return loc; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentAddressSpace;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getPointeeType(), getAddrSpaceExpr());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType PointeeType, Expr *AddrSpaceExpr);
-};
-
-/// Represents an extended vector type where either the type or size is
-/// dependent.
-///
-/// For example:
-/// \code
-/// template<typename T, int Size>
-/// class vector {
-/// typedef T __attribute__((ext_vector_type(Size))) type;
-/// }
-/// \endcode
-class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
-
- Expr *SizeExpr;
-
- /// The element type of the array.
- QualType ElementType;
-
- SourceLocation loc;
-
- DependentSizedExtVectorType(QualType ElementType, QualType can,
- Expr *SizeExpr, SourceLocation loc);
-
-public:
- Expr *getSizeExpr() const { return SizeExpr; }
- QualType getElementType() const { return ElementType; }
- SourceLocation getAttributeLoc() const { return loc; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentSizedExtVector;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getElementType(), getSizeExpr());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType ElementType, Expr *SizeExpr);
-};
-
-enum class VectorKind {
- /// not a target-specific vector type
- Generic,
-
- /// is AltiVec vector
- AltiVecVector,
-
- /// is AltiVec 'vector Pixel'
- AltiVecPixel,
-
- /// is AltiVec 'vector bool ...'
- AltiVecBool,
-
- /// is ARM Neon vector
- Neon,
-
- /// is ARM Neon polynomial vector
- NeonPoly,
-
- /// is AArch64 SVE fixed-length data vector
- SveFixedLengthData,
-
- /// is AArch64 SVE fixed-length predicate vector
- SveFixedLengthPredicate,
-
- /// is RISC-V RVV fixed-length data vector
- RVVFixedLengthData,
-
- /// is RISC-V RVV fixed-length mask vector
- RVVFixedLengthMask,
-
- RVVFixedLengthMask_1,
- RVVFixedLengthMask_2,
- RVVFixedLengthMask_4
-};
-
-/// Represents a GCC generic vector type. This type is created using
-/// __attribute__((vector_size(n)), where "n" specifies the vector size in
-/// bytes; or from an Altivec __vector or vector declaration.
-/// Since the constructor takes the number of vector elements, the
-/// client is responsible for converting the size into the number of elements.
-class VectorType : public Type, public llvm::FoldingSetNode {
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- /// The element type of the vector.
- QualType ElementType;
-
- VectorType(QualType vecType, unsigned nElements, QualType canonType,
- VectorKind vecKind);
-
- VectorType(TypeClass tc, QualType vecType, unsigned nElements,
- QualType canonType, VectorKind vecKind);
-
-public:
- QualType getElementType() const { return ElementType; }
- unsigned getNumElements() const { return VectorTypeBits.NumElements; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- VectorKind getVectorKind() const {
- return VectorKind(VectorTypeBits.VecKind);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getNumElements(),
- getTypeClass(), getVectorKind());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
- unsigned NumElements, TypeClass TypeClass,
- VectorKind VecKind) {
- ID.AddPointer(ElementType.getAsOpaquePtr());
- ID.AddInteger(NumElements);
- ID.AddInteger(TypeClass);
- ID.AddInteger(llvm::to_underlying(VecKind));
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
- }
-};
-
-/// Represents a vector type where either the type or size is dependent.
-////
-/// For example:
-/// \code
-/// template<typename T, int Size>
-/// class vector {
-/// typedef T __attribute__((vector_size(Size))) type;
-/// }
-/// \endcode
-class DependentVectorType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
-
- QualType ElementType;
- Expr *SizeExpr;
- SourceLocation Loc;
-
- DependentVectorType(QualType ElementType, QualType CanonType, Expr *SizeExpr,
- SourceLocation Loc, VectorKind vecKind);
-
-public:
- Expr *getSizeExpr() const { return SizeExpr; }
- QualType getElementType() const { return ElementType; }
- SourceLocation getAttributeLoc() const { return Loc; }
- VectorKind getVectorKind() const {
- return VectorKind(VectorTypeBits.VecKind);
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentVector;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType ElementType, const Expr *SizeExpr,
- VectorKind VecKind);
-};
-
-/// ExtVectorType - Extended vector type. This type is created using
-/// __attribute__((ext_vector_type(n)), where "n" is the number of elements.
-/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This
-/// class enables syntactic extensions, like Vector Components for accessing
-/// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL
-/// Shading Language).
-class ExtVectorType : public VectorType {
- friend class ASTContext; // ASTContext creates these.
-
- ExtVectorType(QualType vecType, unsigned nElements, QualType canonType)
- : VectorType(ExtVector, vecType, nElements, canonType,
- VectorKind::Generic) {}
-
-public:
- static int getPointAccessorIdx(char c) {
- switch (c) {
- default: return -1;
- case 'x': case 'r': return 0;
- case 'y': case 'g': return 1;
- case 'z': case 'b': return 2;
- case 'w': case 'a': return 3;
- }
- }
-
- static int getNumericAccessorIdx(char c) {
- switch (c) {
- default: return -1;
- case '0': return 0;
- case '1': return 1;
- case '2': return 2;
- case '3': return 3;
- case '4': return 4;
- case '5': return 5;
- case '6': return 6;
- case '7': return 7;
- case '8': return 8;
- case '9': return 9;
- case 'A':
- case 'a': return 10;
- case 'B':
- case 'b': return 11;
- case 'C':
- case 'c': return 12;
- case 'D':
- case 'd': return 13;
- case 'E':
- case 'e': return 14;
- case 'F':
- case 'f': return 15;
- }
- }
-
- static int getAccessorIdx(char c, bool isNumericAccessor) {
- if (isNumericAccessor)
- return getNumericAccessorIdx(c);
- else
- return getPointAccessorIdx(c);
- }
-
- bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const {
- if (int idx = getAccessorIdx(c, isNumericAccessor)+1)
- return unsigned(idx-1) < getNumElements();
- return false;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ExtVector;
- }
-};
-
-/// Represents a matrix type, as defined in the Matrix Types clang extensions.
-/// __attribute__((matrix_type(rows, columns))), where "rows" specifies
-/// number of rows and "columns" specifies the number of columns.
-class MatrixType : public Type, public llvm::FoldingSetNode {
-protected:
- friend class ASTContext;
-
- /// The element type of the matrix.
- QualType ElementType;
-
- MatrixType(QualType ElementTy, QualType CanonElementTy);
-
- MatrixType(TypeClass TypeClass, QualType ElementTy, QualType CanonElementTy,
- const Expr *RowExpr = nullptr, const Expr *ColumnExpr = nullptr);
-
-public:
- /// Returns type of the elements being stored in the matrix
- QualType getElementType() const { return ElementType; }
-
- /// Valid elements types are the following:
- /// * an integer type (as in C23 6.2.5p22), but excluding enumerated types
- /// and _Bool
- /// * the standard floating types float or double
- /// * a half-precision floating point type, if one is supported on the target
- static bool isValidElementType(QualType T) {
- return T->isDependentType() ||
- (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType());
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ConstantMatrix ||
- T->getTypeClass() == DependentSizedMatrix;
- }
-};
-
-/// Represents a concrete matrix type with constant number of rows and columns
-class ConstantMatrixType final : public MatrixType {
-protected:
- friend class ASTContext;
-
- /// Number of rows and columns.
- unsigned NumRows;
- unsigned NumColumns;
-
- static constexpr unsigned MaxElementsPerDimension = (1 << 20) - 1;
-
- ConstantMatrixType(QualType MatrixElementType, unsigned NRows,
- unsigned NColumns, QualType CanonElementType);
-
- ConstantMatrixType(TypeClass typeClass, QualType MatrixType, unsigned NRows,
- unsigned NColumns, QualType CanonElementType);
-
-public:
- /// Returns the number of rows in the matrix.
- unsigned getNumRows() const { return NumRows; }
-
- /// Returns the number of columns in the matrix.
- unsigned getNumColumns() const { return NumColumns; }
-
- /// Returns the number of elements required to embed the matrix into a vector.
- unsigned getNumElementsFlattened() const {
- return getNumRows() * getNumColumns();
- }
-
- /// Returns true if \p NumElements is a valid matrix dimension.
- static constexpr bool isDimensionValid(size_t NumElements) {
- return NumElements > 0 && NumElements <= MaxElementsPerDimension;
- }
-
- /// Returns the maximum number of elements per dimension.
- static constexpr unsigned getMaxElementsPerDimension() {
- return MaxElementsPerDimension;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getNumRows(), getNumColumns(),
- getTypeClass());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
- unsigned NumRows, unsigned NumColumns,
- TypeClass TypeClass) {
- ID.AddPointer(ElementType.getAsOpaquePtr());
- ID.AddInteger(NumRows);
- ID.AddInteger(NumColumns);
- ID.AddInteger(TypeClass);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ConstantMatrix;
- }
-};
-
-/// Represents a matrix type where the type and the number of rows and columns
-/// is dependent on a template.
-class DependentSizedMatrixType final : public MatrixType {
- friend class ASTContext;
-
- Expr *RowExpr;
- Expr *ColumnExpr;
-
- SourceLocation loc;
-
- DependentSizedMatrixType(QualType ElementType, QualType CanonicalType,
- Expr *RowExpr, Expr *ColumnExpr, SourceLocation loc);
-
-public:
- Expr *getRowExpr() const { return RowExpr; }
- Expr *getColumnExpr() const { return ColumnExpr; }
- SourceLocation getAttributeLoc() const { return loc; }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentSizedMatrix;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getElementType(), getRowExpr(), getColumnExpr());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType ElementType, Expr *RowExpr, Expr *ColumnExpr);
-};
-
-/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
-/// class of FunctionNoProtoType and FunctionProtoType.
-class FunctionType : public Type {
- // The type returned by the function.
- QualType ResultType;
-
-public:
- /// Interesting information about a specific parameter that can't simply
- /// be reflected in parameter's type. This is only used by FunctionProtoType
- /// but is in FunctionType to make this class available during the
- /// specification of the bases of FunctionProtoType.
- ///
- /// It makes sense to model language features this way when there's some
- /// sort of parameter-specific override (such as an attribute) that
- /// affects how the function is called. For example, the ARC ns_consumed
- /// attribute changes whether a parameter is passed at +0 (the default)
- /// or +1 (ns_consumed). This must be reflected in the function type,
- /// but isn't really a change to the parameter type.
- ///
- /// One serious disadvantage of modelling language features this way is
- /// that they generally do not work with language features that attempt
- /// to destructure types. For example, template argument deduction will
- /// not be able to match a parameter declared as
- /// T (*)(U)
- /// against an argument of type
- /// void (*)(__attribute__((ns_consumed)) id)
- /// because the substitution of T=void, U=id into the former will
- /// not produce the latter.
- class ExtParameterInfo {
- enum {
- ABIMask = 0x0F,
- IsConsumed = 0x10,
- HasPassObjSize = 0x20,
- IsNoEscape = 0x40,
- };
- unsigned char Data = 0;
-
- public:
- ExtParameterInfo() = default;
-
- /// Return the ABI treatment of this parameter.
- ParameterABI getABI() const { return ParameterABI(Data & ABIMask); }
- ExtParameterInfo withABI(ParameterABI kind) const {
- ExtParameterInfo copy = *this;
- copy.Data = (copy.Data & ~ABIMask) | unsigned(kind);
- return copy;
- }
-
- /// Is this parameter considered "consumed" by Objective-C ARC?
- /// Consumed parameters must have retainable object type.
- bool isConsumed() const { return (Data & IsConsumed); }
- ExtParameterInfo withIsConsumed(bool consumed) const {
- ExtParameterInfo copy = *this;
- if (consumed)
- copy.Data |= IsConsumed;
- else
- copy.Data &= ~IsConsumed;
- return copy;
- }
-
- bool hasPassObjectSize() const { return Data & HasPassObjSize; }
- ExtParameterInfo withHasPassObjectSize() const {
- ExtParameterInfo Copy = *this;
- Copy.Data |= HasPassObjSize;
- return Copy;
- }
-
- bool isNoEscape() const { return Data & IsNoEscape; }
- ExtParameterInfo withIsNoEscape(bool NoEscape) const {
- ExtParameterInfo Copy = *this;
- if (NoEscape)
- Copy.Data |= IsNoEscape;
- else
- Copy.Data &= ~IsNoEscape;
- return Copy;
- }
-
- unsigned char getOpaqueValue() const { return Data; }
- static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
- ExtParameterInfo result;
- result.Data = data;
- return result;
- }
-
- friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) {
- return lhs.Data == rhs.Data;
- }
-
- friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) {
- return lhs.Data != rhs.Data;
- }
- };
-
- /// A class which abstracts out some details necessary for
- /// making a call.
- ///
- /// It is not actually used directly for storing this information in
- /// a FunctionType, although FunctionType does currently use the
- /// same bit-pattern.
- ///
- // If you add a field (say Foo), other than the obvious places (both,
- // constructors, compile failures), what you need to update is
- // * Operator==
- // * getFoo
- // * withFoo
- // * functionType. Add Foo, getFoo.
- // * ASTContext::getFooType
- // * ASTContext::mergeFunctionTypes
- // * FunctionNoProtoType::Profile
- // * FunctionProtoType::Profile
- // * TypePrinter::PrintFunctionProto
- // * AST read and write
- // * Codegen
- class ExtInfo {
- friend class FunctionType;
-
- // Feel free to rearrange or add bits, but if you go over 16, you'll need to
- // adjust the Bits field below, and if you add bits, you'll need to adjust
- // Type::FunctionTypeBitfields::ExtInfo as well.
-
- // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall|
- // |0 .. 5| 6 | 7 | 8 |9 .. 11| 12 | 13 |
- //
- // regparm is either 0 (no regparm attribute) or the regparm value+1.
- enum { CallConvMask = 0x3F };
- enum { NoReturnMask = 0x40 };
- enum { ProducesResultMask = 0x80 };
- enum { NoCallerSavedRegsMask = 0x100 };
- enum { RegParmMask = 0xe00, RegParmOffset = 9 };
- enum { NoCfCheckMask = 0x1000 };
- enum { CmseNSCallMask = 0x2000 };
- uint16_t Bits = CC_C;
-
- ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {}
-
- public:
- // Constructor with no defaults. Use this when you know that you
- // have all the elements (when reading an AST file for example).
- ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
- bool producesResult, bool noCallerSavedRegs, bool NoCfCheck,
- bool cmseNSCall) {
- assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
- Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
- (producesResult ? ProducesResultMask : 0) |
- (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
- (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) |
- (NoCfCheck ? NoCfCheckMask : 0) |
- (cmseNSCall ? CmseNSCallMask : 0);
- }
-
- // Constructor with all defaults. Use when for example creating a
- // function known to use defaults.
- ExtInfo() = default;
-
- // Constructor with just the calling convention, which is an important part
- // of the canonical type.
- ExtInfo(CallingConv CC) : Bits(CC) {}
-
- bool getNoReturn() const { return Bits & NoReturnMask; }
- bool getProducesResult() const { return Bits & ProducesResultMask; }
- bool getCmseNSCall() const { return Bits & CmseNSCallMask; }
- bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
- bool getNoCfCheck() const { return Bits & NoCfCheckMask; }
- bool getHasRegParm() const { return ((Bits & RegParmMask) >> RegParmOffset) != 0; }
-
- unsigned getRegParm() const {
- unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset;
- if (RegParm > 0)
- --RegParm;
- return RegParm;
- }
-
- CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
-
- bool operator==(ExtInfo Other) const {
- return Bits == Other.Bits;
- }
- bool operator!=(ExtInfo Other) const {
- return Bits != Other.Bits;
- }
-
- // Note that we don't have setters. That is by design, use
- // the following with methods instead of mutating these objects.
-
- ExtInfo withNoReturn(bool noReturn) const {
- if (noReturn)
- return ExtInfo(Bits | NoReturnMask);
- else
- return ExtInfo(Bits & ~NoReturnMask);
- }
-
- ExtInfo withProducesResult(bool producesResult) const {
- if (producesResult)
- return ExtInfo(Bits | ProducesResultMask);
- else
- return ExtInfo(Bits & ~ProducesResultMask);
- }
-
- ExtInfo withCmseNSCall(bool cmseNSCall) const {
- if (cmseNSCall)
- return ExtInfo(Bits | CmseNSCallMask);
- else
- return ExtInfo(Bits & ~CmseNSCallMask);
- }
-
- ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const {
- if (noCallerSavedRegs)
- return ExtInfo(Bits | NoCallerSavedRegsMask);
- else
- return ExtInfo(Bits & ~NoCallerSavedRegsMask);
- }
-
- ExtInfo withNoCfCheck(bool noCfCheck) const {
- if (noCfCheck)
- return ExtInfo(Bits | NoCfCheckMask);
- else
- return ExtInfo(Bits & ~NoCfCheckMask);
- }
-
- ExtInfo withRegParm(unsigned RegParm) const {
- assert(RegParm < 7 && "Invalid regparm value");
- return ExtInfo((Bits & ~RegParmMask) |
- ((RegParm + 1) << RegParmOffset));
- }
-
- ExtInfo withCallingConv(CallingConv cc) const {
- return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(Bits);
- }
- };
-
- /// A simple holder for a QualType representing a type in an
- /// exception specification. Unfortunately needed by FunctionProtoType
- /// because TrailingObjects cannot handle repeated types.
- struct ExceptionType { QualType Type; };
-
- /// A simple holder for various uncommon bits which do not fit in
- /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
- /// alignment of subsequent objects in TrailingObjects.
- struct alignas(void *) FunctionTypeExtraBitfields {
- /// The number of types in the exception specification.
- /// A whole unsigned is not needed here and according to
- /// [implimits] 8 bits would be enough here.
- unsigned NumExceptionType : 10;
-
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasArmTypeAttributes : 1;
-
- LLVM_PREFERRED_TYPE(bool)
- unsigned EffectsHaveConditions : 1;
- unsigned NumFunctionEffects : 4;
-
- FunctionTypeExtraBitfields()
- : NumExceptionType(0), HasArmTypeAttributes(false),
- EffectsHaveConditions(false), NumFunctionEffects(0) {}
- };
-
- /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number
- /// of function type attributes that can be set on function types, including
- /// function pointers.
- enum AArch64SMETypeAttributes : unsigned {
- SME_NormalFunction = 0,
- SME_PStateSMEnabledMask = 1 << 0,
- SME_PStateSMCompatibleMask = 1 << 1,
-
- // Describes the value of the state using ArmStateValue.
- SME_ZAShift = 2,
- SME_ZAMask = 0b111 << SME_ZAShift,
- SME_ZT0Shift = 5,
- SME_ZT0Mask = 0b111 << SME_ZT0Shift,
-
- // A bit to tell whether a function is agnostic about sme ZA state.
- SME_AgnosticZAStateShift = 8,
- SME_AgnosticZAStateMask = 1 << SME_AgnosticZAStateShift,
-
- SME_AttributeMask =
- 0b1'111'111'11 // We can't support more than 9 bits because of
- // the bitmask in FunctionTypeArmAttributes
- // and ExtProtoInfo.
- };
-
- enum ArmStateValue : unsigned {
- ARM_None = 0,
- ARM_Preserves = 1,
- ARM_In = 2,
- ARM_Out = 3,
- ARM_InOut = 4,
- };
-
- static ArmStateValue getArmZAState(unsigned AttrBits) {
- return (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift);
- }
-
- static ArmStateValue getArmZT0State(unsigned AttrBits) {
- return (ArmStateValue)((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
- }
-
- /// A holder for Arm type attributes as described in the Arm C/C++
- /// Language extensions which are not particularly common to all
- /// types and therefore accounted separately from FunctionTypeBitfields.
- struct alignas(void *) FunctionTypeArmAttributes {
- /// Any AArch64 SME ACLE type attributes that need to be propagated
- /// on declarations and function pointers.
- unsigned AArch64SMEAttributes : 9;
-
- FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {}
- };
-
-protected:
- FunctionType(TypeClass tc, QualType res, QualType Canonical,
- TypeDependence Dependence, ExtInfo Info)
- : Type(tc, Canonical, Dependence), ResultType(res) {
- FunctionTypeBits.ExtInfo = Info.Bits;
- }
-
- Qualifiers getFastTypeQuals() const {
- if (isFunctionProtoType())
- return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals);
-
- return Qualifiers();
- }
-
-public:
- QualType getReturnType() const { return ResultType; }
-
- bool getHasRegParm() const { return getExtInfo().getHasRegParm(); }
- unsigned getRegParmType() const { return getExtInfo().getRegParm(); }
-
- /// Determine whether this function type includes the GNU noreturn
- /// attribute. The C++11 [[noreturn]] attribute does not affect the function
- /// type.
- bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); }
-
- /// Determine whether this is a function prototype that includes the
- /// cfi_unchecked_callee attribute.
- bool getCFIUncheckedCalleeAttr() const;
-
- bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); }
- CallingConv getCallConv() const { return getExtInfo().getCC(); }
- ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); }
-
- static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0,
- "Const, volatile and restrict are assumed to be a subset of "
- "the fast qualifiers.");
-
- bool isConst() const { return getFastTypeQuals().hasConst(); }
- bool isVolatile() const { return getFastTypeQuals().hasVolatile(); }
- bool isRestrict() const { return getFastTypeQuals().hasRestrict(); }
-
- /// Determine the type of an expression that calls a function of
- /// this type.
- QualType getCallResultType(const ASTContext &Context) const {
- return getReturnType().getNonLValueExprType(Context);
- }
-
- static StringRef getNameForCallConv(CallingConv CC);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == FunctionNoProto ||
- T->getTypeClass() == FunctionProto;
- }
-};
-
-/// Represents a K&R-style 'int foo()' function, which has
-/// no information available about its arguments.
-class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
- : FunctionType(FunctionNoProto, Result, Canonical,
- Result->getDependence() &
- ~(TypeDependence::DependentInstantiation |
- TypeDependence::UnexpandedPack),
- Info) {}
-
-public:
- // No additional state past what FunctionType provides.
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getReturnType(), getExtInfo());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
- ExtInfo Info) {
- Info.Profile(ID);
- ID.AddPointer(ResultType.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == FunctionNoProto;
- }
-};
-
-// ------------------------------------------------------------------------------
-
-/// Represents an abstract function effect, using just an enumeration describing
-/// its kind.
-class FunctionEffect {
-public:
- /// Identifies the particular effect.
- enum class Kind : uint8_t {
- NonBlocking,
- NonAllocating,
- Blocking,
- Allocating,
- Last = Allocating
- };
- constexpr static size_t KindCount = static_cast<size_t>(Kind::Last) + 1;
-
- /// Flags describing some behaviors of the effect.
- using Flags = unsigned;
- enum FlagBit : Flags {
- // Can verification inspect callees' implementations? (e.g. nonblocking:
- // yes, tcb+types: no). This also implies the need for 2nd-pass
- // verification.
- FE_InferrableOnCallees = 0x1,
-
- // Language constructs which effects can diagnose as disallowed.
- FE_ExcludeThrow = 0x2,
- FE_ExcludeCatch = 0x4,
- FE_ExcludeObjCMessageSend = 0x8,
- FE_ExcludeStaticLocalVars = 0x10,
- FE_ExcludeThreadLocalVars = 0x20
- };
-
-private:
- Kind FKind;
-
- // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
- // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
- // be considered for uniqueness.
-
-public:
- explicit FunctionEffect(Kind K) : FKind(K) {}
-
- /// The kind of the effect.
- Kind kind() const { return FKind; }
-
- /// Return the opposite kind, for effects which have opposites.
- Kind oppositeKind() const;
-
- /// For serialization.
- uint32_t toOpaqueInt32() const { return uint32_t(FKind); }
- static FunctionEffect fromOpaqueInt32(uint32_t Value) {
- return FunctionEffect(Kind(Value));
- }
-
- /// Flags describing some behaviors of the effect.
- Flags flags() const {
- switch (kind()) {
- case Kind::NonBlocking:
- return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
- FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
- FE_ExcludeThreadLocalVars;
- case Kind::NonAllocating:
- // Same as NonBlocking, except without FE_ExcludeStaticLocalVars.
- return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
- FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
- case Kind::Blocking:
- case Kind::Allocating:
- return 0;
- }
- llvm_unreachable("unknown effect kind");
- }
-
- /// The description printed in diagnostics, e.g. 'nonblocking'.
- StringRef name() const;
-
- friend raw_ostream &operator<<(raw_ostream &OS,
- const FunctionEffect &Effect) {
- OS << Effect.name();
- return OS;
- }
-
- /// Determine whether the effect is allowed to be inferred on the callee,
- /// which is either a FunctionDecl or BlockDecl. If the returned optional
- /// is empty, inference is permitted; otherwise it holds the effect which
- /// blocked inference.
- /// Example: This allows nonblocking(false) to prevent inference for the
- /// function.
- std::optional<FunctionEffect>
- effectProhibitingInference(const Decl &Callee,
- FunctionEffectKindSet CalleeFX) const;
-
- // Return false for success. When true is returned for a direct call, then the
- // FE_InferrableOnCallees flag may trigger inference rather than an immediate
- // diagnostic. Caller should be assumed to have the effect (it may not have it
- // explicitly when inferring).
- bool shouldDiagnoseFunctionCall(bool Direct,
- FunctionEffectKindSet CalleeFX) const;
-
- friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) {
- return LHS.FKind == RHS.FKind;
- }
- friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) {
- return !(LHS == RHS);
- }
- friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) {
- return LHS.FKind < RHS.FKind;
- }
-};
-
-/// Wrap a function effect's condition expression in another struct so
-/// that FunctionProtoType's TrailingObjects can treat it separately.
-class EffectConditionExpr {
- Expr *Cond = nullptr; // if null, unconditional.
-
-public:
- EffectConditionExpr() = default;
- EffectConditionExpr(Expr *E) : Cond(E) {}
-
- Expr *getCondition() const { return Cond; }
-
- bool operator==(const EffectConditionExpr &RHS) const {
- return Cond == RHS.Cond;
- }
-};
-
-/// A FunctionEffect plus a potential boolean expression determining whether
-/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
-/// expression when present, is dependent.
-struct FunctionEffectWithCondition {
- FunctionEffect Effect;
- EffectConditionExpr Cond;
-
- FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C)
- : Effect(E), Cond(C) {}
-
- /// Return a textual description of the effect, and its condition, if any.
- std::string description() const;
-
- friend raw_ostream &operator<<(raw_ostream &OS,
- const FunctionEffectWithCondition &CFE);
-};
-
-/// Support iteration in parallel through a pair of FunctionEffect and
-/// EffectConditionExpr containers.
-template <typename Container> class FunctionEffectIterator {
- friend Container;
-
- const Container *Outer = nullptr;
- size_t Idx = 0;
-
-public:
- FunctionEffectIterator();
- FunctionEffectIterator(const Container &O, size_t I) : Outer(&O), Idx(I) {}
- bool operator==(const FunctionEffectIterator &Other) const {
- return Idx == Other.Idx;
- }
- bool operator!=(const FunctionEffectIterator &Other) const {
- return Idx != Other.Idx;
- }
-
- FunctionEffectIterator operator++() {
- ++Idx;
- return *this;
- }
-
- FunctionEffectWithCondition operator*() const {
- assert(Outer != nullptr && "invalid FunctionEffectIterator");
- bool HasConds = !Outer->Conditions.empty();
- return FunctionEffectWithCondition{Outer->Effects[Idx],
- HasConds ? Outer->Conditions[Idx]
- : EffectConditionExpr()};
- }
-};
-
-/// An immutable set of FunctionEffects and possibly conditions attached to
-/// them. The effects and conditions reside in memory not managed by this object
-/// (typically, trailing objects in FunctionProtoType, or borrowed references
-/// from a FunctionEffectSet).
-///
-/// Invariants:
-/// - there is never more than one instance of any given effect.
-/// - the array of conditions is either empty or has the same size as the
-/// array of effects.
-/// - some conditions may be null expressions; each condition pertains to
-/// the effect at the same array index.
-///
-/// Also, if there are any conditions, at least one of those expressions will be
-/// dependent, but this is only asserted in the constructor of
-/// FunctionProtoType.
-///
-/// See also FunctionEffectSet, in Sema, which provides a mutable set.
-class FunctionEffectsRef {
- // Restrict classes which can call the private constructor -- these friends
- // all maintain the required invariants. FunctionEffectSet is generally the
- // only way in which the arrays are created; FunctionProtoType will not
- // reorder them.
- friend FunctionProtoType;
- friend FunctionEffectSet;
-
- ArrayRef<FunctionEffect> Effects;
- ArrayRef<EffectConditionExpr> Conditions;
-
- // The arrays are expected to have been sorted by the caller, with the
- // effects in order. The conditions array must be empty or the same size
- // as the effects array, since the conditions are associated with the effects
- // at the same array indices.
- FunctionEffectsRef(ArrayRef<FunctionEffect> FX,
- ArrayRef<EffectConditionExpr> Conds)
- : Effects(FX), Conditions(Conds) {}
-
-public:
- /// Extract the effects from a Type if it is a function, block, or member
- /// function pointer, or a reference or pointer to one.
- static FunctionEffectsRef get(QualType QT);
-
- /// Asserts invariants.
- static FunctionEffectsRef create(ArrayRef<FunctionEffect> FX,
- ArrayRef<EffectConditionExpr> Conds);
-
- FunctionEffectsRef() = default;
-
- bool empty() const { return Effects.empty(); }
- size_t size() const { return Effects.size(); }
-
- ArrayRef<FunctionEffect> effects() const { return Effects; }
- ArrayRef<EffectConditionExpr> conditions() const { return Conditions; }
-
- using iterator = FunctionEffectIterator<FunctionEffectsRef>;
- friend iterator;
- iterator begin() const { return iterator(*this, 0); }
- iterator end() const { return iterator(*this, size()); }
-
- friend bool operator==(const FunctionEffectsRef &LHS,
- const FunctionEffectsRef &RHS) {
- return LHS.Effects == RHS.Effects && LHS.Conditions == RHS.Conditions;
- }
- friend bool operator!=(const FunctionEffectsRef &LHS,
- const FunctionEffectsRef &RHS) {
- return !(LHS == RHS);
- }
-
- void dump(llvm::raw_ostream &OS) const;
-};
-
-/// A mutable set of FunctionEffect::Kind.
-class FunctionEffectKindSet {
- // For now this only needs to be a bitmap.
- constexpr static size_t EndBitPos = FunctionEffect::KindCount;
- using KindBitsT = std::bitset<EndBitPos>;
-
- KindBitsT KindBits{};
-
- explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {}
-
- // Functions to translate between an effect kind, starting at 1, and a
- // position in the bitset.
-
- constexpr static size_t kindToPos(FunctionEffect::Kind K) {
- return static_cast<size_t>(K);
- }
-
- constexpr static FunctionEffect::Kind posToKind(size_t Pos) {
- return static_cast<FunctionEffect::Kind>(Pos);
- }
-
- // Iterates through the bits which are set.
- class iterator {
- const FunctionEffectKindSet *Outer = nullptr;
- size_t Idx = 0;
-
- // If Idx does not reference a set bit, advance it until it does,
- // or until it reaches EndBitPos.
- void advanceToNextSetBit() {
- while (Idx < EndBitPos && !Outer->KindBits.test(Idx))
- ++Idx;
- }
-
- public:
- iterator();
- iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) {
- advanceToNextSetBit();
- }
- bool operator==(const iterator &Other) const { return Idx == Other.Idx; }
- bool operator!=(const iterator &Other) const { return Idx != Other.Idx; }
-
- iterator operator++() {
- ++Idx;
- advanceToNextSetBit();
- return *this;
- }
-
- FunctionEffect operator*() const {
- assert(Idx < EndBitPos && "Dereference of end iterator");
- return FunctionEffect(posToKind(Idx));
- }
- };
-
-public:
- FunctionEffectKindSet() = default;
- explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); }
-
- iterator begin() const { return iterator(*this, 0); }
- iterator end() const { return iterator(*this, EndBitPos); }
-
- void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); }
- void insert(FunctionEffectsRef FX) {
- for (FunctionEffect Item : FX.effects())
- insert(Item);
- }
- void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; }
-
- bool empty() const { return KindBits.none(); }
- bool contains(const FunctionEffect::Kind EK) const {
- return KindBits.test(kindToPos(EK));
- }
- void dump(llvm::raw_ostream &OS) const;
-
- static FunctionEffectKindSet difference(FunctionEffectKindSet LHS,
- FunctionEffectKindSet RHS) {
- return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits);
- }
-};
-
-/// A mutable set of FunctionEffects and possibly conditions attached to them.
-/// Used to compare and merge effects on declarations.
-///
-/// Has the same invariants as FunctionEffectsRef.
-class FunctionEffectSet {
- SmallVector<FunctionEffect> Effects;
- SmallVector<EffectConditionExpr> Conditions;
-public:
- FunctionEffectSet() = default;
-
- explicit FunctionEffectSet(const FunctionEffectsRef &FX)
- : Effects(FX.effects()), Conditions(FX.conditions()) {}
-
- bool empty() const { return Effects.empty(); }
- size_t size() const { return Effects.size(); }
-
- using iterator = FunctionEffectIterator<FunctionEffectSet>;
- friend iterator;
- iterator begin() const { return iterator(*this, 0); }
- iterator end() const { return iterator(*this, size()); }
-
- operator FunctionEffectsRef() const { return {Effects, Conditions}; }
-
- void dump(llvm::raw_ostream &OS) const;
-
- // Mutators
-
- // On insertion, a conflict occurs when attempting to insert an
- // effect which is opposite an effect already in the set, or attempting
- // to insert an effect which is already in the set but with a condition
- // which is not identical.
- struct Conflict {
- FunctionEffectWithCondition Kept;
- FunctionEffectWithCondition Rejected;
- };
- using Conflicts = SmallVector<Conflict>;
-
- // Returns true for success (obviating a check of Errs.empty()).
- bool insert(const FunctionEffectWithCondition &NewEC, Conflicts &Errs);
-
- // Returns true for success (obviating a check of Errs.empty()).
- bool insert(const FunctionEffectsRef &Set, Conflicts &Errs);
-
- // Set operations
-
- static FunctionEffectSet getUnion(FunctionEffectsRef LHS,
- FunctionEffectsRef RHS, Conflicts &Errs);
- static FunctionEffectSet getIntersection(FunctionEffectsRef LHS,
- FunctionEffectsRef RHS);
-};
-
-/// Represents a prototype with parameter type info, e.g.
-/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
-/// parameters, not as having a single void parameter. Such a type can have
-/// an exception specification, but this specification is not part of the
-/// canonical type. FunctionProtoType has several trailing objects, some of
-/// which optional. For more information about the trailing objects see
-/// the first comment inside FunctionProtoType.
-class FunctionProtoType final
- : public FunctionType,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<
- FunctionProtoType, QualType, SourceLocation,
- FunctionType::FunctionTypeExtraBitfields,
- FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
- Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
- FunctionEffect, EffectConditionExpr> {
- friend class ASTContext; // ASTContext creates these.
- friend TrailingObjects;
-
- // FunctionProtoType is followed by several trailing objects, some of
- // which optional. They are in order:
- //
- // * An array of getNumParams() QualType holding the parameter types.
- // Always present. Note that for the vast majority of FunctionProtoType,
- // these will be the only trailing objects.
- //
- // * Optionally if the function is variadic, the SourceLocation of the
- // ellipsis.
- //
- // * Optionally if some extra data is stored in FunctionTypeExtraBitfields
- // (see FunctionTypeExtraBitfields and FunctionTypeBitfields):
- // a single FunctionTypeExtraBitfields. Present if and only if
- // hasExtraBitfields() is true.
- //
- // * Optionally exactly one of:
- // * an array of getNumExceptions() ExceptionType,
- // * a single Expr *,
- // * a pair of FunctionDecl *,
- // * a single FunctionDecl *
- // used to store information about the various types of exception
- // specification. See getExceptionSpecSize for the details.
- //
- // * Optionally an array of getNumParams() ExtParameterInfo holding
- // an ExtParameterInfo for each of the parameters. Present if and
- // only if hasExtParameterInfos() is true.
- //
- // * Optionally a Qualifiers object to represent extra qualifiers that can't
- // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and
- // only if hasExtQualifiers() is true.
- //
- // * Optionally, an array of getNumFunctionEffects() FunctionEffect.
- // Present only when getNumFunctionEffects() > 0
- //
- // * Optionally, an array of getNumFunctionEffects() EffectConditionExpr.
- // Present only when getNumFunctionEffectConditions() > 0.
- //
- // The optional FunctionTypeExtraBitfields has to be before the data
- // related to the exception specification since it contains the number
- // of exception types.
- //
- // We put the ExtParameterInfos later. If all were equal, it would make
- // more sense to put these before the exception specification, because
- // it's much easier to skip past them compared to the elaborate switch
- // required to skip the exception specification. However, all is not
- // equal; ExtParameterInfos are used to model very uncommon features,
- // and it's better not to burden the more common paths.
-
-public:
- /// Holds information about the various types of exception specification.
- /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is
- /// used to group together the various bits of information about the
- /// exception specification.
- struct ExceptionSpecInfo {
- /// The kind of exception specification this is.
- ExceptionSpecificationType Type = EST_None;
-
- /// Explicitly-specified list of exception types.
- ArrayRef<QualType> Exceptions;
-
- /// Noexcept expression, if this is a computed noexcept specification.
- Expr *NoexceptExpr = nullptr;
-
- /// The function whose exception specification this is, for
- /// EST_Unevaluated and EST_Uninstantiated.
- FunctionDecl *SourceDecl = nullptr;
-
- /// The function template whose exception specification this is instantiated
- /// from, for EST_Uninstantiated.
- FunctionDecl *SourceTemplate = nullptr;
-
- ExceptionSpecInfo() = default;
-
- ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {}
-
- void instantiate();
- };
-
- /// Extra information about a function prototype. ExtProtoInfo is not
- /// stored as such in FunctionProtoType but is used to group together
- /// the various bits of extra information about a function prototype.
- struct ExtProtoInfo {
- FunctionType::ExtInfo ExtInfo;
- LLVM_PREFERRED_TYPE(bool)
- unsigned Variadic : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned HasTrailingReturn : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned CFIUncheckedCallee : 1;
- unsigned AArch64SMEAttributes : 9;
- Qualifiers TypeQuals;
- RefQualifierKind RefQualifier = RQ_None;
- ExceptionSpecInfo ExceptionSpec;
- const ExtParameterInfo *ExtParameterInfos = nullptr;
- SourceLocation EllipsisLoc;
- FunctionEffectsRef FunctionEffects;
-
- ExtProtoInfo()
- : Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false),
- AArch64SMEAttributes(SME_NormalFunction) {}
-
- ExtProtoInfo(CallingConv CC)
- : ExtInfo(CC), Variadic(false), HasTrailingReturn(false),
- CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction) {}
-
- ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
- ExtProtoInfo Result(*this);
- Result.ExceptionSpec = ESI;
- return Result;
- }
-
- ExtProtoInfo withCFIUncheckedCallee(bool CFIUncheckedCallee) {
- ExtProtoInfo Result(*this);
- Result.CFIUncheckedCallee = CFIUncheckedCallee;
- return Result;
- }
-
- bool requiresFunctionProtoTypeExtraBitfields() const {
- return ExceptionSpec.Type == EST_Dynamic ||
- requiresFunctionProtoTypeArmAttributes() ||
- !FunctionEffects.empty();
- }
-
- bool requiresFunctionProtoTypeArmAttributes() const {
- return AArch64SMEAttributes != SME_NormalFunction;
- }
-
- void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) {
- if (Enable)
- AArch64SMEAttributes |= Kind;
- else
- AArch64SMEAttributes &= ~Kind;
- }
- };
-
-private:
- unsigned numTrailingObjects(OverloadToken<QualType>) const {
- return getNumParams();
- }
-
- unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
- return isVariadic();
- }
-
- unsigned numTrailingObjects(OverloadToken<FunctionTypeArmAttributes>) const {
- return hasArmTypeAttributes();
- }
-
- unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
- return hasExtraBitfields();
- }
-
- unsigned numTrailingObjects(OverloadToken<ExceptionType>) const {
- return getExceptionSpecSize().NumExceptionType;
- }
-
- unsigned numTrailingObjects(OverloadToken<Expr *>) const {
- return getExceptionSpecSize().NumExprPtr;
- }
-
- unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const {
- return getExceptionSpecSize().NumFunctionDeclPtr;
- }
-
- unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const {
- return hasExtParameterInfos() ? getNumParams() : 0;
- }
-
- unsigned numTrailingObjects(OverloadToken<Qualifiers>) const {
- return hasExtQualifiers() ? 1 : 0;
- }
-
- unsigned numTrailingObjects(OverloadToken<FunctionEffect>) const {
- return getNumFunctionEffects();
- }
-
- /// Determine whether there are any argument types that
- /// contain an unexpanded parameter pack.
- static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray,
- unsigned numArgs) {
- for (unsigned Idx = 0; Idx < numArgs; ++Idx)
- if (ArgArray[Idx]->containsUnexpandedParameterPack())
- return true;
-
- return false;
- }
-
- FunctionProtoType(QualType result, ArrayRef<QualType> params,
- QualType canonical, const ExtProtoInfo &epi);
-
- /// This struct is returned by getExceptionSpecSize and is used to
- /// translate an ExceptionSpecificationType to the number and kind
- /// of trailing objects related to the exception specification.
- struct ExceptionSpecSizeHolder {
- unsigned NumExceptionType;
- unsigned NumExprPtr;
- unsigned NumFunctionDeclPtr;
- };
-
- /// Return the number and kind of trailing objects
- /// related to the exception specification.
- static ExceptionSpecSizeHolder
- getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) {
- switch (EST) {
- case EST_None:
- case EST_DynamicNone:
- case EST_MSAny:
- case EST_BasicNoexcept:
- case EST_Unparsed:
- case EST_NoThrow:
- return {0, 0, 0};
-
- case EST_Dynamic:
- return {NumExceptions, 0, 0};
-
- case EST_DependentNoexcept:
- case EST_NoexceptFalse:
- case EST_NoexceptTrue:
- return {0, 1, 0};
-
- case EST_Uninstantiated:
- return {0, 0, 2};
-
- case EST_Unevaluated:
- return {0, 0, 1};
- }
- llvm_unreachable("bad exception specification kind");
- }
-
- /// Return the number and kind of trailing objects
- /// related to the exception specification.
- ExceptionSpecSizeHolder getExceptionSpecSize() const {
- return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions());
- }
-
- /// Whether the trailing FunctionTypeExtraBitfields is present.
- bool hasExtraBitfields() const {
- assert((getExceptionSpecType() != EST_Dynamic ||
- FunctionTypeBits.HasExtraBitfields) &&
- "ExtraBitfields are required for given ExceptionSpecType");
- return FunctionTypeBits.HasExtraBitfields;
-
- }
-
- bool hasArmTypeAttributes() const {
- return FunctionTypeBits.HasExtraBitfields &&
- getTrailingObjects<FunctionTypeExtraBitfields>()
- ->HasArmTypeAttributes;
- }
-
- bool hasExtQualifiers() const {
- return FunctionTypeBits.HasExtQuals;
- }
-
-public:
- unsigned getNumParams() const { return FunctionTypeBits.NumParams; }
-
- QualType getParamType(unsigned i) const {
- assert(i < getNumParams() && "invalid parameter index");
- return param_type_begin()[i];
- }
-
- ArrayRef<QualType> getParamTypes() const {
- return {param_type_begin(), param_type_end()};
- }
-
- ExtProtoInfo getExtProtoInfo() const {
- ExtProtoInfo EPI;
- EPI.ExtInfo = getExtInfo();
- EPI.Variadic = isVariadic();
- EPI.EllipsisLoc = getEllipsisLoc();
- EPI.HasTrailingReturn = hasTrailingReturn();
- EPI.CFIUncheckedCallee = hasCFIUncheckedCallee();
- EPI.ExceptionSpec = getExceptionSpecInfo();
- EPI.TypeQuals = getMethodQuals();
- EPI.RefQualifier = getRefQualifier();
- EPI.ExtParameterInfos = getExtParameterInfosOrNull();
- EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
- EPI.FunctionEffects = getFunctionEffects();
- return EPI;
- }
-
- /// Get the kind of exception specification on this function.
- ExceptionSpecificationType getExceptionSpecType() const {
- return static_cast<ExceptionSpecificationType>(
- FunctionTypeBits.ExceptionSpecType);
- }
-
- /// Return whether this function has any kind of exception spec.
- bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; }
-
- /// Return whether this function has a dynamic (throw) exception spec.
- bool hasDynamicExceptionSpec() const {
- return isDynamicExceptionSpec(getExceptionSpecType());
- }
-
- /// Return whether this function has a noexcept exception spec.
- bool hasNoexceptExceptionSpec() const {
- return isNoexceptExceptionSpec(getExceptionSpecType());
- }
-
- /// Return whether this function has a dependent exception spec.
- bool hasDependentExceptionSpec() const;
-
- /// Return whether this function has an instantiation-dependent exception
- /// spec.
- bool hasInstantiationDependentExceptionSpec() const;
-
- /// Return all the available information about this type's exception spec.
- ExceptionSpecInfo getExceptionSpecInfo() const {
- ExceptionSpecInfo Result;
- Result.Type = getExceptionSpecType();
- if (Result.Type == EST_Dynamic) {
- Result.Exceptions = exceptions();
- } else if (isComputedNoexcept(Result.Type)) {
- Result.NoexceptExpr = getNoexceptExpr();
- } else if (Result.Type == EST_Uninstantiated) {
- Result.SourceDecl = getExceptionSpecDecl();
- Result.SourceTemplate = getExceptionSpecTemplate();
- } else if (Result.Type == EST_Unevaluated) {
- Result.SourceDecl = getExceptionSpecDecl();
- }
- return Result;
- }
-
- /// Return the number of types in the exception specification.
- unsigned getNumExceptions() const {
- return getExceptionSpecType() == EST_Dynamic
- ? getTrailingObjects<FunctionTypeExtraBitfields>()
- ->NumExceptionType
- : 0;
- }
-
- /// Return the ith exception type, where 0 <= i < getNumExceptions().
- QualType getExceptionType(unsigned i) const {
- assert(i < getNumExceptions() && "Invalid exception number!");
- return exception_begin()[i];
- }
-
- /// Return the expression inside noexcept(expression), or a null pointer
- /// if there is none (because the exception spec is not of this form).
- Expr *getNoexceptExpr() const {
- if (!isComputedNoexcept(getExceptionSpecType()))
- return nullptr;
- return *getTrailingObjects<Expr *>();
- }
-
- /// If this function type has an exception specification which hasn't
- /// been determined yet (either because it has not been evaluated or because
- /// it has not been instantiated), this is the function whose exception
- /// specification is represented by this type.
- FunctionDecl *getExceptionSpecDecl() const {
- if (getExceptionSpecType() != EST_Uninstantiated &&
- getExceptionSpecType() != EST_Unevaluated)
- return nullptr;
- return getTrailingObjects<FunctionDecl *>()[0];
- }
-
- /// If this function type has an uninstantiated exception
- /// specification, this is the function whose exception specification
- /// should be instantiated to find the exception specification for
- /// this type.
- FunctionDecl *getExceptionSpecTemplate() const {
- if (getExceptionSpecType() != EST_Uninstantiated)
- return nullptr;
- return getTrailingObjects<FunctionDecl *>()[1];
- }
-
- /// Determine whether this function type has a non-throwing exception
- /// specification.
- CanThrowResult canThrow() const;
-
- /// Determine whether this function type has a non-throwing exception
- /// specification. If this depends on template arguments, returns
- /// \c ResultIfDependent.
- bool isNothrow(bool ResultIfDependent = false) const {
- return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot;
- }
-
- /// Whether this function prototype is variadic.
- bool isVariadic() const { return FunctionTypeBits.Variadic; }
-
- SourceLocation getEllipsisLoc() const {
- return isVariadic() ? *getTrailingObjects<SourceLocation>()
- : SourceLocation();
- }
-
- /// Determines whether this function prototype contains a
- /// parameter pack at the end.
- ///
- /// A function template whose last parameter is a parameter pack can be
- /// called with an arbitrary number of arguments, much like a variadic
- /// function.
- bool isTemplateVariadic() const;
-
- /// Whether this function prototype has a trailing return type.
- bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; }
-
- bool hasCFIUncheckedCallee() const {
- return FunctionTypeBits.CFIUncheckedCallee;
- }
-
- Qualifiers getMethodQuals() const {
- if (hasExtQualifiers())
- return *getTrailingObjects<Qualifiers>();
- else
- return getFastTypeQuals();
- }
-
- /// Retrieve the ref-qualifier associated with this function type.
- RefQualifierKind getRefQualifier() const {
- return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
- }
-
- using param_type_iterator = const QualType *;
-
- ArrayRef<QualType> param_types() const {
- return {param_type_begin(), param_type_end()};
- }
-
- param_type_iterator param_type_begin() const {
- return getTrailingObjects<QualType>();
- }
-
- param_type_iterator param_type_end() const {
- return param_type_begin() + getNumParams();
- }
-
- using exception_iterator = const QualType *;
-
- ArrayRef<QualType> exceptions() const {
- return {exception_begin(), exception_end()};
- }
-
- exception_iterator exception_begin() const {
- return reinterpret_cast<exception_iterator>(
- getTrailingObjects<ExceptionType>());
- }
-
- exception_iterator exception_end() const {
- return exception_begin() + getNumExceptions();
- }
-
- /// Is there any interesting extra information for any of the parameters
- /// of this function type?
- bool hasExtParameterInfos() const {
- return FunctionTypeBits.HasExtParameterInfos;
- }
-
- ArrayRef<ExtParameterInfo> getExtParameterInfos() const {
- assert(hasExtParameterInfos());
- return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(),
- getNumParams());
- }
-
- /// Return a pointer to the beginning of the array of extra parameter
- /// information, if present, or else null if none of the parameters
- /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos.
- const ExtParameterInfo *getExtParameterInfosOrNull() const {
- if (!hasExtParameterInfos())
- return nullptr;
- return getTrailingObjects<ExtParameterInfo>();
- }
-
- /// Return a bitmask describing the SME attributes on the function type, see
- /// AArch64SMETypeAttributes for their values.
- unsigned getAArch64SMEAttributes() const {
- if (!hasArmTypeAttributes())
- return SME_NormalFunction;
- return getTrailingObjects<FunctionTypeArmAttributes>()
- ->AArch64SMEAttributes;
- }
-
- ExtParameterInfo getExtParameterInfo(unsigned I) const {
- assert(I < getNumParams() && "parameter index out of range");
- if (hasExtParameterInfos())
- return getTrailingObjects<ExtParameterInfo>()[I];
- return ExtParameterInfo();
- }
-
- ParameterABI getParameterABI(unsigned I) const {
- assert(I < getNumParams() && "parameter index out of range");
- if (hasExtParameterInfos())
- return getTrailingObjects<ExtParameterInfo>()[I].getABI();
- return ParameterABI::Ordinary;
- }
-
- bool isParamConsumed(unsigned I) const {
- assert(I < getNumParams() && "parameter index out of range");
- if (hasExtParameterInfos())
- return getTrailingObjects<ExtParameterInfo>()[I].isConsumed();
- return false;
- }
-
- unsigned getNumFunctionEffects() const {
- return hasExtraBitfields()
- ? getTrailingObjects<FunctionTypeExtraBitfields>()
- ->NumFunctionEffects
- : 0;
- }
-
- // For serialization.
- ArrayRef<FunctionEffect> getFunctionEffectsWithoutConditions() const {
- if (hasExtraBitfields()) {
- const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
- if (Bitfields->NumFunctionEffects > 0)
- return getTrailingObjects<FunctionEffect>(
- Bitfields->NumFunctionEffects);
- }
- return {};
- }
-
- unsigned getNumFunctionEffectConditions() const {
- if (hasExtraBitfields()) {
- const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
- if (Bitfields->EffectsHaveConditions)
- return Bitfields->NumFunctionEffects;
- }
- return 0;
- }
-
- // For serialization.
- ArrayRef<EffectConditionExpr> getFunctionEffectConditions() const {
- if (hasExtraBitfields()) {
- const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
- if (Bitfields->EffectsHaveConditions)
- return getTrailingObjects<EffectConditionExpr>(
- Bitfields->NumFunctionEffects);
- }
- return {};
- }
-
- // Combines effects with their conditions.
- FunctionEffectsRef getFunctionEffects() const {
- if (hasExtraBitfields()) {
- const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
- if (Bitfields->NumFunctionEffects > 0) {
- const size_t NumConds = Bitfields->EffectsHaveConditions
- ? Bitfields->NumFunctionEffects
- : 0;
- return FunctionEffectsRef(
- getTrailingObjects<FunctionEffect>(Bitfields->NumFunctionEffects),
- {NumConds ? getTrailingObjects<EffectConditionExpr>() : nullptr,
- NumConds});
- }
- }
- return {};
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void printExceptionSpecification(raw_ostream &OS,
- const PrintingPolicy &Policy) const;
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == FunctionProto;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
- param_type_iterator ArgTys, unsigned NumArgs,
- const ExtProtoInfo &EPI, const ASTContext &Context,
- bool Canonical);
-};
-
-/// Represents the dependent type named by a dependently-scoped
-/// typename using declaration, e.g.
-/// using typename Base<T>::foo;
-///
-/// Template instantiation turns these into the underlying type.
-class UnresolvedUsingType : public Type {
- friend class ASTContext; // ASTContext creates these.
-
- UnresolvedUsingTypenameDecl *Decl;
-
- UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D)
- : Type(UnresolvedUsing, QualType(),
- TypeDependence::DependentInstantiation),
- Decl(const_cast<UnresolvedUsingTypenameDecl *>(D)) {}
-
-public:
- UnresolvedUsingTypenameDecl *getDecl() const { return Decl; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == UnresolvedUsing;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- return Profile(ID, Decl);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID,
- UnresolvedUsingTypenameDecl *D) {
- ID.AddPointer(D);
- }
-};
-
-class UsingType final : public Type,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<UsingType, QualType> {
- UsingShadowDecl *Found;
- friend class ASTContext; // ASTContext creates these.
- friend TrailingObjects;
-
- UsingType(const UsingShadowDecl *Found, QualType Underlying, QualType Canon);
-
-public:
- UsingShadowDecl *getFoundDecl() const { return Found; }
- QualType getUnderlyingType() const;
-
- bool isSugared() const { return true; }
-
- // This always has the 'same' type as declared, but not necessarily identical.
- QualType desugar() const { return getUnderlyingType(); }
-
- // Internal helper, for debugging purposes.
- bool typeMatchesDecl() const { return !UsingBits.hasTypeDifferentFromDecl; }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Found, getUnderlyingType());
- }
- static void Profile(llvm::FoldingSetNodeID &ID, const UsingShadowDecl *Found,
- QualType Underlying) {
- ID.AddPointer(Found);
- Underlying.Profile(ID);
- }
- static bool classof(const Type *T) { return T->getTypeClass() == Using; }
-};
-
-class TypedefType final : public Type,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<TypedefType, QualType> {
- TypedefNameDecl *Decl;
- friend class ASTContext; // ASTContext creates these.
- friend TrailingObjects;
-
- TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType UnderlyingType,
- bool HasTypeDifferentFromDecl);
-
-public:
- TypedefNameDecl *getDecl() const { return Decl; }
-
- bool isSugared() const { return true; }
-
- // This always has the 'same' type as declared, but not necessarily identical.
- QualType desugar() const;
-
- // Internal helper, for debugging purposes.
- bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Decl, typeMatchesDecl() ? QualType() : desugar());
- }
- static void Profile(llvm::FoldingSetNodeID &ID, const TypedefNameDecl *Decl,
- QualType Underlying) {
- ID.AddPointer(Decl);
- if (!Underlying.isNull())
- Underlying.Profile(ID);
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
-};
-
-/// Sugar type that represents a type that was qualified by a qualifier written
-/// as a macro invocation.
-class MacroQualifiedType : public Type {
- friend class ASTContext; // ASTContext creates these.
-
- QualType UnderlyingTy;
- const IdentifierInfo *MacroII;
-
- MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy,
- const IdentifierInfo *MacroII)
- : Type(MacroQualified, CanonTy, UnderlyingTy->getDependence()),
- UnderlyingTy(UnderlyingTy), MacroII(MacroII) {
- assert(isa<AttributedType>(UnderlyingTy) &&
- "Expected a macro qualified type to only wrap attributed types.");
- }
-
-public:
- const IdentifierInfo *getMacroIdentifier() const { return MacroII; }
- QualType getUnderlyingType() const { return UnderlyingTy; }
-
- /// Return this attributed type's modified type with no qualifiers attached to
- /// it.
- QualType getModifiedType() const;
-
- bool isSugared() const { return true; }
- QualType desugar() const;
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == MacroQualified;
- }
-};
-
-/// Represents a `typeof` (or __typeof__) expression (a C23 feature and GCC
-/// extension) or a `typeof_unqual` expression (a C23 feature).
-class TypeOfExprType : public Type {
- Expr *TOExpr;
- const ASTContext &Context;
-
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- TypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind,
- QualType Can = QualType());
-
-public:
- Expr *getUnderlyingExpr() const { return TOExpr; }
-
- /// Returns the kind of 'typeof' type this is.
- TypeOfKind getKind() const {
- return static_cast<TypeOfKind>(TypeOfBits.Kind);
- }
-
- /// Remove a single level of sugar.
- QualType desugar() const;
-
- /// Returns whether this type directly provides sugar.
- bool isSugared() const;
-
- static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
-};
-
-/// Internal representation of canonical, dependent
-/// `typeof(expr)` types.
-///
-/// This class is used internally by the ASTContext to manage
-/// canonical, dependent types, only. Clients will only see instances
-/// of this class via TypeOfExprType nodes.
-class DependentTypeOfExprType : public TypeOfExprType,
- public llvm::FoldingSetNode {
-public:
- DependentTypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind)
- : TypeOfExprType(Context, E, Kind) {}
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getUnderlyingExpr(),
- getKind() == TypeOfKind::Unqualified);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- Expr *E, bool IsUnqual);
-};
-
-/// Represents `typeof(type)`, a C23 feature and GCC extension, or
-/// `typeof_unqual(type), a C23 feature.
-class TypeOfType : public Type {
- friend class ASTContext; // ASTContext creates these.
-
- QualType TOType;
- const ASTContext &Context;
-
- TypeOfType(const ASTContext &Context, QualType T, QualType Can,
- TypeOfKind Kind);
-
-public:
- QualType getUnmodifiedType() const { return TOType; }
-
- /// Remove a single level of sugar.
- QualType desugar() const;
-
- /// Returns whether this type directly provides sugar.
- bool isSugared() const { return true; }
-
- /// Returns the kind of 'typeof' type this is.
- TypeOfKind getKind() const {
- return static_cast<TypeOfKind>(TypeOfBits.Kind);
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
-};
-
-/// Represents the type `decltype(expr)` (C++11).
-class DecltypeType : public Type {
- Expr *E;
- QualType UnderlyingType;
-
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType());
-
-public:
- Expr *getUnderlyingExpr() const { return E; }
- QualType getUnderlyingType() const { return UnderlyingType; }
-
- /// Remove a single level of sugar.
- QualType desugar() const;
-
- /// Returns whether this type directly provides sugar.
- bool isSugared() const;
-
- static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
-};
-
-/// Internal representation of canonical, dependent
-/// decltype(expr) types.
-///
-/// This class is used internally by the ASTContext to manage
-/// canonical, dependent types, only. Clients will only see instances
-/// of this class via DecltypeType nodes.
-class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
-public:
- DependentDecltypeType(Expr *E);
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getUnderlyingExpr());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- Expr *E);
-};
-
-class PackIndexingType final
- : public Type,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<PackIndexingType, QualType> {
- friend TrailingObjects;
-
- QualType Pattern;
- Expr *IndexExpr;
-
- unsigned Size : 31;
-
- LLVM_PREFERRED_TYPE(bool)
- unsigned FullySubstituted : 1;
-
-protected:
- friend class ASTContext; // ASTContext creates these.
- PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr,
- bool FullySubstituted, ArrayRef<QualType> Expansions = {});
-
-public:
- Expr *getIndexExpr() const { return IndexExpr; }
- QualType getPattern() const { return Pattern; }
-
- bool isSugared() const { return hasSelectedType(); }
-
- QualType desugar() const {
- if (hasSelectedType())
- return getSelectedType();
- return QualType(this, 0);
- }
-
- QualType getSelectedType() const {
- assert(hasSelectedType() && "Type is dependant");
- return *(getExpansionsPtr() + *getSelectedIndex());
- }
-
- UnsignedOrNone getSelectedIndex() const;
-
- bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }
-
- bool isFullySubstituted() const { return FullySubstituted; }
-
- bool expandsToEmptyPack() const { return isFullySubstituted() && Size == 0; }
-
- ArrayRef<QualType> getExpansions() const {
- return {getExpansionsPtr(), Size};
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == PackIndexing;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType Pattern, Expr *E, bool FullySubstituted,
- ArrayRef<QualType> Expansions);
-
-private:
- const QualType *getExpansionsPtr() const { return getTrailingObjects(); }
-
- static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
- ArrayRef<QualType> Expansions = {});
-};
-
-/// A unary type transform, which is a type constructed from another.
-class UnaryTransformType : public Type, public llvm::FoldingSetNode {
-public:
- enum UTTKind {
-#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
-#include "clang/Basic/TransformTypeTraits.def"
- };
-
-private:
- /// The untransformed type.
- QualType BaseType;
-
- /// The transformed type if not dependent, otherwise the same as BaseType.
- QualType UnderlyingType;
-
- UTTKind UKind;
-
-protected:
- friend class ASTContext;
-
- UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind,
- QualType CanonicalTy);
-
-public:
- bool isSugared() const { return !isDependentType(); }
- QualType desugar() const { return UnderlyingType; }
-
- QualType getUnderlyingType() const { return UnderlyingType; }
- QualType getBaseType() const { return BaseType; }
-
- UTTKind getUTTKind() const { return UKind; }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == UnaryTransform;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
- QualType UnderlyingType, UTTKind UKind) {
- BaseType.Profile(ID);
- UnderlyingType.Profile(ID);
- ID.AddInteger(UKind);
- }
-};
-
-class TagType : public Type {
- friend class ASTReader;
- template <class T> friend class serialization::AbstractTypeReader;
-
- /// Stores the TagDecl associated with this type. The decl may point to any
- /// TagDecl that declares the entity.
- TagDecl *decl;
-
-protected:
- TagType(TypeClass TC, const TagDecl *D, QualType can);
-
-public:
- TagDecl *getDecl() const;
-
- /// Determines whether this type is in the process of being defined.
- bool isBeingDefined() const;
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Enum || T->getTypeClass() == Record;
- }
-};
-
-/// A helper class that allows the use of isa/cast/dyncast
-/// to detect TagType objects of structs/unions/classes.
-class RecordType : public TagType {
-protected:
- friend class ASTContext; // ASTContext creates these.
-
- explicit RecordType(const RecordDecl *D)
- : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) {}
- explicit RecordType(TypeClass TC, RecordDecl *D)
- : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) {}
-
-public:
- RecordDecl *getDecl() const {
- return reinterpret_cast<RecordDecl*>(TagType::getDecl());
- }
-
- /// Recursively check all fields in the record for const-ness. If any field
- /// is declared const, return true. Otherwise, return false.
- bool hasConstFields() const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Record; }
-};
-
-/// A helper class that allows the use of isa/cast/dyncast
-/// to detect TagType objects of enums.
-class EnumType : public TagType {
- friend class ASTContext; // ASTContext creates these.
-
- explicit EnumType(const EnumDecl *D)
- : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) {}
-
-public:
- EnumDecl *getDecl() const {
- return reinterpret_cast<EnumDecl*>(TagType::getDecl());
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
-};
-
-/// An attributed type is a type to which a type attribute has been applied.
-///
-/// The "modified type" is the fully-sugared type to which the attributed
-/// type was applied; generally it is not canonically equivalent to the
-/// attributed type. The "equivalent type" is the minimally-desugared type
-/// which the type is canonically equivalent to.
-///
-/// For example, in the following attributed type:
-/// int32_t __attribute__((vector_size(16)))
-/// - the modified type is the TypedefType for int32_t
-/// - the equivalent type is VectorType(16, int32_t)
-/// - the canonical type is VectorType(16, int)
-class AttributedType : public Type, public llvm::FoldingSetNode {
-public:
- using Kind = attr::Kind;
-
-private:
- friend class ASTContext; // ASTContext creates these
-
- const Attr *Attribute;
-
- QualType ModifiedType;
- QualType EquivalentType;
-
- AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
- QualType equivalent)
- : AttributedType(canon, attrKind, nullptr, modified, equivalent) {}
-
- AttributedType(QualType canon, const Attr *attr, QualType modified,
- QualType equivalent);
-
-private:
- AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr,
- QualType modified, QualType equivalent);
-
-public:
- Kind getAttrKind() const {
- return static_cast<Kind>(AttributedTypeBits.AttrKind);
- }
-
- const Attr *getAttr() const { return Attribute; }
-
- QualType getModifiedType() const { return ModifiedType; }
- QualType getEquivalentType() const { return EquivalentType; }
-
- bool isSugared() const { return true; }
- QualType desugar() const { return getEquivalentType(); }
-
- /// Does this attribute behave like a type qualifier?
- ///
- /// A type qualifier adjusts a type to provide specialized rules for
- /// a specific object, like the standard const and volatile qualifiers.
- /// This includes attributes controlling things like nullability,
- /// address spaces, and ARC ownership. The value of the object is still
- /// largely described by the modified type.
- ///
- /// In contrast, many type attributes "rewrite" their modified type to
- /// produce a fundamentally different type, not necessarily related in any
- /// formalizable way to the original type. For example, calling convention
- /// and vector attributes are not simple type qualifiers.
- ///
- /// Type qualifiers are often, but not always, reflected in the canonical
- /// type.
- bool isQualifier() const;
-
- bool isMSTypeSpec() const;
-
- bool isWebAssemblyFuncrefSpec() const;
-
- bool isCallingConv() const;
-
- std::optional<NullabilityKind> getImmediateNullability() const;
-
- /// Strip off the top-level nullability annotation on the given
- /// type, if it's there.
- ///
- /// \param T The type to strip. If the type is exactly an
- /// AttributedType specifying nullability (without looking through
- /// type sugar), the nullability is returned and this type changed
- /// to the underlying modified type.
- ///
- /// \returns the top-level nullability, if present.
- static std::optional<NullabilityKind> stripOuterNullability(QualType &T);
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
- QualType modified, QualType equivalent,
- const Attr *attr) {
- ID.AddInteger(attrKind);
- ID.AddPointer(modified.getAsOpaquePtr());
- ID.AddPointer(equivalent.getAsOpaquePtr());
- ID.AddPointer(attr);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Attributed;
- }
-};
-
-class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
-private:
- friend class ASTContext; // ASTContext creates these
-
- QualType WrappedType;
- const BTFTypeTagAttr *BTFAttr;
-
- BTFTagAttributedType(QualType Canon, QualType Wrapped,
- const BTFTypeTagAttr *BTFAttr)
- : Type(BTFTagAttributed, Canon, Wrapped->getDependence()),
- WrappedType(Wrapped), BTFAttr(BTFAttr) {}
-
-public:
- QualType getWrappedType() const { return WrappedType; }
- const BTFTypeTagAttr *getAttr() const { return BTFAttr; }
-
- bool isSugared() const { return true; }
- QualType desugar() const { return getWrappedType(); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, WrappedType, BTFAttr);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped,
- const BTFTypeTagAttr *BTFAttr) {
- ID.AddPointer(Wrapped.getAsOpaquePtr());
- ID.AddPointer(BTFAttr);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == BTFTagAttributed;
- }
-};
-
-class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
-public:
- struct Attributes {
- // Data gathered from HLSL resource attributes
- llvm::dxil::ResourceClass ResourceClass;
-
- LLVM_PREFERRED_TYPE(bool)
- uint8_t IsROV : 1;
-
- LLVM_PREFERRED_TYPE(bool)
- uint8_t RawBuffer : 1;
-
- Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
- bool RawBuffer = false)
- : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
-
- Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
-
- friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
- return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
- std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
- }
- friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
- return !(LHS == RHS);
- }
- };
-
-private:
- friend class ASTContext; // ASTContext creates these
-
- QualType WrappedType;
- QualType ContainedType;
- const Attributes Attrs;
-
- HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
- const Attributes &Attrs)
- : Type(HLSLAttributedResource, QualType(),
- Contained.isNull() ? TypeDependence::None
- : Contained->getDependence()),
- WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}
-
-public:
- QualType getWrappedType() const { return WrappedType; }
- QualType getContainedType() const { return ContainedType; }
- bool hasContainedType() const { return !ContainedType.isNull(); }
- const Attributes &getAttrs() const { return Attrs; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, WrappedType, ContainedType, Attrs);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped,
- QualType Contained, const Attributes &Attrs) {
- ID.AddPointer(Wrapped.getAsOpaquePtr());
- ID.AddPointer(Contained.getAsOpaquePtr());
- ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
- ID.AddBoolean(Attrs.IsROV);
- ID.AddBoolean(Attrs.RawBuffer);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == HLSLAttributedResource;
- }
-
- // Returns handle type from HLSL resource, if the type is a resource
- static const HLSLAttributedResourceType *
- findHandleTypeOnResource(const Type *RT);
-};
-
-/// Instances of this class represent operands to a SPIR-V type instruction.
-class SpirvOperand {
-public:
- enum SpirvOperandKind : unsigned char {
- Invalid, ///< Uninitialized.
- ConstantId, ///< Integral value to represent as a SPIR-V OpConstant
- ///< instruction ID.
- Literal, ///< Integral value to represent as an immediate literal.
- TypeId, ///< Type to represent as a SPIR-V type ID.
-
- Max,
- };
-
-private:
- SpirvOperandKind Kind = Invalid;
-
- QualType ResultType;
- llvm::APInt Value; // Signedness of constants is represented by ResultType.
-
-public:
- SpirvOperand() : Kind(Invalid), ResultType(), Value() {}
-
- SpirvOperand(SpirvOperandKind Kind, QualType ResultType, llvm::APInt Value)
- : Kind(Kind), ResultType(ResultType), Value(std::move(Value)) {}
-
- SpirvOperand(const SpirvOperand &Other) { *this = Other; }
- ~SpirvOperand() {}
-
- SpirvOperand &operator=(const SpirvOperand &Other) = default;
-
- bool operator==(const SpirvOperand &Other) const {
- return Kind == Other.Kind && ResultType == Other.ResultType &&
- Value == Other.Value;
- }
-
- bool operator!=(const SpirvOperand &Other) const { return !(*this == Other); }
-
- SpirvOperandKind getKind() const { return Kind; }
-
- bool isValid() const { return Kind != Invalid && Kind < Max; }
- bool isConstant() const { return Kind == ConstantId; }
- bool isLiteral() const { return Kind == Literal; }
- bool isType() const { return Kind == TypeId; }
-
- llvm::APInt getValue() const {
- assert((isConstant() || isLiteral()) &&
- "This is not an operand with a value!");
- return Value;
- }
-
- QualType getResultType() const {
- assert((isConstant() || isType()) &&
- "This is not an operand with a result type!");
- return ResultType;
- }
-
- static SpirvOperand createConstant(QualType ResultType, llvm::APInt Val) {
- return SpirvOperand(ConstantId, ResultType, std::move(Val));
- }
-
- static SpirvOperand createLiteral(llvm::APInt Val) {
- return SpirvOperand(Literal, QualType(), std::move(Val));
- }
-
- static SpirvOperand createType(QualType T) {
- return SpirvOperand(TypeId, T, llvm::APSInt());
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(Kind);
- ID.AddPointer(ResultType.getAsOpaquePtr());
- Value.Profile(ID);
- }
-};
-
-/// Represents an arbitrary, user-specified SPIR-V type instruction.
-class HLSLInlineSpirvType final
- : public Type,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<HLSLInlineSpirvType, SpirvOperand> {
- friend class ASTContext; // ASTContext creates these
- friend TrailingObjects;
-
-private:
- uint32_t Opcode;
- uint32_t Size;
- uint32_t Alignment;
- size_t NumOperands;
-
- HLSLInlineSpirvType(uint32_t Opcode, uint32_t Size, uint32_t Alignment,
- ArrayRef<SpirvOperand> Operands)
- : Type(HLSLInlineSpirv, QualType(), TypeDependence::None), Opcode(Opcode),
- Size(Size), Alignment(Alignment), NumOperands(Operands.size()) {
- for (size_t I = 0; I < NumOperands; I++) {
- // Since Operands are stored as a trailing object, they have not been
- // initialized yet. Call the constructor manually.
- auto *Operand = new (&getTrailingObjects()[I]) SpirvOperand();
- *Operand = Operands[I];
- }
- }
-
-public:
- uint32_t getOpcode() const { return Opcode; }
- uint32_t getSize() const { return Size; }
- uint32_t getAlignment() const { return Alignment; }
- ArrayRef<SpirvOperand> getOperands() const {
- return getTrailingObjects(NumOperands);
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Opcode, Size, Alignment, getOperands());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, uint32_t Opcode,
- uint32_t Size, uint32_t Alignment,
- ArrayRef<SpirvOperand> Operands) {
- ID.AddInteger(Opcode);
- ID.AddInteger(Size);
- ID.AddInteger(Alignment);
- for (auto &Operand : Operands)
- Operand.Profile(ID);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == HLSLInlineSpirv;
- }
-};
-
-class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these
-
- // The associated TemplateTypeParmDecl for the non-canonical type.
- TemplateTypeParmDecl *TTPDecl;
-
- TemplateTypeParmType(unsigned D, unsigned I, bool PP,
- TemplateTypeParmDecl *TTPDecl, QualType Canon)
- : Type(TemplateTypeParm, Canon,
- TypeDependence::DependentInstantiation |
- (PP ? TypeDependence::UnexpandedPack : TypeDependence::None)),
- TTPDecl(TTPDecl) {
- assert(!TTPDecl == Canon.isNull());
- TemplateTypeParmTypeBits.Depth = D;
- TemplateTypeParmTypeBits.Index = I;
- TemplateTypeParmTypeBits.ParameterPack = PP;
- }
-
-public:
- unsigned getDepth() const { return TemplateTypeParmTypeBits.Depth; }
- unsigned getIndex() const { return TemplateTypeParmTypeBits.Index; }
- bool isParameterPack() const {
- return TemplateTypeParmTypeBits.ParameterPack;
- }
-
- TemplateTypeParmDecl *getDecl() const { return TTPDecl; }
-
- IdentifierInfo *getIdentifier() const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
- unsigned Index, bool ParameterPack,
- TemplateTypeParmDecl *TTPDecl) {
- ID.AddInteger(Depth);
- ID.AddInteger(Index);
- ID.AddBoolean(ParameterPack);
- ID.AddPointer(TTPDecl);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == TemplateTypeParm;
- }
-};
-
-/// Represents the result of substituting a type for a template
-/// type parameter.
-///
-/// Within an instantiated template, all template type parameters have
-/// been replaced with these. They are used solely to record that a
-/// type was originally written as a template type parameter;
-/// therefore they are never canonical.
-class SubstTemplateTypeParmType final
- : public Type,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<SubstTemplateTypeParmType, QualType> {
- friend class ASTContext;
- friend class llvm::TrailingObjects<SubstTemplateTypeParmType, QualType>;
-
- Decl *AssociatedDecl;
-
- SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
- unsigned Index, UnsignedOrNone PackIndex,
- bool Final);
-
-public:
- /// Gets the type that was substituted for the template
- /// parameter.
- QualType getReplacementType() const {
- return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType
- ? *getTrailingObjects()
- : getCanonicalTypeInternal();
- }
-
- /// A template-like entity which owns the whole pattern being substituted.
- /// This will usually own a set of template parameters, or in some
- /// cases might even be a template parameter itself.
- Decl *getAssociatedDecl() const { return AssociatedDecl; }
-
- /// Gets the template parameter declaration that was substituted for.
- const TemplateTypeParmDecl *getReplacedParameter() const;
-
- /// Returns the index of the replaced parameter in the associated declaration.
- /// This should match the result of `getReplacedParameter()->getIndex()`.
- unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; }
-
- // This substitution is Final, which means the substitution is fully
- // sugared: it doesn't need to be resugared later.
- unsigned getFinal() const { return SubstTemplateTypeParmTypeBits.Final; }
-
- UnsignedOrNone getPackIndex() const {
- return UnsignedOrNone::fromInternalRepresentation(
- SubstTemplateTypeParmTypeBits.PackIndex);
- }
-
- bool isSugared() const { return true; }
- QualType desugar() const { return getReplacementType(); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
- getPackIndex(), getFinal());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
- const Decl *AssociatedDecl, unsigned Index,
- UnsignedOrNone PackIndex, bool Final);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == SubstTemplateTypeParm;
- }
-};
-
-/// Represents the result of substituting a set of types for a template
-/// type parameter pack.
-///
-/// When a pack expansion in the source code contains multiple parameter packs
-/// and those parameter packs correspond to different levels of template
-/// parameter lists, this type node is used to represent a template type
-/// parameter pack from an outer level, which has already had its argument pack
-/// substituted but that still lives within a pack expansion that itself
-/// could not be instantiated. When actually performing a substitution into
-/// that pack expansion (e.g., when all template parameters have corresponding
-/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
-/// at the current pack substitution index.
-class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
-
- /// A pointer to the set of template arguments that this
- /// parameter pack is instantiated with.
- const TemplateArgument *Arguments;
-
- llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;
-
- SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl,
- unsigned Index, bool Final,
- const TemplateArgument &ArgPack);
-
-public:
- IdentifierInfo *getIdentifier() const;
-
- /// A template-like entity which owns the whole pattern being substituted.
- /// This will usually own a set of template parameters, or in some
- /// cases might even be a template parameter itself.
- Decl *getAssociatedDecl() const;
-
- /// Gets the template parameter declaration that was substituted for.
- const TemplateTypeParmDecl *getReplacedParameter() const;
-
- /// Returns the index of the replaced parameter in the associated declaration.
- /// This should match the result of `getReplacedParameter()->getIndex()`.
- unsigned getIndex() const { return SubstTemplateTypeParmPackTypeBits.Index; }
-
- // This substitution will be Final, which means the substitution will be fully
- // sugared: it doesn't need to be resugared later.
- bool getFinal() const;
-
- unsigned getNumArgs() const {
- return SubstTemplateTypeParmPackTypeBits.NumArgs;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- TemplateArgument getArgumentPack() const;
-
- void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
- unsigned Index, bool Final,
- const TemplateArgument &ArgPack);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == SubstTemplateTypeParmPack;
- }
-};
-
-/// Common base class for placeholders for types that get replaced by
-/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
-/// class template types, and constrained type names.
-///
-/// These types are usually a placeholder for a deduced type. However, before
-/// the initializer is attached, or (usually) if the initializer is
-/// type-dependent, there is no deduced type and the type is canonical. In
-/// the latter case, it is also a dependent type.
-class DeducedType : public Type {
- QualType DeducedAsType;
-
-protected:
- DeducedType(TypeClass TC, QualType DeducedAsType,
- TypeDependence ExtraDependence, QualType Canon)
- : Type(TC, Canon,
- ExtraDependence | (DeducedAsType.isNull()
- ? TypeDependence::None
- : DeducedAsType->getDependence() &
- ~TypeDependence::VariablyModified)),
- DeducedAsType(DeducedAsType) {}
-
-public:
- bool isSugared() const { return !DeducedAsType.isNull(); }
- QualType desugar() const {
- return isSugared() ? DeducedAsType : QualType(this, 0);
- }
-
- /// Get the type deduced for this placeholder type, or null if it
- /// has not been deduced.
- QualType getDeducedType() const { return DeducedAsType; }
- bool isDeduced() const {
- return !DeducedAsType.isNull() || isDependentType();
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Auto ||
- T->getTypeClass() == DeducedTemplateSpecialization;
- }
-};
-
-/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
-/// by a type-constraint.
-class AutoType : public DeducedType {
- friend class ASTContext; // ASTContext creates these
-
- TemplateDecl *TypeConstraintConcept;
-
- AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD,
- ArrayRef<TemplateArgument> TypeConstraintArgs);
-
-public:
- ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
- return {reinterpret_cast<const TemplateArgument *>(this + 1),
- AutoTypeBits.NumArgs};
- }
-
- TemplateDecl *getTypeConstraintConcept() const {
- return TypeConstraintConcept;
- }
-
- bool isConstrained() const {
- return TypeConstraintConcept != nullptr;
- }
-
- bool isDecltypeAuto() const {
- return getKeyword() == AutoTypeKeyword::DecltypeAuto;
- }
-
- bool isGNUAutoType() const {
- return getKeyword() == AutoTypeKeyword::GNUAutoType;
- }
-
- AutoTypeKeyword getKeyword() const {
- return (AutoTypeKeyword)AutoTypeBits.Keyword;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- QualType Deduced, AutoTypeKeyword Keyword,
- bool IsDependent, TemplateDecl *CD,
- ArrayRef<TemplateArgument> Arguments);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Auto;
- }
-};
-
-/// Represents a C++17 deduced template specialization type.
-class DeducedTemplateSpecializationType : public DeducedType,
- public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these
-
- /// The name of the template whose arguments will be deduced.
- TemplateName Template;
-
- DeducedTemplateSpecializationType(TemplateName Template,
- QualType DeducedAsType,
- bool IsDeducedAsDependent, QualType Canon)
- : DeducedType(DeducedTemplateSpecialization, DeducedAsType,
- toTypeDependence(Template.getDependence()) |
- (IsDeducedAsDependent
- ? TypeDependence::DependentInstantiation
- : TypeDependence::None),
- Canon),
- Template(Template) {}
-
-public:
- /// Retrieve the name of the template that we are deducing.
- TemplateName getTemplateName() const { return Template;}
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- Profile(ID, getTemplateName(), getDeducedType(), isDependentType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template,
- QualType Deduced, bool IsDependent) {
- Template.Profile(ID);
- Deduced.Profile(ID);
- ID.AddBoolean(IsDependent || Template.isDependent());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DeducedTemplateSpecialization;
- }
-};
-
-/// Represents a type template specialization; the template
-/// must be a class template, a type alias template, or a template
-/// template parameter. A template which cannot be resolved to one of
-/// these, e.g. because it is written with a dependent scope
-/// specifier, is instead represented as a
-/// @c DependentTemplateSpecializationType.
-///
-/// A non-dependent template specialization type is always "sugar",
-/// typically for a \c RecordType. For example, a class template
-/// specialization type of \c vector<int> will refer to a tag type for
-/// the instantiation \c std::vector<int, std::allocator<int>>
-///
-/// Template specializations are dependent if either the template or
-/// any of the template arguments are dependent, in which case the
-/// type may also be canonical.
-///
-/// Instances of this type are allocated with a trailing array of
-/// TemplateArguments, followed by a QualType representing the
-/// non-canonical aliased type when the template is a type alias
-/// template.
-class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these
-
- /// The name of the template being specialized. This is
- /// either a TemplateName::Template (in which case it is a
- /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a
- /// TypeAliasTemplateDecl*), a
- /// TemplateName::SubstTemplateTemplateParmPack, or a
- /// TemplateName::SubstTemplateTemplateParm (in which case the
- /// replacement must, recursively, be one of these).
- TemplateName Template;
-
- TemplateSpecializationType(TemplateName T, bool IsAlias,
- ArrayRef<TemplateArgument> Args,
- QualType Underlying);
-
-public:
- /// Determine whether any of the given template arguments are dependent.
- ///
- /// The converted arguments should be supplied when known; whether an
- /// argument is dependent can depend on the conversions performed on it
- /// (for example, a 'const int' passed as a template argument might be
- /// dependent if the parameter is a reference but non-dependent if the
- /// parameter is an int).
- ///
- /// Note that the \p Args parameter is unused: this is intentional, to remind
- /// the caller that they need to pass in the converted arguments, not the
- /// specified arguments.
- static bool
- anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
- ArrayRef<TemplateArgument> Converted);
- static bool
- anyDependentTemplateArguments(const TemplateArgumentListInfo &,
- ArrayRef<TemplateArgument> Converted);
- static bool anyInstantiationDependentTemplateArguments(
- ArrayRef<TemplateArgumentLoc> Args);
-
- /// True if this template specialization type matches a current
- /// instantiation in the context in which it is found.
- bool isCurrentInstantiation() const {
- return isa<InjectedClassNameType>(getCanonicalTypeInternal());
- }
-
- /// Determine if this template specialization type is for a type alias
- /// template that has been substituted.
- ///
- /// Nearly every template specialization type whose template is an alias
- /// template will be substituted. However, this is not the case when
- /// the specialization contains a pack expansion but the template alias
- /// does not have a corresponding parameter pack, e.g.,
- ///
- /// \code
- /// template<typename T, typename U, typename V> struct S;
- /// template<typename T, typename U> using A = S<T, int, U>;
- /// template<typename... Ts> struct X {
- /// typedef A<Ts...> type; // not a type alias
- /// };
- /// \endcode
- bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; }
-
- /// Get the aliased type, if this is a specialization of a type alias
- /// template.
- QualType getAliasedType() const;
-
- /// Retrieve the name of the template that we are specializing.
- TemplateName getTemplateName() const { return Template; }
-
- ArrayRef<TemplateArgument> template_arguments() const {
- return {reinterpret_cast<const TemplateArgument *>(this + 1),
- TemplateSpecializationTypeBits.NumArgs};
- }
-
- bool isSugared() const {
- return !isDependentType() || isCurrentInstantiation() || isTypeAlias();
- }
-
- QualType desugar() const {
- return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
- }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
- static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
- ArrayRef<TemplateArgument> Args, QualType Underlying,
- const ASTContext &Context);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == TemplateSpecialization;
- }
-};
-
-/// Print a template argument list, including the '<' and '>'
-/// enclosing the template arguments.
-void printTemplateArgumentList(raw_ostream &OS,
- ArrayRef<TemplateArgument> Args,
- const PrintingPolicy &Policy,
- const TemplateParameterList *TPL = nullptr);
-
-void printTemplateArgumentList(raw_ostream &OS,
- ArrayRef<TemplateArgumentLoc> Args,
- const PrintingPolicy &Policy,
- const TemplateParameterList *TPL = nullptr);
-
-void printTemplateArgumentList(raw_ostream &OS,
- const TemplateArgumentListInfo &Args,
- const PrintingPolicy &Policy,
- const TemplateParameterList *TPL = nullptr);
-
-/// Make a best-effort determination of whether the type T can be produced by
-/// substituting Args into the default argument of Param.
-bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
- const NamedDecl *Param,
- ArrayRef<TemplateArgument> Args,
- unsigned Depth);
-
-/// The injected class name of a C++ class template or class
-/// template partial specialization. Used to record that a type was
-/// spelled with a bare identifier rather than as a template-id; the
-/// equivalent for non-templated classes is just RecordType.
-///
-/// Injected class name types are always dependent. Template
-/// instantiation turns these into RecordTypes.
-///
-/// Injected class name types are always canonical. This works
-/// because it is impossible to compare an injected class name type
-/// with the corresponding non-injected template type, for the same
-/// reason that it is impossible to directly compare template
-/// parameters from different dependent contexts: injected class name
-/// types can only occur within the scope of a particular templated
-/// declaration, and within that scope every template specialization
-/// will canonicalize to the injected class name (when appropriate
-/// according to the rules of the language).
-class InjectedClassNameType : public Type {
- friend class ASTContext; // ASTContext creates these.
- friend class ASTNodeImporter;
- friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not
- // currently suitable for AST reading, too much
- // interdependencies.
- template <class T> friend class serialization::AbstractTypeReader;
-
- CXXRecordDecl *Decl;
-
- /// The template specialization which this type represents.
- /// For example, in
- /// template <class T> class A { ... };
- /// this is A<T>, whereas in
- /// template <class X, class Y> class A<B<X,Y> > { ... };
- /// this is A<B<X,Y> >.
- ///
- /// It is always unqualified, always a template specialization type,
- /// and always dependent.
- QualType InjectedType;
-
- InjectedClassNameType(CXXRecordDecl *D, QualType TST)
- : Type(InjectedClassName, QualType(),
- TypeDependence::DependentInstantiation),
- Decl(D), InjectedType(TST) {
- assert(isa<TemplateSpecializationType>(TST));
- assert(!TST.hasQualifiers());
- assert(TST->isDependentType());
- }
-
-public:
- QualType getInjectedSpecializationType() const { return InjectedType; }
-
- const TemplateSpecializationType *getInjectedTST() const {
- return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
- }
-
- TemplateName getTemplateName() const {
- return getInjectedTST()->getTemplateName();
- }
-
- CXXRecordDecl *getDecl() const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == InjectedClassName;
- }
-};
-
-/// The elaboration keyword that precedes a qualified type name or
-/// introduces an elaborated-type-specifier.
-enum class ElaboratedTypeKeyword {
- /// The "struct" keyword introduces the elaborated-type-specifier.
- Struct,
-
- /// The "__interface" keyword introduces the elaborated-type-specifier.
- Interface,
-
- /// The "union" keyword introduces the elaborated-type-specifier.
- Union,
-
- /// The "class" keyword introduces the elaborated-type-specifier.
- Class,
-
- /// The "enum" keyword introduces the elaborated-type-specifier.
- Enum,
-
- /// The "typename" keyword precedes the qualified type name, e.g.,
- /// \c typename T::type.
- Typename,
-
- /// No keyword precedes the qualified type name.
- None
-};
-
-/// The kind of a tag type.
-enum class TagTypeKind {
- /// The "struct" keyword.
- Struct,
-
- /// The "__interface" keyword.
- Interface,
-
- /// The "union" keyword.
- Union,
-
- /// The "class" keyword.
- Class,
-
- /// The "enum" keyword.
- Enum
-};
-
-/// A helper class for Type nodes having an ElaboratedTypeKeyword.
-/// The keyword in stored in the free bits of the base class.
-/// Also provides a few static helpers for converting and printing
-/// elaborated type keyword and tag type kind enumerations.
-class TypeWithKeyword : public Type {
-protected:
- TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
- QualType Canonical, TypeDependence Dependence)
- : Type(tc, Canonical, Dependence) {
- TypeWithKeywordBits.Keyword = llvm::to_underlying(Keyword);
- }
-
-public:
- ElaboratedTypeKeyword getKeyword() const {
- return static_cast<ElaboratedTypeKeyword>(TypeWithKeywordBits.Keyword);
- }
-
- /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword.
- static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec);
-
- /// Converts a type specifier (DeclSpec::TST) into a tag type kind.
- /// It is an error to provide a type specifier which *isn't* a tag kind here.
- static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec);
-
- /// Converts a TagTypeKind into an elaborated type keyword.
- static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag);
-
- /// Converts an elaborated type keyword into a TagTypeKind.
- /// It is an error to provide an elaborated type keyword
- /// which *isn't* a tag kind here.
- static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword);
-
- static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword);
-
- static StringRef getKeywordName(ElaboratedTypeKeyword Keyword);
-
- static StringRef getTagTypeKindName(TagTypeKind Kind) {
- return getKeywordName(getKeywordForTagTypeKind(Kind));
- }
-
- class CannotCastToThisType {};
- static CannotCastToThisType classof(const Type *);
-};
-
-/// Represents a type that was referred to using an elaborated type
-/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type,
-/// or both.
-///
-/// This type is used to keep track of a type name as written in the
-/// source code, including tag keywords and any nested-name-specifiers.
-/// The type itself is always "sugar", used to express what was written
-/// in the source code but containing no additional semantic information.
-class ElaboratedType final
- : public TypeWithKeyword,
- public llvm::FoldingSetNode,
- private llvm::TrailingObjects<ElaboratedType, TagDecl *> {
- friend class ASTContext; // ASTContext creates these
- friend TrailingObjects;
-
- /// The nested name specifier containing the qualifier.
- NestedNameSpecifier *NNS;
-
- /// The type that this qualified name refers to.
- QualType NamedType;
-
- /// The (re)declaration of this tag type owned by this occurrence is stored
- /// as a trailing object if there is one. Use getOwnedTagDecl to obtain
- /// it, or obtain a null pointer if there is none.
-
- ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
- QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl)
- : TypeWithKeyword(Keyword, Elaborated, CanonType,
- // Any semantic dependence on the qualifier will have
- // been incorporated into NamedType. We still need to
- // track syntactic (instantiation / error / pack)
- // dependence on the qualifier.
- NamedType->getDependence() |
- (NNS ? toSyntacticDependence(
- toTypeDependence(NNS->getDependence()))
- : TypeDependence::None)),
- NNS(NNS), NamedType(NamedType) {
- ElaboratedTypeBits.HasOwnedTagDecl = false;
- if (OwnedTagDecl) {
- ElaboratedTypeBits.HasOwnedTagDecl = true;
- *getTrailingObjects() = OwnedTagDecl;
- }
- }
-
-public:
- /// Retrieve the qualification on this type.
- NestedNameSpecifier *getQualifier() const { return NNS; }
-
- /// Retrieve the type named by the qualified-id.
- QualType getNamedType() const { return NamedType; }
-
- /// Remove a single level of sugar.
- QualType desugar() const { return getNamedType(); }
-
- /// Returns whether this type directly provides sugar.
- bool isSugared() const { return true; }
-
- /// Return the (re)declaration of this type owned by this occurrence of this
- /// type, or nullptr if there is none.
- TagDecl *getOwnedTagDecl() const {
- return ElaboratedTypeBits.HasOwnedTagDecl ? *getTrailingObjects() : nullptr;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getKeyword(), NNS, NamedType, getOwnedTagDecl());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, QualType NamedType,
- TagDecl *OwnedTagDecl) {
- ID.AddInteger(llvm::to_underlying(Keyword));
- ID.AddPointer(NNS);
- NamedType.Profile(ID);
- ID.AddPointer(OwnedTagDecl);
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == Elaborated; }
-};
-
-/// Represents a qualified type name for which the type name is
-/// dependent.
-///
-/// DependentNameType represents a class of dependent types that involve a
-/// possibly dependent nested-name-specifier (e.g., "T::") followed by a
-/// name of a type. The DependentNameType may start with a "typename" (for a
-/// typename-specifier), "class", "struct", "union", or "enum" (for a
-/// dependent elaborated-type-specifier), or nothing (in contexts where we
-/// know that we must be referring to a type, e.g., in a base class specifier).
-/// Typically the nested-name-specifier is dependent, but in MSVC compatibility
-/// mode, this type is used with non-dependent names to delay name lookup until
-/// instantiation.
-class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these
-
- /// The nested name specifier containing the qualifier.
- NestedNameSpecifier *NNS;
-
- /// The type that this typename specifier refers to.
- const IdentifierInfo *Name;
-
- DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
- const IdentifierInfo *Name, QualType CanonType)
- : TypeWithKeyword(Keyword, DependentName, CanonType,
- TypeDependence::DependentInstantiation |
- toTypeDependence(NNS->getDependence())),
- NNS(NNS), Name(Name) {
- assert(NNS);
- assert(Name);
- }
-
-public:
- /// Retrieve the qualification on this type.
- NestedNameSpecifier *getQualifier() const { return NNS; }
-
- /// Retrieve the identifier that terminates this type name.
- /// For example, "type" in "typename T::type".
- const IdentifierInfo *getIdentifier() const {
- return Name;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getKeyword(), NNS, Name);
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS, const IdentifierInfo *Name) {
- ID.AddInteger(llvm::to_underlying(Keyword));
- ID.AddPointer(NNS);
- ID.AddPointer(Name);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentName;
- }
-};
-
-/// Represents a template specialization type whose template cannot be
-/// resolved, e.g.
-/// A<T>::template B<T>
-class DependentTemplateSpecializationType : public TypeWithKeyword {
- friend class ASTContext; // ASTContext creates these
-
- DependentTemplateStorage Name;
-
- DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
- const DependentTemplateStorage &Name,
- ArrayRef<TemplateArgument> Args,
- QualType Canon);
-
-public:
- const DependentTemplateStorage &getDependentTemplateName() const {
- return Name;
- }
-
- ArrayRef<TemplateArgument> template_arguments() const {
- return {reinterpret_cast<const TemplateArgument *>(this + 1),
- DependentTemplateSpecializationTypeBits.NumArgs};
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, getKeyword(), Name, template_arguments());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- ElaboratedTypeKeyword Keyword,
- const DependentTemplateStorage &Name,
- ArrayRef<TemplateArgument> Args);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentTemplateSpecialization;
- }
-};
-
-/// Represents a pack expansion of types.
-///
-/// Pack expansions are part of C++11 variadic templates. A pack
-/// expansion contains a pattern, which itself contains one or more
-/// "unexpanded" parameter packs. When instantiated, a pack expansion
-/// produces a series of types, each instantiated from the pattern of
-/// the expansion, where the Ith instantiation of the pattern uses the
-/// Ith arguments bound to each of the unexpanded parameter packs. The
-/// pack expansion is considered to "expand" these unexpanded
-/// parameter packs.
-///
-/// \code
-/// template<typename ...Types> struct tuple;
-///
-/// template<typename ...Types>
-/// struct tuple_of_references {
-/// typedef tuple<Types&...> type;
-/// };
-/// \endcode
-///
-/// Here, the pack expansion \c Types&... is represented via a
-/// PackExpansionType whose pattern is Types&.
-class PackExpansionType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these
-
- /// The pattern of the pack expansion.
- QualType Pattern;
-
- PackExpansionType(QualType Pattern, QualType Canon,
- UnsignedOrNone NumExpansions)
- : Type(PackExpansion, Canon,
- (Pattern->getDependence() | TypeDependence::Dependent |
- TypeDependence::Instantiation) &
- ~TypeDependence::UnexpandedPack),
- Pattern(Pattern) {
- PackExpansionTypeBits.NumExpansions =
- NumExpansions ? *NumExpansions + 1 : 0;
- }
-
-public:
- /// Retrieve the pattern of this pack expansion, which is the
- /// type that will be repeatedly instantiated when instantiating the
- /// pack expansion itself.
- QualType getPattern() const { return Pattern; }
-
- /// Retrieve the number of expansions that this pack expansion will
- /// generate, if known.
- UnsignedOrNone getNumExpansions() const {
- if (PackExpansionTypeBits.NumExpansions)
- return PackExpansionTypeBits.NumExpansions - 1;
- return std::nullopt;
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPattern(), getNumExpansions());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern,
- UnsignedOrNone NumExpansions) {
- ID.AddPointer(Pattern.getAsOpaquePtr());
- ID.AddInteger(NumExpansions.toInternalRepresentation());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == PackExpansion;
- }
-};
-
-/// This class wraps the list of protocol qualifiers. For types that can
-/// take ObjC protocol qualifers, they can subclass this class.
-template <class T>
-class ObjCProtocolQualifiers {
-protected:
- ObjCProtocolQualifiers() = default;
-
- ObjCProtocolDecl * const *getProtocolStorage() const {
- return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage();
- }
-
- ObjCProtocolDecl **getProtocolStorage() {
- return static_cast<T*>(this)->getProtocolStorageImpl();
- }
-
- void setNumProtocols(unsigned N) {
- static_cast<T*>(this)->setNumProtocolsImpl(N);
- }
-
- void initialize(ArrayRef<ObjCProtocolDecl *> protocols) {
- setNumProtocols(protocols.size());
- assert(getNumProtocols() == protocols.size() &&
- "bitfield overflow in protocol count");
- if (!protocols.empty())
- memcpy(getProtocolStorage(), protocols.data(),
- protocols.size() * sizeof(ObjCProtocolDecl*));
- }
-
-public:
- using qual_iterator = ObjCProtocolDecl * const *;
- using qual_range = llvm::iterator_range<qual_iterator>;
-
- qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
- qual_iterator qual_begin() const { return getProtocolStorage(); }
- qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); }
-
- bool qual_empty() const { return getNumProtocols() == 0; }
-
- /// Return the number of qualifying protocols in this type, or 0 if
- /// there are none.
- unsigned getNumProtocols() const {
- return static_cast<const T*>(this)->getNumProtocolsImpl();
- }
-
- /// Fetch a protocol by index.
- ObjCProtocolDecl *getProtocol(unsigned I) const {
- assert(I < getNumProtocols() && "Out-of-range protocol access");
- return qual_begin()[I];
- }
-
- /// Retrieve all of the protocol qualifiers.
- ArrayRef<ObjCProtocolDecl *> getProtocols() const {
- return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols());
- }
-};
-
-/// Represents a type parameter type in Objective C. It can take
-/// a list of protocols.
-class ObjCTypeParamType : public Type,
- public ObjCProtocolQualifiers<ObjCTypeParamType>,
- public llvm::FoldingSetNode {
- friend class ASTContext;
- friend class ObjCProtocolQualifiers<ObjCTypeParamType>;
-
- /// The number of protocols stored on this type.
- unsigned NumProtocols : 6;
-
- ObjCTypeParamDecl *OTPDecl;
-
- /// The protocols are stored after the ObjCTypeParamType node. In the
- /// canonical type, the list of protocols are sorted alphabetically
- /// and uniqued.
- ObjCProtocolDecl **getProtocolStorageImpl();
-
- /// Return the number of qualifying protocols in this interface type,
- /// or 0 if there are none.
- unsigned getNumProtocolsImpl() const {
- return NumProtocols;
- }
-
- void setNumProtocolsImpl(unsigned N) {
- NumProtocols = N;
- }
-
- ObjCTypeParamType(const ObjCTypeParamDecl *D,
- QualType can,
- ArrayRef<ObjCProtocolDecl *> protocols);
-
-public:
- bool isSugared() const { return true; }
- QualType desugar() const { return getCanonicalTypeInternal(); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCTypeParam;
- }
-
- void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID,
- const ObjCTypeParamDecl *OTPDecl,
- QualType CanonicalType,
- ArrayRef<ObjCProtocolDecl *> protocols);
-
- ObjCTypeParamDecl *getDecl() const { return OTPDecl; }
-};
-
-/// Represents a class type in Objective C.
-///
-/// Every Objective C type is a combination of a base type, a set of
-/// type arguments (optional, for parameterized classes) and a list of
-/// protocols.
-///
-/// Given the following declarations:
-/// \code
-/// \@class C<T>;
-/// \@protocol P;
-/// \endcode
-///
-/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType
-/// with base C and no protocols.
-///
-/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P].
-/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no
-/// protocol list.
-/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*',
-/// and protocol list [P].
-///
-/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
-/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
-/// and no protocols.
-///
-/// 'id<P>' is an ObjCObjectPointerType whose pointee is an ObjCObjectType
-/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually
-/// this should get its own sugar class to better represent the source.
-class ObjCObjectType : public Type,
- public ObjCProtocolQualifiers<ObjCObjectType> {
- friend class ObjCProtocolQualifiers<ObjCObjectType>;
-
- // ObjCObjectType.NumTypeArgs - the number of type arguments stored
- // after the ObjCObjectPointerType node.
- // ObjCObjectType.NumProtocols - the number of protocols stored
- // after the type arguments of ObjCObjectPointerType node.
- //
- // These protocols are those written directly on the type. If
- // protocol qualifiers ever become additive, the iterators will need
- // to get kindof complicated.
- //
- // In the canonical object type, these are sorted alphabetically
- // and uniqued.
-
- /// Either a BuiltinType or an InterfaceType or sugar for either.
- QualType BaseType;
-
- /// Cached superclass type.
- mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool>
- CachedSuperClassType;
-
- QualType *getTypeArgStorage();
- const QualType *getTypeArgStorage() const {
- return const_cast<ObjCObjectType *>(this)->getTypeArgStorage();
- }
-
- ObjCProtocolDecl **getProtocolStorageImpl();
- /// Return the number of qualifying protocols in this interface type,
- /// or 0 if there are none.
- unsigned getNumProtocolsImpl() const {
- return ObjCObjectTypeBits.NumProtocols;
- }
- void setNumProtocolsImpl(unsigned N) {
- ObjCObjectTypeBits.NumProtocols = N;
- }
-
-protected:
- enum Nonce_ObjCInterface { Nonce_ObjCInterface };
-
- ObjCObjectType(QualType Canonical, QualType Base,
- ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf);
-
- ObjCObjectType(enum Nonce_ObjCInterface)
- : Type(ObjCInterface, QualType(), TypeDependence::None),
- BaseType(QualType(this_(), 0)) {
- ObjCObjectTypeBits.NumProtocols = 0;
- ObjCObjectTypeBits.NumTypeArgs = 0;
- ObjCObjectTypeBits.IsKindOf = 0;
- }
-
- void computeSuperClassTypeSlow() const;
-
-public:
- /// Gets the base type of this object type. This is always (possibly
- /// sugar for) one of:
- /// - the 'id' builtin type (as opposed to the 'id' type visible to the
- /// user, which is a typedef for an ObjCObjectPointerType)
- /// - the 'Class' builtin type (same caveat)
- /// - an ObjCObjectType (currently always an ObjCInterfaceType)
- QualType getBaseType() const { return BaseType; }
-
- bool isObjCId() const {
- return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId);
- }
-
- bool isObjCClass() const {
- return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass);
- }
-
- bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); }
- bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); }
- bool isObjCUnqualifiedIdOrClass() const {
- if (!qual_empty()) return false;
- if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>())
- return T->getKind() == BuiltinType::ObjCId ||
- T->getKind() == BuiltinType::ObjCClass;
- return false;
- }
- bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); }
- bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); }
-
- /// Gets the interface declaration for this object type, if the base type
- /// really is an interface.
- ObjCInterfaceDecl *getInterface() const;
-
- /// Determine whether this object type is "specialized", meaning
- /// that it has type arguments.
- bool isSpecialized() const;
-
- /// Determine whether this object type was written with type arguments.
- bool isSpecializedAsWritten() const {
- return ObjCObjectTypeBits.NumTypeArgs > 0;
- }
-
- /// Determine whether this object type is "unspecialized", meaning
- /// that it has no type arguments.
- bool isUnspecialized() const { return !isSpecialized(); }
-
- /// Determine whether this object type is "unspecialized" as
- /// written, meaning that it has no type arguments.
- bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
-
- /// Retrieve the type arguments of this object type (semantically).
- ArrayRef<QualType> getTypeArgs() const;
-
- /// Retrieve the type arguments of this object type as they were
- /// written.
- ArrayRef<QualType> getTypeArgsAsWritten() const {
- return {getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs};
- }
-
- /// Whether this is a "__kindof" type as written.
- bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; }
-
- /// Whether this ia a "__kindof" type (semantically).
- bool isKindOfType() const;
-
- /// Retrieve the type of the superclass of this object type.
- ///
- /// This operation substitutes any type arguments into the
- /// superclass of the current class type, potentially producing a
- /// specialization of the superclass type. Produces a null type if
- /// there is no superclass.
- QualType getSuperClassType() const {
- if (!CachedSuperClassType.getInt())
- computeSuperClassTypeSlow();
-
- assert(CachedSuperClassType.getInt() && "Superclass not set?");
- return QualType(CachedSuperClassType.getPointer(), 0);
- }
-
- /// Strip off the Objective-C "kindof" type and (with it) any
- /// protocol qualifiers.
- QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCObject ||
- T->getTypeClass() == ObjCInterface;
- }
-};
-
-/// A class providing a concrete implementation
-/// of ObjCObjectType, so as to not increase the footprint of
-/// ObjCInterfaceType. Code outside of ASTContext and the core type
-/// system should not reference this type.
-class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
- friend class ASTContext;
-
- // If anyone adds fields here, ObjCObjectType::getProtocolStorage()
- // will need to be modified.
-
- ObjCObjectTypeImpl(QualType Canonical, QualType Base,
- ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf)
- : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
-
-public:
- void Profile(llvm::FoldingSetNodeID &ID);
- static void Profile(llvm::FoldingSetNodeID &ID,
- QualType Base,
- ArrayRef<QualType> typeArgs,
- ArrayRef<ObjCProtocolDecl *> protocols,
- bool isKindOf);
-};
-
-inline QualType *ObjCObjectType::getTypeArgStorage() {
- return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1);
+inline CXXRecordDecl *Type::castAsCXXRecordDecl() const {
+ const auto *TT = cast<TagType>(CanonicalType);
+ return cast<CXXRecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf();
}
-inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() {
- return reinterpret_cast<ObjCProtocolDecl**>(
- getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
+inline RecordDecl *Type::getAsRecordDecl() const {
+ const auto *TT = dyn_cast<TagType>(CanonicalType);
+ if (!isa_and_present<RecordType, InjectedClassNameType>(TT))
+ return nullptr;
+ return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf();
}
-inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() {
- return reinterpret_cast<ObjCProtocolDecl**>(
- static_cast<ObjCTypeParamType*>(this)+1);
+inline RecordDecl *Type::castAsRecordDecl() const {
+ const auto *TT = cast<TagType>(CanonicalType);
+ return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf();
}
-/// Interfaces are the core concept in Objective-C for object oriented design.
-/// They basically correspond to C++ classes. There are two kinds of interface
-/// types: normal interfaces like `NSString`, and qualified interfaces, which
-/// are qualified with a protocol list like `NSString<NSCopyable, NSAmazing>`.
-///
-/// ObjCInterfaceType guarantees the following properties when considered
-/// as a subtype of its superclass, ObjCObjectType:
-/// - There are no protocol qualifiers. To reinforce this, code which
-/// tries to invoke the protocol methods via an ObjCInterfaceType will
-/// fail to compile.
-/// - It is its own base type. That is, if T is an ObjCInterfaceType*,
-/// T->getBaseType() == QualType(T, 0).
-class ObjCInterfaceType : public ObjCObjectType {
- friend class ASTContext; // ASTContext creates these.
- friend class ASTReader;
- template <class T> friend class serialization::AbstractTypeReader;
-
- ObjCInterfaceDecl *Decl;
-
- ObjCInterfaceType(const ObjCInterfaceDecl *D)
- : ObjCObjectType(Nonce_ObjCInterface),
- Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
-
-public:
- /// Get the declaration of this interface.
- ObjCInterfaceDecl *getDecl() const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCInterface;
- }
-
- // Nonsense to "hide" certain members of ObjCObjectType within this
- // class. People asking for protocols on an ObjCInterfaceType are
- // not going to get what they want: ObjCInterfaceTypes are
- // guaranteed to have no protocols.
- enum {
- qual_iterator,
- qual_begin,
- qual_end,
- getNumProtocols,
- getProtocol
- };
-};
-
-inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
- QualType baseType = getBaseType();
- while (const auto *ObjT = baseType->getAs<ObjCObjectType>()) {
- if (const auto *T = dyn_cast<ObjCInterfaceType>(ObjT))
- return T->getDecl();
-
- baseType = ObjT->getBaseType();
- }
-
+inline EnumDecl *Type::getAsEnumDecl() const {
+ if (const auto *TT = dyn_cast<EnumType>(CanonicalType))
+ return TT->getOriginalDecl()->getDefinitionOrSelf();
return nullptr;
}
-/// Represents a pointer to an Objective C object.
-///
-/// These are constructed from pointer declarators when the pointee type is
-/// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class'
-/// types are typedefs for these, and the protocol-qualified types 'id<P>'
-/// and 'Class<P>' are translated into these.
-///
-/// Pointers to pointers to Objective C objects are still PointerTypes;
-/// only the first level of pointer gets it own type implementation.
-class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType PointeeType;
-
- ObjCObjectPointerType(QualType Canonical, QualType Pointee)
- : Type(ObjCObjectPointer, Canonical, Pointee->getDependence()),
- PointeeType(Pointee) {}
-
-public:
- /// Gets the type pointed to by this ObjC pointer.
- /// The result will always be an ObjCObjectType or sugar thereof.
- QualType getPointeeType() const { return PointeeType; }
-
- /// Gets the type pointed to by this ObjC pointer. Always returns non-null.
- ///
- /// This method is equivalent to getPointeeType() except that
- /// it discards any typedefs (or other sugar) between this
- /// type and the "outermost" object type. So for:
- /// \code
- /// \@class A; \@protocol P; \@protocol Q;
- /// typedef A<P> AP;
- /// typedef A A1;
- /// typedef A1<P> A1P;
- /// typedef A1P<Q> A1PQ;
- /// \endcode
- /// For 'A*', getObjectType() will return 'A'.
- /// For 'A<P>*', getObjectType() will return 'A<P>'.
- /// For 'AP*', getObjectType() will return 'A<P>'.
- /// For 'A1*', getObjectType() will return 'A'.
- /// For 'A1<P>*', getObjectType() will return 'A1<P>'.
- /// For 'A1P*', getObjectType() will return 'A1<P>'.
- /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because
- /// adding protocols to a protocol-qualified base discards the
- /// old qualifiers (for now). But if it didn't, getObjectType()
- /// would return 'A1P<Q>' (and we'd have to make iterating over
- /// qualifiers more complicated).
- const ObjCObjectType *getObjectType() const {
- return PointeeType->castAs<ObjCObjectType>();
- }
-
- /// If this pointer points to an Objective C
- /// \@interface type, gets the type for that interface. Any protocol
- /// qualifiers on the interface are ignored.
- ///
- /// \return null if the base type for this pointer is 'id' or 'Class'
- const ObjCInterfaceType *getInterfaceType() const;
-
- /// If this pointer points to an Objective \@interface
- /// type, gets the declaration for that interface.
- ///
- /// \return null if the base type for this pointer is 'id' or 'Class'
- ObjCInterfaceDecl *getInterfaceDecl() const {
- return getObjectType()->getInterface();
- }
-
- /// True if this is equivalent to the 'id' type, i.e. if
- /// its object type is the primitive 'id' type with no protocols.
- bool isObjCIdType() const {
- return getObjectType()->isObjCUnqualifiedId();
- }
-
- /// True if this is equivalent to the 'Class' type,
- /// i.e. if its object tive is the primitive 'Class' type with no protocols.
- bool isObjCClassType() const {
- return getObjectType()->isObjCUnqualifiedClass();
- }
-
- /// True if this is equivalent to the 'id' or 'Class' type,
- bool isObjCIdOrClassType() const {
- return getObjectType()->isObjCUnqualifiedIdOrClass();
- }
-
- /// True if this is equivalent to 'id<P>' for some non-empty set of
- /// protocols.
- bool isObjCQualifiedIdType() const {
- return getObjectType()->isObjCQualifiedId();
- }
-
- /// True if this is equivalent to 'Class<P>' for some non-empty set of
- /// protocols.
- bool isObjCQualifiedClassType() const {
- return getObjectType()->isObjCQualifiedClass();
- }
-
- /// Whether this is a "__kindof" type.
- bool isKindOfType() const { return getObjectType()->isKindOfType(); }
-
- /// Whether this type is specialized, meaning that it has type arguments.
- bool isSpecialized() const { return getObjectType()->isSpecialized(); }
-
- /// Whether this type is specialized, meaning that it has type arguments.
- bool isSpecializedAsWritten() const {
- return getObjectType()->isSpecializedAsWritten();
- }
-
- /// Whether this type is unspecialized, meaning that is has no type arguments.
- bool isUnspecialized() const { return getObjectType()->isUnspecialized(); }
-
- /// Determine whether this object type is "unspecialized" as
- /// written, meaning that it has no type arguments.
- bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
-
- /// Retrieve the type arguments for this type.
- ArrayRef<QualType> getTypeArgs() const {
- return getObjectType()->getTypeArgs();
- }
-
- /// Retrieve the type arguments for this type.
- ArrayRef<QualType> getTypeArgsAsWritten() const {
- return getObjectType()->getTypeArgsAsWritten();
- }
-
- /// An iterator over the qualifiers on the object type. Provided
- /// for convenience. This will always iterate over the full set of
- /// protocols on a type, not just those provided directly.
- using qual_iterator = ObjCObjectType::qual_iterator;
- using qual_range = llvm::iterator_range<qual_iterator>;
-
- qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
-
- qual_iterator qual_begin() const {
- return getObjectType()->qual_begin();
- }
-
- qual_iterator qual_end() const {
- return getObjectType()->qual_end();
- }
-
- bool qual_empty() const { return getObjectType()->qual_empty(); }
-
- /// Return the number of qualifying protocols on the object type.
- unsigned getNumProtocols() const {
- return getObjectType()->getNumProtocols();
- }
-
- /// Retrieve a qualifying protocol by index on the object type.
- ObjCProtocolDecl *getProtocol(unsigned I) const {
- return getObjectType()->getProtocol(I);
- }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- /// Retrieve the type of the superclass of this object pointer type.
- ///
- /// This operation substitutes any type arguments into the
- /// superclass of the current class type, potentially producing a
- /// pointer to a specialization of the superclass type. Produces a
- /// null type if there is no superclass.
- QualType getSuperClassType() const;
-
- /// Strip off the Objective-C "kindof" type and (with it) any
- /// protocol qualifiers.
- const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
- const ASTContext &ctx) const;
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getPointeeType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
- ID.AddPointer(T.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == ObjCObjectPointer;
- }
-};
-
-class AtomicType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType ValueType;
-
- AtomicType(QualType ValTy, QualType Canonical)
- : Type(Atomic, Canonical, ValTy->getDependence()), ValueType(ValTy) {}
-
-public:
- /// Gets the type contained by this atomic type, i.e.
- /// the type returned by performing an atomic load of this atomic type.
- QualType getValueType() const { return ValueType; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getValueType());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
- ID.AddPointer(T.getAsOpaquePtr());
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Atomic;
- }
-};
-
-/// PipeType - OpenCL20.
-class PipeType : public Type, public llvm::FoldingSetNode {
- friend class ASTContext; // ASTContext creates these.
-
- QualType ElementType;
- bool isRead;
-
- PipeType(QualType elemType, QualType CanonicalPtr, bool isRead)
- : Type(Pipe, CanonicalPtr, elemType->getDependence()),
- ElementType(elemType), isRead(isRead) {}
-
-public:
- QualType getElementType() const { return ElementType; }
-
- bool isSugared() const { return false; }
-
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), isReadOnly());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) {
- ID.AddPointer(T.getAsOpaquePtr());
- ID.AddBoolean(isRead);
- }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == Pipe;
- }
-
- bool isReadOnly() const { return isRead; }
-};
-
-/// A fixed int type of a specified bitwidth.
-class BitIntType final : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsUnsigned : 1;
- unsigned NumBits : 24;
-
-protected:
- BitIntType(bool isUnsigned, unsigned NumBits);
-
-public:
- bool isUnsigned() const { return IsUnsigned; }
- bool isSigned() const { return !IsUnsigned; }
- unsigned getNumBits() const { return NumBits; }
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- Profile(ID, isUnsigned(), getNumBits());
- }
-
- static void Profile(llvm::FoldingSetNodeID &ID, bool IsUnsigned,
- unsigned NumBits) {
- ID.AddBoolean(IsUnsigned);
- ID.AddInteger(NumBits);
- }
-
- static bool classof(const Type *T) { return T->getTypeClass() == BitInt; }
-};
-
-class DependentBitIntType final : public Type, public llvm::FoldingSetNode {
- friend class ASTContext;
- llvm::PointerIntPair<Expr*, 1, bool> ExprAndUnsigned;
-
-protected:
- DependentBitIntType(bool IsUnsigned, Expr *NumBits);
-
-public:
- bool isUnsigned() const;
- bool isSigned() const { return !isUnsigned(); }
- Expr *getNumBitsExpr() const;
-
- bool isSugared() const { return false; }
- QualType desugar() const { return QualType(this, 0); }
-
- void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
- Profile(ID, Context, isUnsigned(), getNumBitsExpr());
- }
- static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
- bool IsUnsigned, Expr *NumBitsExpr);
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == DependentBitInt;
- }
-};
-
-class PredefinedSugarType final : public Type {
-public:
- friend class ASTContext;
- using Kind = PredefinedSugarKind;
-
-private:
- PredefinedSugarType(Kind KD, const IdentifierInfo *IdentName,
- QualType CanonicalType)
- : Type(PredefinedSugar, CanonicalType, TypeDependence::None),
- Name(IdentName) {
- PredefinedSugarTypeBits.Kind = llvm::to_underlying(KD);
- }
-
- static StringRef getName(Kind KD);
-
- const IdentifierInfo *Name;
-
-public:
- bool isSugared() const { return true; }
-
- QualType desugar() const { return getCanonicalTypeInternal(); }
-
- Kind getKind() const { return Kind(PredefinedSugarTypeBits.Kind); }
-
- const IdentifierInfo *getIdentifier() const { return Name; }
-
- static bool classof(const Type *T) {
- return T->getTypeClass() == PredefinedSugar;
- }
-};
-
-/// A qualifier set is used to build a set of qualifiers.
-class QualifierCollector : public Qualifiers {
-public:
- QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {}
-
- /// Collect any qualifiers on the given type and return an
- /// unqualified type. The qualifiers are assumed to be consistent
- /// with those already in the type.
- const Type *strip(QualType type) {
- addFastQualifiers(type.getLocalFastQualifiers());
- if (!type.hasLocalNonFastQualifiers())
- return type.getTypePtrUnsafe();
-
- const ExtQuals *extQuals = type.getExtQualsUnsafe();
- addConsistentQualifiers(extQuals->getQualifiers());
- return extQuals->getBaseType();
- }
-
- /// Apply the collected qualifiers to the given type.
- QualType apply(const ASTContext &Context, QualType QT) const;
-
- /// Apply the collected qualifiers to the given type.
- QualType apply(const ASTContext &Context, const Type* T) const;
-};
-
-/// A container of type source information.
-///
-/// A client can read the relevant info using TypeLoc wrappers, e.g:
-/// @code
-/// TypeLoc TL = TypeSourceInfo->getTypeLoc();
-/// TL.getBeginLoc().print(OS, SrcMgr);
-/// @endcode
-class alignas(8) TypeSourceInfo {
- // Contains a memory block after the class, used for type source information,
- // allocated by ASTContext.
- friend class ASTContext;
-
- QualType Ty;
-
- TypeSourceInfo(QualType ty, size_t DataSize); // implemented in TypeLoc.h
-
-public:
- /// Return the type wrapped by this type source info.
- QualType getType() const { return Ty; }
-
- /// Return the TypeLoc wrapper for the type source info.
- TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
-
- /// Override the type stored in this TypeSourceInfo. Use with caution!
- void overrideType(QualType T) { Ty = T; }
-};
-
-// Inline function definitions.
-
-inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {
- SplitQualType desugar =
- Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
- desugar.Quals.addConsistentQualifiers(Quals);
- return desugar;
-}
-
-inline const Type *QualType::getTypePtr() const {
- return getCommonPtr()->BaseType;
-}
-
-inline const Type *QualType::getTypePtrOrNull() const {
- return (isNull() ? nullptr : getCommonPtr()->BaseType);
-}
-
-inline bool QualType::isReferenceable() const {
- // C++ [defns.referenceable]
- // type that is either an object type, a function type that does not have
- // cv-qualifiers or a ref-qualifier, or a reference type.
- const Type &Self = **this;
- if (Self.isObjectType() || Self.isReferenceType())
- return true;
- if (const auto *F = Self.getAs<FunctionProtoType>())
- return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
-
- return false;
-}
-
-inline SplitQualType QualType::split() const {
- if (!hasLocalNonFastQualifiers())
- return SplitQualType(getTypePtrUnsafe(),
- Qualifiers::fromFastMask(getLocalFastQualifiers()));
-
- const ExtQuals *eq = getExtQualsUnsafe();
- Qualifiers qs = eq->getQualifiers();
- qs.addFastQualifiers(getLocalFastQualifiers());
- return SplitQualType(eq->getBaseType(), qs);
-}
-
-inline Qualifiers QualType::getLocalQualifiers() const {
- Qualifiers Quals;
- if (hasLocalNonFastQualifiers())
- Quals = getExtQualsUnsafe()->getQualifiers();
- Quals.addFastQualifiers(getLocalFastQualifiers());
- return Quals;
-}
-
-inline Qualifiers QualType::getQualifiers() const {
- Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers();
- quals.addFastQualifiers(getLocalFastQualifiers());
- return quals;
-}
-
-inline unsigned QualType::getCVRQualifiers() const {
- unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers();
- cvr |= getLocalCVRQualifiers();
- return cvr;
-}
-
-inline QualType QualType::getCanonicalType() const {
- QualType canon = getCommonPtr()->CanonicalType;
- return canon.withFastQualifiers(getLocalFastQualifiers());
-}
-
-inline bool QualType::isCanonical() const {
- return getTypePtr()->isCanonicalUnqualified();
-}
-
-inline bool QualType::isCanonicalAsParam() const {
- if (!isCanonical()) return false;
- if (hasLocalQualifiers()) return false;
-
- const Type *T = getTypePtr();
- if (T->isVariablyModifiedType() && T->hasSizedVLAType())
- return false;
-
- return !isa<FunctionType>(T) &&
- (!isa<ArrayType>(T) || isa<ArrayParameterType>(T));
-}
-
-inline bool QualType::isConstQualified() const {
- return isLocalConstQualified() ||
- getCommonPtr()->CanonicalType.isLocalConstQualified();
-}
-
-inline bool QualType::isRestrictQualified() const {
- return isLocalRestrictQualified() ||
- getCommonPtr()->CanonicalType.isLocalRestrictQualified();
-}
-
-
-inline bool QualType::isVolatileQualified() const {
- return isLocalVolatileQualified() ||
- getCommonPtr()->CanonicalType.isLocalVolatileQualified();
-}
-
-inline bool QualType::hasQualifiers() const {
- return hasLocalQualifiers() ||
- getCommonPtr()->CanonicalType.hasLocalQualifiers();
-}
-
-inline QualType QualType::getUnqualifiedType() const {
- if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
- return QualType(getTypePtr(), 0);
-
- return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0);
-}
-
-inline SplitQualType QualType::getSplitUnqualifiedType() const {
- if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
- return split();
-
- return getSplitUnqualifiedTypeImpl(*this);
-}
-
-inline void QualType::removeLocalConst() {
- removeLocalFastQualifiers(Qualifiers::Const);
-}
-
-inline void QualType::removeLocalRestrict() {
- removeLocalFastQualifiers(Qualifiers::Restrict);
-}
-
-inline void QualType::removeLocalVolatile() {
- removeLocalFastQualifiers(Qualifiers::Volatile);
-}
-
-/// Check if this type has any address space qualifier.
-inline bool QualType::hasAddressSpace() const {
- return getQualifiers().hasAddressSpace();
+inline EnumDecl *Type::castAsEnumDecl() const {
+ return cast<EnumType>(CanonicalType)
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf();
}
-/// Return the address space of this type.
-inline LangAS QualType::getAddressSpace() const {
- return getQualifiers().getAddressSpace();
+inline TagDecl *Type::getAsTagDecl() const {
+ if (const auto *TT = dyn_cast<TagType>(CanonicalType))
+ return TT->getOriginalDecl()->getDefinitionOrSelf();
+ return nullptr;
}
-/// Return the gc attribute of this type.
-inline Qualifiers::GC QualType::getObjCGCAttr() const {
- return getQualifiers().getObjCGCAttr();
+inline TagDecl *Type::castAsTagDecl() const {
+ return cast<TagType>(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf();
}
inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const {
@@ -8307,809 +90,6 @@ inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const {
return false;
}
-inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
- if (const auto *PT = t.getAs<PointerType>()) {
- if (const auto *FT = PT->getPointeeType()->getAs<FunctionType>())
- return FT->getExtInfo();
- } else if (const auto *FT = t.getAs<FunctionType>())
- return FT->getExtInfo();
-
- return FunctionType::ExtInfo();
-}
-
-inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
- return getFunctionExtInfo(*t);
-}
-
-/// Determine whether this type is more
-/// qualified than the Other type. For example, "const volatile int"
-/// is more qualified than "const int", "volatile int", and
-/// "int". However, it is not more qualified than "const volatile
-/// int".
-inline bool QualType::isMoreQualifiedThan(QualType other,
- const ASTContext &Ctx) const {
- Qualifiers MyQuals = getQualifiers();
- Qualifiers OtherQuals = other.getQualifiers();
- return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx));
-}
-
-/// Determine whether this type is at last
-/// as qualified as the Other type. For example, "const volatile
-/// int" is at least as qualified as "const int", "volatile int",
-/// "int", and "const volatile int".
-inline bool QualType::isAtLeastAsQualifiedAs(QualType other,
- const ASTContext &Ctx) const {
- Qualifiers OtherQuals = other.getQualifiers();
-
- // Ignore __unaligned qualifier if this type is a void.
- if (getUnqualifiedType()->isVoidType())
- OtherQuals.removeUnaligned();
-
- return getQualifiers().compatiblyIncludes(OtherQuals, Ctx);
-}
-
-/// If Type is a reference type (e.g., const
-/// int&), returns the type that the reference refers to ("const
-/// int"). Otherwise, returns the type itself. This routine is used
-/// throughout Sema to implement C++ 5p6:
-///
-/// If an expression initially has the type "reference to T" (8.3.2,
-/// 8.5.3), the type is adjusted to "T" prior to any further
-/// analysis, the expression designates the object or function
-/// denoted by the reference, and the expression is an lvalue.
-inline QualType QualType::getNonReferenceType() const {
- if (const auto *RefType = (*this)->getAs<ReferenceType>())
- return RefType->getPointeeType();
- else
- return *this;
-}
-
-inline bool QualType::isCForbiddenLValueType() const {
- return ((getTypePtr()->isVoidType() && !hasQualifiers()) ||
- getTypePtr()->isFunctionType());
-}
-
-/// Tests whether the type is categorized as a fundamental type.
-///
-/// \returns True for types specified in C++0x [basic.fundamental].
-inline bool Type::isFundamentalType() const {
- return isVoidType() ||
- isNullPtrType() ||
- // FIXME: It's really annoying that we don't have an
- // 'isArithmeticType()' which agrees with the standard definition.
- (isArithmeticType() && !isEnumeralType());
-}
-
-/// Tests whether the type is categorized as a compound type.
-///
-/// \returns True for types specified in C++0x [basic.compound].
-inline bool Type::isCompoundType() const {
- // C++0x [basic.compound]p1:
- // Compound types can be constructed in the following ways:
- // -- arrays of objects of a given type [...];
- return isArrayType() ||
- // -- functions, which have parameters of given types [...];
- isFunctionType() ||
- // -- pointers to void or objects or functions [...];
- isPointerType() ||
- // -- references to objects or functions of a given type. [...]
- isReferenceType() ||
- // -- classes containing a sequence of objects of various types, [...];
- isRecordType() ||
- // -- unions, which are classes capable of containing objects of different
- // types at different times;
- isUnionType() ||
- // -- enumerations, which comprise a set of named constant values. [...];
- isEnumeralType() ||
- // -- pointers to non-static class members, [...].
- isMemberPointerType();
-}
-
-inline bool Type::isFunctionType() const {
- return isa<FunctionType>(CanonicalType);
-}
-
-inline bool Type::isPointerType() const {
- return isa<PointerType>(CanonicalType);
-}
-
-inline bool Type::isPointerOrReferenceType() const {
- return isPointerType() || isReferenceType();
-}
-
-inline bool Type::isAnyPointerType() const {
- return isPointerType() || isObjCObjectPointerType();
-}
-
-inline bool Type::isSignableType(const ASTContext &Ctx) const {
- return isSignablePointerType() || isSignableIntegerType(Ctx);
-}
-
-inline bool Type::isSignablePointerType() const {
- return isPointerType() || isObjCClassType() || isObjCQualifiedClassType();
-}
-
-inline bool Type::isBlockPointerType() const {
- return isa<BlockPointerType>(CanonicalType);
-}
-
-inline bool Type::isReferenceType() const {
- return isa<ReferenceType>(CanonicalType);
-}
-
-inline bool Type::isLValueReferenceType() const {
- return isa<LValueReferenceType>(CanonicalType);
-}
-
-inline bool Type::isRValueReferenceType() const {
- return isa<RValueReferenceType>(CanonicalType);
-}
-
-inline bool Type::isObjectPointerType() const {
- // Note: an "object pointer type" is not the same thing as a pointer to an
- // object type; rather, it is a pointer to an object type or a pointer to cv
- // void.
- if (const auto *T = getAs<PointerType>())
- return !T->getPointeeType()->isFunctionType();
- else
- return false;
-}
-
-inline bool Type::isCFIUncheckedCalleeFunctionType() const {
- if (const auto *Fn = getAs<FunctionProtoType>())
- return Fn->hasCFIUncheckedCallee();
- return false;
-}
-
-inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const {
- QualType Pointee;
- if (const auto *PT = getAs<PointerType>())
- Pointee = PT->getPointeeType();
- else if (const auto *RT = getAs<ReferenceType>())
- Pointee = RT->getPointeeType();
- else if (const auto *MPT = getAs<MemberPointerType>())
- Pointee = MPT->getPointeeType();
- else if (const auto *DT = getAs<DecayedType>())
- Pointee = DT->getPointeeType();
- else
- return false;
- return Pointee->isCFIUncheckedCalleeFunctionType();
-}
-
-inline bool Type::isFunctionPointerType() const {
- if (const auto *T = getAs<PointerType>())
- return T->getPointeeType()->isFunctionType();
- else
- return false;
-}
-
-inline bool Type::isFunctionReferenceType() const {
- if (const auto *T = getAs<ReferenceType>())
- return T->getPointeeType()->isFunctionType();
- else
- return false;
-}
-
-inline bool Type::isMemberPointerType() const {
- return isa<MemberPointerType>(CanonicalType);
-}
-
-inline bool Type::isMemberFunctionPointerType() const {
- if (const auto *T = getAs<MemberPointerType>())
- return T->isMemberFunctionPointer();
- else
- return false;
-}
-
-inline bool Type::isMemberDataPointerType() const {
- if (const auto *T = getAs<MemberPointerType>())
- return T->isMemberDataPointer();
- else
- return false;
-}
-
-inline bool Type::isArrayType() const {
- return isa<ArrayType>(CanonicalType);
-}
-
-inline bool Type::isConstantArrayType() const {
- return isa<ConstantArrayType>(CanonicalType);
-}
-
-inline bool Type::isIncompleteArrayType() const {
- return isa<IncompleteArrayType>(CanonicalType);
-}
-
-inline bool Type::isVariableArrayType() const {
- return isa<VariableArrayType>(CanonicalType);
-}
-
-inline bool Type::isArrayParameterType() const {
- return isa<ArrayParameterType>(CanonicalType);
-}
-
-inline bool Type::isDependentSizedArrayType() const {
- return isa<DependentSizedArrayType>(CanonicalType);
-}
-
-inline bool Type::isBuiltinType() const {
- return isa<BuiltinType>(CanonicalType);
-}
-
-inline bool Type::isRecordType() const {
- return isa<RecordType>(CanonicalType);
-}
-
-inline bool Type::isEnumeralType() const {
- return isa<EnumType>(CanonicalType);
-}
-
-inline bool Type::isAnyComplexType() const {
- return isa<ComplexType>(CanonicalType);
-}
-
-inline bool Type::isVectorType() const {
- return isa<VectorType>(CanonicalType);
-}
-
-inline bool Type::isExtVectorType() const {
- return isa<ExtVectorType>(CanonicalType);
-}
-
-inline bool Type::isExtVectorBoolType() const {
- if (!isExtVectorType())
- return false;
- return cast<ExtVectorType>(CanonicalType)->getElementType()->isBooleanType();
-}
-
-inline bool Type::isSubscriptableVectorType() const {
- return isVectorType() || isSveVLSBuiltinType();
-}
-
-inline bool Type::isMatrixType() const {
- return isa<MatrixType>(CanonicalType);
-}
-
-inline bool Type::isConstantMatrixType() const {
- return isa<ConstantMatrixType>(CanonicalType);
-}
-
-inline bool Type::isDependentAddressSpaceType() const {
- return isa<DependentAddressSpaceType>(CanonicalType);
-}
-
-inline bool Type::isObjCObjectPointerType() const {
- return isa<ObjCObjectPointerType>(CanonicalType);
-}
-
-inline bool Type::isObjCObjectType() const {
- return isa<ObjCObjectType>(CanonicalType);
-}
-
-inline bool Type::isObjCObjectOrInterfaceType() const {
- return isa<ObjCInterfaceType>(CanonicalType) ||
- isa<ObjCObjectType>(CanonicalType);
-}
-
-inline bool Type::isAtomicType() const {
- return isa<AtomicType>(CanonicalType);
-}
-
-inline bool Type::isUndeducedAutoType() const {
- return isa<AutoType>(CanonicalType);
-}
-
-inline bool Type::isObjCQualifiedIdType() const {
- if (const auto *OPT = getAs<ObjCObjectPointerType>())
- return OPT->isObjCQualifiedIdType();
- return false;
-}
-
-inline bool Type::isObjCQualifiedClassType() const {
- if (const auto *OPT = getAs<ObjCObjectPointerType>())
- return OPT->isObjCQualifiedClassType();
- return false;
-}
-
-inline bool Type::isObjCIdType() const {
- if (const auto *OPT = getAs<ObjCObjectPointerType>())
- return OPT->isObjCIdType();
- return false;
-}
-
-inline bool Type::isObjCClassType() const {
- if (const auto *OPT = getAs<ObjCObjectPointerType>())
- return OPT->isObjCClassType();
- return false;
-}
-
-inline bool Type::isObjCSelType() const {
- if (const auto *OPT = getAs<PointerType>())
- return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel);
- return false;
-}
-
-inline bool Type::isObjCBuiltinType() const {
- return isObjCIdType() || isObjCClassType() || isObjCSelType();
-}
-
-inline bool Type::isDecltypeType() const {
- return isa<DecltypeType>(this);
-}
-
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- inline bool Type::is##Id##Type() const { \
- return isSpecificBuiltinType(BuiltinType::Id); \
- }
-#include "clang/Basic/OpenCLImageTypes.def"
-
-inline bool Type::isSamplerT() const {
- return isSpecificBuiltinType(BuiltinType::OCLSampler);
-}
-
-inline bool Type::isEventT() const {
- return isSpecificBuiltinType(BuiltinType::OCLEvent);
-}
-
-inline bool Type::isClkEventT() const {
- return isSpecificBuiltinType(BuiltinType::OCLClkEvent);
-}
-
-inline bool Type::isQueueT() const {
- return isSpecificBuiltinType(BuiltinType::OCLQueue);
-}
-
-inline bool Type::isReserveIDT() const {
- return isSpecificBuiltinType(BuiltinType::OCLReserveID);
-}
-
-inline bool Type::isImageType() const {
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() ||
- return
-#include "clang/Basic/OpenCLImageTypes.def"
- false; // end boolean or operation
-}
-
-inline bool Type::isPipeType() const {
- return isa<PipeType>(CanonicalType);
-}
-
-inline bool Type::isBitIntType() const {
- return isa<BitIntType>(CanonicalType);
-}
-
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- inline bool Type::is##Id##Type() const { \
- return isSpecificBuiltinType(BuiltinType::Id); \
- }
-#include "clang/Basic/OpenCLExtensionTypes.def"
-
-inline bool Type::isOCLIntelSubgroupAVCType() const {
-#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \
- isOCLIntelSubgroupAVC##Id##Type() ||
- return
-#include "clang/Basic/OpenCLExtensionTypes.def"
- false; // end of boolean or operation
-}
-
-inline bool Type::isOCLExtOpaqueType() const {
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() ||
- return
-#include "clang/Basic/OpenCLExtensionTypes.def"
- false; // end of boolean or operation
-}
-
-inline bool Type::isOpenCLSpecificType() const {
- return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType();
-}
-
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \
- inline bool Type::is##Id##Type() const { \
- return isSpecificBuiltinType(BuiltinType::Id); \
- }
-#include "clang/Basic/HLSLIntangibleTypes.def"
-
-inline bool Type::isHLSLBuiltinIntangibleType() const {
-#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
- return
-#include "clang/Basic/HLSLIntangibleTypes.def"
- false;
-}
-
-inline bool Type::isHLSLSpecificType() const {
- return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType() ||
- isHLSLInlineSpirvType();
-}
-
-inline bool Type::isHLSLAttributedResourceType() const {
- return isa<HLSLAttributedResourceType>(this);
-}
-
-inline bool Type::isHLSLInlineSpirvType() const {
- return isa<HLSLInlineSpirvType>(this);
-}
-
-inline bool Type::isTemplateTypeParmType() const {
- return isa<TemplateTypeParmType>(CanonicalType);
-}
-
-inline bool Type::isSpecificBuiltinType(unsigned K) const {
- if (const BuiltinType *BT = getAs<BuiltinType>()) {
- return BT->getKind() == static_cast<BuiltinType::Kind>(K);
- }
- return false;
-}
-
-inline bool Type::isPlaceholderType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(this))
- return BT->isPlaceholderType();
- return false;
-}
-
-inline const BuiltinType *Type::getAsPlaceholderType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(this))
- if (BT->isPlaceholderType())
- return BT;
- return nullptr;
-}
-
-inline bool Type::isSpecificPlaceholderType(unsigned K) const {
- assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K));
- return isSpecificBuiltinType(K);
-}
-
-inline bool Type::isNonOverloadPlaceholderType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(this))
- return BT->isNonOverloadPlaceholderType();
- return false;
-}
-
-inline bool Type::isVoidType() const {
- return isSpecificBuiltinType(BuiltinType::Void);
-}
-
-inline bool Type::isHalfType() const {
- // FIXME: Should we allow complex __fp16? Probably not.
- return isSpecificBuiltinType(BuiltinType::Half);
-}
-
-inline bool Type::isFloat16Type() const {
- return isSpecificBuiltinType(BuiltinType::Float16);
-}
-
-inline bool Type::isFloat32Type() const {
- return isSpecificBuiltinType(BuiltinType::Float);
-}
-
-inline bool Type::isDoubleType() const {
- return isSpecificBuiltinType(BuiltinType::Double);
-}
-
-inline bool Type::isBFloat16Type() const {
- return isSpecificBuiltinType(BuiltinType::BFloat16);
-}
-
-inline bool Type::isMFloat8Type() const {
- return isSpecificBuiltinType(BuiltinType::MFloat8);
-}
-
-inline bool Type::isFloat128Type() const {
- return isSpecificBuiltinType(BuiltinType::Float128);
-}
-
-inline bool Type::isIbm128Type() const {
- return isSpecificBuiltinType(BuiltinType::Ibm128);
-}
-
-inline bool Type::isNullPtrType() const {
- return isSpecificBuiltinType(BuiltinType::NullPtr);
-}
-
-bool IsEnumDeclComplete(EnumDecl *);
-bool IsEnumDeclScoped(EnumDecl *);
-
-inline bool Type::isIntegerType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->isInteger();
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
- // Incomplete enum types are not treated as integer types.
- // FIXME: In C++, enum types are never integer types.
- return IsEnumDeclComplete(ET->getDecl()) &&
- !IsEnumDeclScoped(ET->getDecl());
- }
- return isBitIntType();
-}
-
-inline bool Type::isFixedPointType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
- return BT->getKind() >= BuiltinType::ShortAccum &&
- BT->getKind() <= BuiltinType::SatULongFract;
- }
- return false;
-}
-
-inline bool Type::isFixedPointOrIntegerType() const {
- return isFixedPointType() || isIntegerType();
-}
-
-inline bool Type::isConvertibleToFixedPointType() const {
- return isRealFloatingType() || isFixedPointOrIntegerType();
-}
-
-inline bool Type::isSaturatedFixedPointType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
- return BT->getKind() >= BuiltinType::SatShortAccum &&
- BT->getKind() <= BuiltinType::SatULongFract;
- }
- return false;
-}
-
-inline bool Type::isUnsaturatedFixedPointType() const {
- return isFixedPointType() && !isSaturatedFixedPointType();
-}
-
-inline bool Type::isSignedFixedPointType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
- return ((BT->getKind() >= BuiltinType::ShortAccum &&
- BT->getKind() <= BuiltinType::LongAccum) ||
- (BT->getKind() >= BuiltinType::ShortFract &&
- BT->getKind() <= BuiltinType::LongFract) ||
- (BT->getKind() >= BuiltinType::SatShortAccum &&
- BT->getKind() <= BuiltinType::SatLongAccum) ||
- (BT->getKind() >= BuiltinType::SatShortFract &&
- BT->getKind() <= BuiltinType::SatLongFract));
- }
- return false;
-}
-
-inline bool Type::isUnsignedFixedPointType() const {
- return isFixedPointType() && !isSignedFixedPointType();
-}
-
-inline bool Type::isScalarType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() > BuiltinType::Void &&
- BT->getKind() <= BuiltinType::NullPtr;
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- // Enums are scalar types, but only if they are defined. Incomplete enums
- // are not treated as scalar types.
- return IsEnumDeclComplete(ET->getDecl());
- return isa<PointerType>(CanonicalType) ||
- isa<BlockPointerType>(CanonicalType) ||
- isa<MemberPointerType>(CanonicalType) ||
- isa<ComplexType>(CanonicalType) ||
- isa<ObjCObjectPointerType>(CanonicalType) ||
- isBitIntType();
-}
-
-inline bool Type::isIntegralOrEnumerationType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->isInteger();
-
- // Check for a complete enum type; incomplete enum types are not properly an
- // enumeration type in the sense required here.
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return IsEnumDeclComplete(ET->getDecl());
-
- return isBitIntType();
-}
-
-inline bool Type::isBooleanType() const {
- if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() == BuiltinType::Bool;
- return false;
-}
-
-inline bool Type::isUndeducedType() const {
- auto *DT = getContainedDeducedType();
- return DT && !DT->isDeduced();
-}
-
-/// Determines whether this is a type for which one can define
-/// an overloaded operator.
-inline bool Type::isOverloadableType() const {
- if (!isDependentType())
- return isRecordType() || isEnumeralType();
- return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
- !isMemberPointerType();
-}
-
-/// Determines whether this type is written as a typedef-name.
-inline bool Type::isTypedefNameType() const {
- if (getAs<TypedefType>())
- return true;
- if (auto *TST = getAs<TemplateSpecializationType>())
- return TST->isTypeAlias();
- return false;
-}
-
-/// Determines whether this type can decay to a pointer type.
-inline bool Type::canDecayToPointerType() const {
- return isFunctionType() || (isArrayType() && !isArrayParameterType());
-}
-
-inline bool Type::hasPointerRepresentation() const {
- return (isPointerType() || isReferenceType() || isBlockPointerType() ||
- isObjCObjectPointerType() || isNullPtrType());
-}
-
-inline bool Type::hasObjCPointerRepresentation() const {
- return isObjCObjectPointerType();
-}
-
-inline const Type *Type::getBaseElementTypeUnsafe() const {
- const Type *type = this;
- while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe())
- type = arrayType->getElementType().getTypePtr();
- return type;
-}
-
-inline const Type *Type::getPointeeOrArrayElementType() const {
- const Type *type = this;
- if (type->isAnyPointerType())
- return type->getPointeeType().getTypePtr();
- else if (type->isArrayType())
- return type->getBaseElementTypeUnsafe();
- return type;
-}
-/// Insertion operator for partial diagnostics. This allows sending adress
-/// spaces into a diagnostic with <<.
-inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
- LangAS AS) {
- PD.AddTaggedVal(llvm::to_underlying(AS),
- DiagnosticsEngine::ArgumentKind::ak_addrspace);
- return PD;
-}
-
-/// Insertion operator for partial diagnostics. This allows sending Qualifiers
-/// into a diagnostic with <<.
-inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
- Qualifiers Q) {
- PD.AddTaggedVal(Q.getAsOpaqueValue(),
- DiagnosticsEngine::ArgumentKind::ak_qual);
- return PD;
-}
-
-/// Insertion operator for partial diagnostics. This allows sending QualType's
-/// into a diagnostic with <<.
-inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
- QualType T) {
- PD.AddTaggedVal(reinterpret_cast<uint64_t>(T.getAsOpaquePtr()),
- DiagnosticsEngine::ak_qualtype);
- return PD;
-}
-
-// Helper class template that is used by Type::getAs to ensure that one does
-// not try to look through a qualified type to get to an array type.
-template <typename T>
-using TypeIsArrayType =
- std::integral_constant<bool, std::is_same<T, ArrayType>::value ||
- std::is_base_of<ArrayType, T>::value>;
-
-// Member-template getAs<specific type>'.
-template <typename T> const T *Type::getAs() const {
- static_assert(!TypeIsArrayType<T>::value,
- "ArrayType cannot be used with getAs!");
-
- // If this is directly a T type, return it.
- if (const auto *Ty = dyn_cast<T>(this))
- return Ty;
-
- // If the canonical form of this type isn't the right kind, reject it.
- if (!isa<T>(CanonicalType))
- return nullptr;
-
- // If this is a typedef for the type, strip the typedef off without
- // losing all typedef information.
- return cast<T>(getUnqualifiedDesugaredType());
-}
-
-template <typename T> const T *Type::getAsAdjusted() const {
- static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
-
- // If this is directly a T type, return it.
- if (const auto *Ty = dyn_cast<T>(this))
- return Ty;
-
- // If the canonical form of this type isn't the right kind, reject it.
- if (!isa<T>(CanonicalType))
- return nullptr;
-
- // Strip off type adjustments that do not modify the underlying nature of the
- // type.
- const Type *Ty = this;
- while (Ty) {
- if (const auto *A = dyn_cast<AttributedType>(Ty))
- Ty = A->getModifiedType().getTypePtr();
- else if (const auto *A = dyn_cast<BTFTagAttributedType>(Ty))
- Ty = A->getWrappedType().getTypePtr();
- else if (const auto *A = dyn_cast<HLSLAttributedResourceType>(Ty))
- Ty = A->getWrappedType().getTypePtr();
- else if (const auto *E = dyn_cast<ElaboratedType>(Ty))
- Ty = E->desugar().getTypePtr();
- else if (const auto *P = dyn_cast<ParenType>(Ty))
- Ty = P->desugar().getTypePtr();
- else if (const auto *A = dyn_cast<AdjustedType>(Ty))
- Ty = A->desugar().getTypePtr();
- else if (const auto *M = dyn_cast<MacroQualifiedType>(Ty))
- Ty = M->desugar().getTypePtr();
- else
- break;
- }
-
- // Just because the canonical type is correct does not mean we can use cast<>,
- // since we may not have stripped off all the sugar down to the base type.
- return dyn_cast<T>(Ty);
-}
-
-inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
- // If this is directly an array type, return it.
- if (const auto *arr = dyn_cast<ArrayType>(this))
- return arr;
-
- // If the canonical form of this type isn't the right kind, reject it.
- if (!isa<ArrayType>(CanonicalType))
- return nullptr;
-
- // If this is a typedef for the type, strip the typedef off without
- // losing all typedef information.
- return cast<ArrayType>(getUnqualifiedDesugaredType());
-}
-
-template <typename T> const T *Type::castAs() const {
- static_assert(!TypeIsArrayType<T>::value,
- "ArrayType cannot be used with castAs!");
-
- if (const auto *ty = dyn_cast<T>(this)) return ty;
- assert(isa<T>(CanonicalType));
- return cast<T>(getUnqualifiedDesugaredType());
-}
-
-inline const ArrayType *Type::castAsArrayTypeUnsafe() const {
- assert(isa<ArrayType>(CanonicalType));
- if (const auto *arr = dyn_cast<ArrayType>(this)) return arr;
- return cast<ArrayType>(getUnqualifiedDesugaredType());
-}
-
-DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr,
- QualType CanonicalPtr)
- : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) {
-#ifndef NDEBUG
- QualType Adjusted = getAdjustedType();
- (void)AttributedType::stripOuterNullability(Adjusted);
- assert(isa<PointerType>(Adjusted));
-#endif
-}
-
-QualType DecayedType::getPointeeType() const {
- QualType Decayed = getDecayedType();
- (void)AttributedType::stripOuterNullability(Decayed);
- return cast<PointerType>(Decayed)->getPointeeType();
-}
-
-// Get the decimal string representation of a fixed point type, represented
-// as a scaled integer.
-// TODO: At some point, we should change the arguments to instead just accept an
-// APFixedPoint instead of APSInt and scale.
-void FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val,
- unsigned Scale);
-
-inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) {
- const Type *TypePtr = QT.getTypePtr();
- while (true) {
- if (QualType Pointee = TypePtr->getPointeeType(); !Pointee.isNull())
- TypePtr = Pointee.getTypePtr();
- else if (TypePtr->isArrayType())
- TypePtr = TypePtr->getBaseElementTypeUnsafe();
- else
- break;
- }
- if (const auto *FPT = TypePtr->getAs<FunctionProtoType>())
- return FPT->getFunctionEffects();
- return {};
-}
-
} // namespace clang
#endif // LLVM_CLANG_AST_TYPE_H
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
new file mode 100644
index 0000000..db2ab04
--- /dev/null
+++ b/clang/include/clang/AST/TypeBase.h
@@ -0,0 +1,9281 @@
+//===- TypeBase.h - C Language Family Type Representation -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// C Language Family Type Representation
+///
+/// This file defines the clang::Type interface and subclasses, used to
+/// represent types for languages in the C family.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TYPE_BASE_H
+#define LLVM_CLANG_AST_TYPE_BASE_H
+
+#include "clang/AST/DependenceFlags.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Linkage.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/PointerAuthOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/Visibility.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DXILABI.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+#include "llvm/Support/TrailingObjects.h"
+#include "llvm/Support/type_traits.h"
+#include <bitset>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+namespace clang {
+
+class BTFTypeTagAttr;
+class ExtQuals;
+class QualType;
+class ConceptDecl;
+class ValueDecl;
+class TagDecl;
+class TemplateParameterList;
+class Type;
+class Attr;
+
+enum {
+ TypeAlignmentInBits = 4,
+ TypeAlignment = 1 << TypeAlignmentInBits
+};
+
+namespace serialization {
+ template <class T> class AbstractTypeReader;
+ template <class T> class AbstractTypeWriter;
+}
+
+} // namespace clang
+
+namespace llvm {
+
+ template <typename T>
+ struct PointerLikeTypeTraits;
+ template<>
+ struct PointerLikeTypeTraits< ::clang::Type*> {
+ static inline void *getAsVoidPointer(::clang::Type *P) { return P; }
+
+ static inline ::clang::Type *getFromVoidPointer(void *P) {
+ return static_cast< ::clang::Type*>(P);
+ }
+
+ static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
+ };
+
+ template<>
+ struct PointerLikeTypeTraits< ::clang::ExtQuals*> {
+ static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; }
+
+ static inline ::clang::ExtQuals *getFromVoidPointer(void *P) {
+ return static_cast< ::clang::ExtQuals*>(P);
+ }
+
+ static constexpr int NumLowBitsAvailable = clang::TypeAlignmentInBits;
+ };
+
+} // namespace llvm
+
+namespace clang {
+
+class ASTContext;
+template <typename> class CanQual;
+class CXXRecordDecl;
+class DeclContext;
+class EnumDecl;
+class Expr;
+class ExtQualsTypeCommonBase;
+class FunctionDecl;
+class FunctionEffectsRef;
+class FunctionEffectKindSet;
+class FunctionEffectSet;
+class IdentifierInfo;
+class NamedDecl;
+class ObjCInterfaceDecl;
+class ObjCProtocolDecl;
+class ObjCTypeParamDecl;
+struct PrintingPolicy;
+class RecordDecl;
+class Stmt;
+class TagDecl;
+class ClassTemplateDecl;
+class TemplateArgument;
+class TemplateArgumentListInfo;
+class TemplateArgumentLoc;
+class TemplateTypeParmDecl;
+class TypedefNameDecl;
+class UnresolvedUsingTypenameDecl;
+class UsingShadowDecl;
+
+using CanQualType = CanQual<Type>;
+
+// Provide forward declarations for all of the *Type classes.
+#define TYPE(Class, Base) class Class##Type;
+#include "clang/AST/TypeNodes.inc"
+
+/// Pointer-authentication qualifiers.
+class PointerAuthQualifier {
+ enum : uint32_t {
+ EnabledShift = 0,
+ EnabledBits = 1,
+ EnabledMask = 1 << EnabledShift,
+ AddressDiscriminatedShift = EnabledShift + EnabledBits,
+ AddressDiscriminatedBits = 1,
+ AddressDiscriminatedMask = 1 << AddressDiscriminatedShift,
+ AuthenticationModeShift =
+ AddressDiscriminatedShift + AddressDiscriminatedBits,
+ AuthenticationModeBits = 2,
+ AuthenticationModeMask = ((1 << AuthenticationModeBits) - 1)
+ << AuthenticationModeShift,
+ IsaPointerShift = AuthenticationModeShift + AuthenticationModeBits,
+ IsaPointerBits = 1,
+ IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift,
+ AuthenticatesNullValuesShift = IsaPointerShift + IsaPointerBits,
+ AuthenticatesNullValuesBits = 1,
+ AuthenticatesNullValuesMask = ((1 << AuthenticatesNullValuesBits) - 1)
+ << AuthenticatesNullValuesShift,
+ KeyShift = AuthenticatesNullValuesShift + AuthenticatesNullValuesBits,
+ KeyBits = 10,
+ KeyMask = ((1 << KeyBits) - 1) << KeyShift,
+ DiscriminatorShift = KeyShift + KeyBits,
+ DiscriminatorBits = 16,
+ DiscriminatorMask = ((1u << DiscriminatorBits) - 1) << DiscriminatorShift,
+ };
+
+ // bits: |0 |1 |2..3 |4 |
+ // |Enabled|Address|AuthenticationMode|ISA pointer|
+ // bits: |5 |6..15| 16...31 |
+ // |AuthenticatesNull|Key |Discriminator|
+ uint32_t Data = 0;
+
+ // The following static assertions check that each of the 32 bits is present
+ // exactly in one of the constants.
+ static_assert((EnabledBits + AddressDiscriminatedBits +
+ AuthenticationModeBits + IsaPointerBits +
+ AuthenticatesNullValuesBits + KeyBits + DiscriminatorBits) ==
+ 32,
+ "PointerAuthQualifier should be exactly 32 bits");
+ static_assert((EnabledMask + AddressDiscriminatedMask +
+ AuthenticationModeMask + IsaPointerMask +
+ AuthenticatesNullValuesMask + KeyMask + DiscriminatorMask) ==
+ 0xFFFFFFFF,
+ "All masks should cover the entire bits");
+ static_assert((EnabledMask ^ AddressDiscriminatedMask ^
+ AuthenticationModeMask ^ IsaPointerMask ^
+ AuthenticatesNullValuesMask ^ KeyMask ^ DiscriminatorMask) ==
+ 0xFFFFFFFF,
+ "All masks should cover the entire bits");
+
+ PointerAuthQualifier(unsigned Key, bool IsAddressDiscriminated,
+ unsigned ExtraDiscriminator,
+ PointerAuthenticationMode AuthenticationMode,
+ bool IsIsaPointer, bool AuthenticatesNullValues)
+ : Data(EnabledMask |
+ (IsAddressDiscriminated
+ ? llvm::to_underlying(AddressDiscriminatedMask)
+ : 0) |
+ (Key << KeyShift) |
+ (llvm::to_underlying(AuthenticationMode)
+ << AuthenticationModeShift) |
+ (ExtraDiscriminator << DiscriminatorShift) |
+ (IsIsaPointer << IsaPointerShift) |
+ (AuthenticatesNullValues << AuthenticatesNullValuesShift)) {
+ assert(Key <= KeyNoneInternal);
+ assert(ExtraDiscriminator <= MaxDiscriminator);
+ assert((Data == 0) ==
+ (getAuthenticationMode() == PointerAuthenticationMode::None));
+ }
+
+public:
+ enum {
+ KeyNoneInternal = (1u << KeyBits) - 1,
+
+ /// The maximum supported pointer-authentication key.
+ MaxKey = KeyNoneInternal - 1,
+
+ /// The maximum supported pointer-authentication discriminator.
+ MaxDiscriminator = (1u << DiscriminatorBits) - 1
+ };
+
+public:
+ PointerAuthQualifier() = default;
+
+ static PointerAuthQualifier
+ Create(unsigned Key, bool IsAddressDiscriminated, unsigned ExtraDiscriminator,
+ PointerAuthenticationMode AuthenticationMode, bool IsIsaPointer,
+ bool AuthenticatesNullValues) {
+ if (Key == PointerAuthKeyNone)
+ Key = KeyNoneInternal;
+ assert(Key <= KeyNoneInternal && "out-of-range key value");
+ return PointerAuthQualifier(Key, IsAddressDiscriminated, ExtraDiscriminator,
+ AuthenticationMode, IsIsaPointer,
+ AuthenticatesNullValues);
+ }
+
+ bool isPresent() const {
+ assert((Data == 0) ==
+ (getAuthenticationMode() == PointerAuthenticationMode::None));
+ return Data != 0;
+ }
+
+ explicit operator bool() const { return isPresent(); }
+
+ unsigned getKey() const {
+ assert(isPresent());
+ return (Data & KeyMask) >> KeyShift;
+ }
+
+ bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; }
+
+ bool isAddressDiscriminated() const {
+ assert(isPresent());
+ return (Data & AddressDiscriminatedMask) >> AddressDiscriminatedShift;
+ }
+
+ unsigned getExtraDiscriminator() const {
+ assert(isPresent());
+ return (Data >> DiscriminatorShift);
+ }
+
+ PointerAuthenticationMode getAuthenticationMode() const {
+ return PointerAuthenticationMode((Data & AuthenticationModeMask) >>
+ AuthenticationModeShift);
+ }
+
+ bool isIsaPointer() const {
+ assert(isPresent());
+ return (Data & IsaPointerMask) >> IsaPointerShift;
+ }
+
+ bool authenticatesNullValues() const {
+ assert(isPresent());
+ return (Data & AuthenticatesNullValuesMask) >> AuthenticatesNullValuesShift;
+ }
+
+ PointerAuthQualifier withoutKeyNone() const {
+ return hasKeyNone() ? PointerAuthQualifier() : *this;
+ }
+
+ friend bool operator==(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
+ return Lhs.Data == Rhs.Data;
+ }
+ friend bool operator!=(PointerAuthQualifier Lhs, PointerAuthQualifier Rhs) {
+ return Lhs.Data != Rhs.Data;
+ }
+
+ bool isEquivalent(PointerAuthQualifier Other) const {
+ return withoutKeyNone() == Other.withoutKeyNone();
+ }
+
+ uint32_t getAsOpaqueValue() const { return Data; }
+
+ // Deserialize pointer-auth qualifiers from an opaque representation.
+ static PointerAuthQualifier fromOpaqueValue(uint32_t Opaque) {
+ PointerAuthQualifier Result;
+ Result.Data = Opaque;
+ assert((Result.Data == 0) ==
+ (Result.getAuthenticationMode() == PointerAuthenticationMode::None));
+ return Result;
+ }
+
+ std::string getAsString() const;
+ std::string getAsString(const PrintingPolicy &Policy) const;
+
+ bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
+ void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Data); }
+};
+
+/// The collection of all-type qualifiers we support.
+/// Clang supports five independent qualifiers:
+/// * C99: const, volatile, and restrict
+/// * MS: __unaligned
+/// * Embedded C (TR18037): address spaces
+/// * Objective C: the GC attributes (none, weak, or strong)
+class Qualifiers {
+public:
+ Qualifiers() = default;
+ enum TQ : uint64_t {
+ // NOTE: These flags must be kept in sync with DeclSpec::TQ.
+ Const = 0x1,
+ Restrict = 0x2,
+ Volatile = 0x4,
+ CVRMask = Const | Volatile | Restrict
+ };
+
+ enum GC {
+ GCNone = 0,
+ Weak,
+ Strong
+ };
+
+ enum ObjCLifetime {
+ /// There is no lifetime qualification on this type.
+ OCL_None,
+
+ /// This object can be modified without requiring retains or
+ /// releases.
+ OCL_ExplicitNone,
+
+ /// Assigning into this object requires the old value to be
+ /// released and the new value to be retained. The timing of the
+ /// release of the old value is inexact: it may be moved to
+ /// immediately after the last known point where the value is
+ /// live.
+ OCL_Strong,
+
+ /// Reading or writing from this object requires a barrier call.
+ OCL_Weak,
+
+ /// Assigning into this object requires a lifetime extension.
+ OCL_Autoreleasing
+ };
+
+ enum : uint64_t {
+ /// The maximum supported address space number.
+ /// 23 bits should be enough for anyone.
+ MaxAddressSpace = 0x7fffffu,
+
+ /// The width of the "fast" qualifier mask.
+ FastWidth = 3,
+
+ /// The fast qualifier mask.
+ FastMask = (1 << FastWidth) - 1
+ };
+
+ /// Returns the common set of qualifiers while removing them from
+ /// the given sets.
+ static Qualifiers removeCommonQualifiers(Qualifiers &L, Qualifiers &R) {
+ Qualifiers Q;
+ PointerAuthQualifier LPtrAuth = L.getPointerAuth();
+ if (LPtrAuth.isPresent() &&
+ LPtrAuth.getKey() != PointerAuthQualifier::KeyNoneInternal &&
+ LPtrAuth == R.getPointerAuth()) {
+ Q.setPointerAuth(LPtrAuth);
+ PointerAuthQualifier Empty;
+ L.setPointerAuth(Empty);
+ R.setPointerAuth(Empty);
+ }
+
+ // If both are only CVR-qualified, bit operations are sufficient.
+ if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) {
+ Q.Mask = L.Mask & R.Mask;
+ L.Mask &= ~Q.Mask;
+ R.Mask &= ~Q.Mask;
+ return Q;
+ }
+
+ unsigned CommonCRV = L.getCVRQualifiers() & R.getCVRQualifiers();
+ Q.addCVRQualifiers(CommonCRV);
+ L.removeCVRQualifiers(CommonCRV);
+ R.removeCVRQualifiers(CommonCRV);
+
+ if (L.getObjCGCAttr() == R.getObjCGCAttr()) {
+ Q.setObjCGCAttr(L.getObjCGCAttr());
+ L.removeObjCGCAttr();
+ R.removeObjCGCAttr();
+ }
+
+ if (L.getObjCLifetime() == R.getObjCLifetime()) {
+ Q.setObjCLifetime(L.getObjCLifetime());
+ L.removeObjCLifetime();
+ R.removeObjCLifetime();
+ }
+
+ if (L.getAddressSpace() == R.getAddressSpace()) {
+ Q.setAddressSpace(L.getAddressSpace());
+ L.removeAddressSpace();
+ R.removeAddressSpace();
+ }
+ return Q;
+ }
+
+ static Qualifiers fromFastMask(unsigned Mask) {
+ Qualifiers Qs;
+ Qs.addFastQualifiers(Mask);
+ return Qs;
+ }
+
+ static Qualifiers fromCVRMask(unsigned CVR) {
+ Qualifiers Qs;
+ Qs.addCVRQualifiers(CVR);
+ return Qs;
+ }
+
+ static Qualifiers fromCVRUMask(unsigned CVRU) {
+ Qualifiers Qs;
+ Qs.addCVRUQualifiers(CVRU);
+ return Qs;
+ }
+
+ // Deserialize qualifiers from an opaque representation.
+ static Qualifiers fromOpaqueValue(uint64_t opaque) {
+ Qualifiers Qs;
+ Qs.Mask = opaque;
+ return Qs;
+ }
+
+ // Serialize these qualifiers into an opaque representation.
+ uint64_t getAsOpaqueValue() const { return Mask; }
+
+ bool hasConst() const { return Mask & Const; }
+ bool hasOnlyConst() const { return Mask == Const; }
+ void removeConst() { Mask &= ~Const; }
+ void addConst() { Mask |= Const; }
+ Qualifiers withConst() const {
+ Qualifiers Qs = *this;
+ Qs.addConst();
+ return Qs;
+ }
+
+ bool hasVolatile() const { return Mask & Volatile; }
+ bool hasOnlyVolatile() const { return Mask == Volatile; }
+ void removeVolatile() { Mask &= ~Volatile; }
+ void addVolatile() { Mask |= Volatile; }
+ Qualifiers withVolatile() const {
+ Qualifiers Qs = *this;
+ Qs.addVolatile();
+ return Qs;
+ }
+
+ bool hasRestrict() const { return Mask & Restrict; }
+ bool hasOnlyRestrict() const { return Mask == Restrict; }
+ void removeRestrict() { Mask &= ~Restrict; }
+ void addRestrict() { Mask |= Restrict; }
+ Qualifiers withRestrict() const {
+ Qualifiers Qs = *this;
+ Qs.addRestrict();
+ return Qs;
+ }
+
+ bool hasCVRQualifiers() const { return getCVRQualifiers(); }
+ unsigned getCVRQualifiers() const { return Mask & CVRMask; }
+ unsigned getCVRUQualifiers() const { return Mask & (CVRMask | UMask); }
+
+ void setCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask = (Mask & ~CVRMask) | mask;
+ }
+ void removeCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask &= ~static_cast<uint64_t>(mask);
+ }
+ void removeCVRQualifiers() {
+ removeCVRQualifiers(CVRMask);
+ }
+ void addCVRQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits");
+ Mask |= mask;
+ }
+ void addCVRUQualifiers(unsigned mask) {
+ assert(!(mask & ~CVRMask & ~UMask) && "bitmask contains non-CVRU bits");
+ Mask |= mask;
+ }
+
+ bool hasUnaligned() const { return Mask & UMask; }
+ void setUnaligned(bool flag) {
+ Mask = (Mask & ~UMask) | (flag ? UMask : 0);
+ }
+ void removeUnaligned() { Mask &= ~UMask; }
+ void addUnaligned() { Mask |= UMask; }
+
+ bool hasObjCGCAttr() const { return Mask & GCAttrMask; }
+ GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); }
+ void setObjCGCAttr(GC type) {
+ Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift);
+ }
+ void removeObjCGCAttr() { setObjCGCAttr(GCNone); }
+ void addObjCGCAttr(GC type) {
+ assert(type);
+ setObjCGCAttr(type);
+ }
+ Qualifiers withoutObjCGCAttr() const {
+ Qualifiers qs = *this;
+ qs.removeObjCGCAttr();
+ return qs;
+ }
+ Qualifiers withoutObjCLifetime() const {
+ Qualifiers qs = *this;
+ qs.removeObjCLifetime();
+ return qs;
+ }
+ Qualifiers withoutAddressSpace() const {
+ Qualifiers qs = *this;
+ qs.removeAddressSpace();
+ return qs;
+ }
+
+ bool hasObjCLifetime() const { return Mask & LifetimeMask; }
+ ObjCLifetime getObjCLifetime() const {
+ return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift);
+ }
+ void setObjCLifetime(ObjCLifetime type) {
+ Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift);
+ }
+ void removeObjCLifetime() { setObjCLifetime(OCL_None); }
+ void addObjCLifetime(ObjCLifetime type) {
+ assert(type);
+ assert(!hasObjCLifetime());
+ Mask |= (type << LifetimeShift);
+ }
+
+ /// True if the lifetime is neither None or ExplicitNone.
+ bool hasNonTrivialObjCLifetime() const {
+ ObjCLifetime lifetime = getObjCLifetime();
+ return (lifetime > OCL_ExplicitNone);
+ }
+
+ /// True if the lifetime is either strong or weak.
+ bool hasStrongOrWeakObjCLifetime() const {
+ ObjCLifetime lifetime = getObjCLifetime();
+ return (lifetime == OCL_Strong || lifetime == OCL_Weak);
+ }
+
+ bool hasAddressSpace() const { return Mask & AddressSpaceMask; }
+ LangAS getAddressSpace() const {
+ return static_cast<LangAS>((Mask & AddressSpaceMask) >> AddressSpaceShift);
+ }
+ bool hasTargetSpecificAddressSpace() const {
+ return isTargetAddressSpace(getAddressSpace());
+ }
+ /// Get the address space attribute value to be printed by diagnostics.
+ unsigned getAddressSpaceAttributePrintValue() const {
+ auto Addr = getAddressSpace();
+ // This function is not supposed to be used with language specific
+ // address spaces. If that happens, the diagnostic message should consider
+ // printing the QualType instead of the address space value.
+ assert(Addr == LangAS::Default || hasTargetSpecificAddressSpace());
+ if (Addr != LangAS::Default)
+ return toTargetAddressSpace(Addr);
+ // TODO: The diagnostic messages where Addr may be 0 should be fixed
+ // since it cannot differentiate the situation where 0 denotes the default
+ // address space or user specified __attribute__((address_space(0))).
+ return 0;
+ }
+ void setAddressSpace(LangAS space) {
+ assert((unsigned)space <= MaxAddressSpace);
+ Mask = (Mask & ~AddressSpaceMask)
+ | (((uint32_t) space) << AddressSpaceShift);
+ }
+ void removeAddressSpace() { setAddressSpace(LangAS::Default); }
+ void addAddressSpace(LangAS space) {
+ assert(space != LangAS::Default);
+ setAddressSpace(space);
+ }
+
+ bool hasPointerAuth() const { return Mask & PtrAuthMask; }
+ PointerAuthQualifier getPointerAuth() const {
+ return PointerAuthQualifier::fromOpaqueValue(Mask >> PtrAuthShift);
+ }
+ void setPointerAuth(PointerAuthQualifier Q) {
+ Mask = (Mask & ~PtrAuthMask) |
+ (uint64_t(Q.getAsOpaqueValue()) << PtrAuthShift);
+ }
+ void removePointerAuth() { Mask &= ~PtrAuthMask; }
+ void addPointerAuth(PointerAuthQualifier Q) {
+ assert(Q.isPresent());
+ setPointerAuth(Q);
+ }
+
+ // Fast qualifiers are those that can be allocated directly
+ // on a QualType object.
+ bool hasFastQualifiers() const { return getFastQualifiers(); }
+ unsigned getFastQualifiers() const { return Mask & FastMask; }
+ void setFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask = (Mask & ~FastMask) | mask;
+ }
+ void removeFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask &= ~static_cast<uint64_t>(mask);
+ }
+ void removeFastQualifiers() {
+ removeFastQualifiers(FastMask);
+ }
+ void addFastQualifiers(unsigned mask) {
+ assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits");
+ Mask |= mask;
+ }
+
+ /// Return true if the set contains any qualifiers which require an ExtQuals
+ /// node to be allocated.
+ bool hasNonFastQualifiers() const { return Mask & ~FastMask; }
+ Qualifiers getNonFastQualifiers() const {
+ Qualifiers Quals = *this;
+ Quals.setFastQualifiers(0);
+ return Quals;
+ }
+
+ /// Return true if the set contains any qualifiers.
+ bool hasQualifiers() const { return Mask; }
+ bool empty() const { return !Mask; }
+
+ /// Add the qualifiers from the given set to this set.
+ void addQualifiers(Qualifiers Q) {
+ // If the other set doesn't have any non-boolean qualifiers, just
+ // bit-or it in.
+ if (!(Q.Mask & ~CVRMask))
+ Mask |= Q.Mask;
+ else {
+ Mask |= (Q.Mask & CVRMask);
+ if (Q.hasAddressSpace())
+ addAddressSpace(Q.getAddressSpace());
+ if (Q.hasObjCGCAttr())
+ addObjCGCAttr(Q.getObjCGCAttr());
+ if (Q.hasObjCLifetime())
+ addObjCLifetime(Q.getObjCLifetime());
+ if (Q.hasPointerAuth())
+ addPointerAuth(Q.getPointerAuth());
+ }
+ }
+
+ /// Remove the qualifiers from the given set from this set.
+ void removeQualifiers(Qualifiers Q) {
+ // If the other set doesn't have any non-boolean qualifiers, just
+ // bit-and the inverse in.
+ if (!(Q.Mask & ~CVRMask))
+ Mask &= ~Q.Mask;
+ else {
+ Mask &= ~(Q.Mask & CVRMask);
+ if (getObjCGCAttr() == Q.getObjCGCAttr())
+ removeObjCGCAttr();
+ if (getObjCLifetime() == Q.getObjCLifetime())
+ removeObjCLifetime();
+ if (getAddressSpace() == Q.getAddressSpace())
+ removeAddressSpace();
+ if (getPointerAuth() == Q.getPointerAuth())
+ removePointerAuth();
+ }
+ }
+
+ /// Add the qualifiers from the given set to this set, given that
+ /// they don't conflict.
+ void addConsistentQualifiers(Qualifiers qs) {
+ assert(getAddressSpace() == qs.getAddressSpace() ||
+ !hasAddressSpace() || !qs.hasAddressSpace());
+ assert(getObjCGCAttr() == qs.getObjCGCAttr() ||
+ !hasObjCGCAttr() || !qs.hasObjCGCAttr());
+ assert(getObjCLifetime() == qs.getObjCLifetime() ||
+ !hasObjCLifetime() || !qs.hasObjCLifetime());
+ assert(!hasPointerAuth() || !qs.hasPointerAuth() ||
+ getPointerAuth() == qs.getPointerAuth());
+ Mask |= qs.Mask;
+ }
+
+ /// Returns true if address space A is equal to or a superset of B.
+ /// OpenCL v2.0 defines conversion rules (OpenCLC v2.0 s6.5.5) and notion of
+ /// overlapping address spaces.
+ /// CL1.1 or CL1.2:
+ /// every address space is a superset of itself.
+ /// CL2.0 adds:
+ /// __generic is a superset of any address space except for __constant.
+ static bool isAddressSpaceSupersetOf(LangAS A, LangAS B,
+ const ASTContext &Ctx) {
+ // Address spaces must match exactly.
+ return A == B || isTargetAddressSpaceSupersetOf(A, B, Ctx);
+ }
+
+ static bool isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
+ const ASTContext &Ctx);
+
+ /// Returns true if the address space in these qualifiers is equal to or
+ /// a superset of the address space in the argument qualifiers.
+ bool isAddressSpaceSupersetOf(Qualifiers other, const ASTContext &Ctx) const {
+ return isAddressSpaceSupersetOf(getAddressSpace(), other.getAddressSpace(),
+ Ctx);
+ }
+
+ /// Determines if these qualifiers compatibly include another set.
+ /// Generally this answers the question of whether an object with the other
+ /// qualifiers can be safely used as an object with these qualifiers.
+ bool compatiblyIncludes(Qualifiers other, const ASTContext &Ctx) const {
+ return isAddressSpaceSupersetOf(other, Ctx) &&
+ // ObjC GC qualifiers can match, be added, or be removed, but can't
+ // be changed.
+ (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() ||
+ !other.hasObjCGCAttr()) &&
+ // Pointer-auth qualifiers must match exactly.
+ getPointerAuth() == other.getPointerAuth() &&
+ // ObjC lifetime qualifiers must match exactly.
+ getObjCLifetime() == other.getObjCLifetime() &&
+ // CVR qualifiers may subset.
+ (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)) &&
+ // U qualifier may superset.
+ (!other.hasUnaligned() || hasUnaligned());
+ }
+
+ /// Determines if these qualifiers compatibly include another set of
+ /// qualifiers from the narrow perspective of Objective-C ARC lifetime.
+ ///
+ /// One set of Objective-C lifetime qualifiers compatibly includes the other
+ /// if the lifetime qualifiers match, or if both are non-__weak and the
+ /// including set also contains the 'const' qualifier, or both are non-__weak
+ /// and one is None (which can only happen in non-ARC modes).
+ bool compatiblyIncludesObjCLifetime(Qualifiers other) const {
+ if (getObjCLifetime() == other.getObjCLifetime())
+ return true;
+
+ if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak)
+ return false;
+
+ if (getObjCLifetime() == OCL_None || other.getObjCLifetime() == OCL_None)
+ return true;
+
+ return hasConst();
+ }
+
+ /// Determine whether this set of qualifiers is a strict superset of
+ /// another set of qualifiers, not considering qualifier compatibility.
+ bool isStrictSupersetOf(Qualifiers Other) const;
+
+ bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
+ bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
+
+ explicit operator bool() const { return hasQualifiers(); }
+
+ Qualifiers &operator+=(Qualifiers R) {
+ addQualifiers(R);
+ return *this;
+ }
+
+ // Union two qualifier sets. If an enumerated qualifier appears
+ // in both sets, use the one from the right.
+ friend Qualifiers operator+(Qualifiers L, Qualifiers R) {
+ L += R;
+ return L;
+ }
+
+ Qualifiers &operator-=(Qualifiers R) {
+ removeQualifiers(R);
+ return *this;
+ }
+
+ /// Compute the difference between two qualifier sets.
+ friend Qualifiers operator-(Qualifiers L, Qualifiers R) {
+ L -= R;
+ return L;
+ }
+
+ std::string getAsString() const;
+ std::string getAsString(const PrintingPolicy &Policy) const;
+
+ static std::string getAddrSpaceAsString(LangAS AS);
+
+ bool isEmptyWhenPrinted(const PrintingPolicy &Policy) const;
+ void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ bool appendSpaceIfNonEmpty = false) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); }
+
+private:
+ // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63|
+ // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth |
+ uint64_t Mask = 0;
+ static_assert(sizeof(PointerAuthQualifier) == sizeof(uint32_t),
+ "PointerAuthQualifier must be 32 bits");
+
+ static constexpr uint64_t PtrAuthShift = 32;
+ static constexpr uint64_t PtrAuthMask = UINT64_C(0xffffffff) << PtrAuthShift;
+
+ static constexpr uint64_t UMask = 0x8;
+ static constexpr uint64_t UShift = 3;
+ static constexpr uint64_t GCAttrMask = 0x30;
+ static constexpr uint64_t GCAttrShift = 4;
+ static constexpr uint64_t LifetimeMask = 0x1C0;
+ static constexpr uint64_t LifetimeShift = 6;
+ static constexpr uint64_t AddressSpaceMask =
+ ~(CVRMask | UMask | GCAttrMask | LifetimeMask | PtrAuthMask);
+ static constexpr uint64_t AddressSpaceShift = 9;
+};
+
+class QualifiersAndAtomic {
+ Qualifiers Quals;
+ bool HasAtomic;
+
+public:
+ QualifiersAndAtomic() : HasAtomic(false) {}
+ QualifiersAndAtomic(Qualifiers Quals, bool HasAtomic)
+ : Quals(Quals), HasAtomic(HasAtomic) {}
+
+ operator Qualifiers() const { return Quals; }
+
+ bool hasVolatile() const { return Quals.hasVolatile(); }
+ bool hasConst() const { return Quals.hasConst(); }
+ bool hasRestrict() const { return Quals.hasRestrict(); }
+ bool hasAtomic() const { return HasAtomic; }
+
+ void addVolatile() { Quals.addVolatile(); }
+ void addConst() { Quals.addConst(); }
+ void addRestrict() { Quals.addRestrict(); }
+ void addAtomic() { HasAtomic = true; }
+
+ void removeVolatile() { Quals.removeVolatile(); }
+ void removeConst() { Quals.removeConst(); }
+ void removeRestrict() { Quals.removeRestrict(); }
+ void removeAtomic() { HasAtomic = false; }
+
+ QualifiersAndAtomic withVolatile() {
+ return {Quals.withVolatile(), HasAtomic};
+ }
+ QualifiersAndAtomic withConst() { return {Quals.withConst(), HasAtomic}; }
+ QualifiersAndAtomic withRestrict() {
+ return {Quals.withRestrict(), HasAtomic};
+ }
+ QualifiersAndAtomic withAtomic() { return {Quals, true}; }
+
+ QualifiersAndAtomic &operator+=(Qualifiers RHS) {
+ Quals += RHS;
+ return *this;
+ }
+};
+
+/// A std::pair-like structure for storing a qualified type split
+/// into its local qualifiers and its locally-unqualified type.
+struct SplitQualType {
+ /// The locally-unqualified type.
+ const Type *Ty = nullptr;
+
+ /// The local qualifiers.
+ Qualifiers Quals;
+
+ SplitQualType() = default;
+ SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {}
+
+ SplitQualType getSingleStepDesugaredType() const; // end of this file
+
+ // Make std::tie work.
+ std::pair<const Type *,Qualifiers> asPair() const {
+ return std::pair<const Type *, Qualifiers>(Ty, Quals);
+ }
+
+ friend bool operator==(SplitQualType a, SplitQualType b) {
+ return a.Ty == b.Ty && a.Quals == b.Quals;
+ }
+ friend bool operator!=(SplitQualType a, SplitQualType b) {
+ return a.Ty != b.Ty || a.Quals != b.Quals;
+ }
+};
+
+/// The kind of type we are substituting Objective-C type arguments into.
+///
+/// The kind of substitution affects the replacement of type parameters when
+/// no concrete type information is provided, e.g., when dealing with an
+/// unspecialized type.
+enum class ObjCSubstitutionContext {
+ /// An ordinary type.
+ Ordinary,
+
+ /// The result type of a method or function.
+ Result,
+
+ /// The parameter type of a method or function.
+ Parameter,
+
+ /// The type of a property.
+ Property,
+
+ /// The superclass of a type.
+ Superclass,
+};
+
+/// The kind of 'typeof' expression we're after.
+enum class TypeOfKind : uint8_t {
+ Qualified,
+ Unqualified,
+};
+
+/// A (possibly-)qualified type.
+///
+/// For efficiency, we don't store CV-qualified types as nodes on their
+/// own: instead each reference to a type stores the qualifiers. This
+/// greatly reduces the number of nodes we need to allocate for types (for
+/// example we only need one for 'int', 'const int', 'volatile int',
+/// 'const volatile int', etc).
+///
+/// As an added efficiency bonus, instead of making this a pair, we
+/// just store the two bits we care about in the low bits of the
+/// pointer. To handle the packing/unpacking, we make QualType be a
+/// simple wrapper class that acts like a smart pointer. A third bit
+/// indicates whether there are extended qualifiers present, in which
+/// case the pointer points to a special structure.
+class QualType {
+ friend class QualifierCollector;
+
+ // Thankfully, these are efficiently composable.
+ llvm::PointerIntPair<llvm::PointerUnion<const Type *, const ExtQuals *>,
+ Qualifiers::FastWidth> Value;
+
+ const ExtQuals *getExtQualsUnsafe() const {
+ return cast<const ExtQuals *>(Value.getPointer());
+ }
+
+ const Type *getTypePtrUnsafe() const {
+ return cast<const Type *>(Value.getPointer());
+ }
+
+ const ExtQualsTypeCommonBase *getCommonPtr() const {
+ assert(!isNull() && "Cannot retrieve a NULL type pointer");
+ auto CommonPtrVal = reinterpret_cast<uintptr_t>(Value.getOpaqueValue());
+ CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1);
+ return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal);
+ }
+
+public:
+ QualType() = default;
+ QualType(const Type *Ptr, unsigned Quals) : Value(Ptr, Quals) {}
+ QualType(const ExtQuals *Ptr, unsigned Quals) : Value(Ptr, Quals) {}
+
+ unsigned getLocalFastQualifiers() const { return Value.getInt(); }
+ void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); }
+
+ bool UseExcessPrecision(const ASTContext &Ctx);
+
+ /// Retrieves a pointer to the underlying (unqualified) type.
+ ///
+ /// This function requires that the type not be NULL. If the type might be
+ /// NULL, use the (slightly less efficient) \c getTypePtrOrNull().
+ const Type *getTypePtr() const;
+
+ const Type *getTypePtrOrNull() const;
+
+ /// Retrieves a pointer to the name of the base type.
+ const IdentifierInfo *getBaseTypeIdentifier() const;
+
+ /// Divides a QualType into its unqualified type and a set of local
+ /// qualifiers.
+ SplitQualType split() const;
+
+ void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
+
+ static QualType getFromOpaquePtr(const void *Ptr) {
+ QualType T;
+ T.Value.setFromOpaqueValue(const_cast<void*>(Ptr));
+ return T;
+ }
+
+ const Type &operator*() const {
+ return *getTypePtr();
+ }
+
+ const Type *operator->() const {
+ return getTypePtr();
+ }
+
+ bool isCanonical() const;
+ bool isCanonicalAsParam() const;
+
+ /// Return true if this QualType doesn't point to a type yet.
+ bool isNull() const {
+ return Value.getPointer().isNull();
+ }
+
+ // Determines if a type can form `T&`.
+ bool isReferenceable() const;
+
+ /// Determine whether this particular QualType instance has the
+ /// "const" qualifier set, without looking through typedefs that may have
+ /// added "const" at a different level.
+ bool isLocalConstQualified() const {
+ return (getLocalFastQualifiers() & Qualifiers::Const);
+ }
+
+ /// Determine whether this type is const-qualified.
+ bool isConstQualified() const;
+
+ enum class NonConstantStorageReason {
+ MutableField,
+ NonConstNonReferenceType,
+ NonTrivialCtor,
+ NonTrivialDtor,
+ };
+ /// Determine whether instances of this type can be placed in immutable
+ /// storage.
+ /// If ExcludeCtor is true, the duration when the object's constructor runs
+ /// will not be considered. The caller will need to verify that the object is
+ /// not written to during its construction. ExcludeDtor works similarly.
+ std::optional<NonConstantStorageReason>
+ isNonConstantStorage(const ASTContext &Ctx, bool ExcludeCtor,
+ bool ExcludeDtor);
+
+ bool isConstantStorage(const ASTContext &Ctx, bool ExcludeCtor,
+ bool ExcludeDtor) {
+ return !isNonConstantStorage(Ctx, ExcludeCtor, ExcludeDtor);
+ }
+
+ /// Determine whether this particular QualType instance has the
+ /// "restrict" qualifier set, without looking through typedefs that may have
+ /// added "restrict" at a different level.
+ bool isLocalRestrictQualified() const {
+ return (getLocalFastQualifiers() & Qualifiers::Restrict);
+ }
+
+ /// Determine whether this type is restrict-qualified.
+ bool isRestrictQualified() const;
+
+ /// Determine whether this particular QualType instance has the
+ /// "volatile" qualifier set, without looking through typedefs that may have
+ /// added "volatile" at a different level.
+ bool isLocalVolatileQualified() const {
+ return (getLocalFastQualifiers() & Qualifiers::Volatile);
+ }
+
+ /// Determine whether this type is volatile-qualified.
+ bool isVolatileQualified() const;
+
+ /// Determine whether this particular QualType instance has any
+ /// qualifiers, without looking through any typedefs that might add
+ /// qualifiers at a different level.
+ bool hasLocalQualifiers() const {
+ return getLocalFastQualifiers() || hasLocalNonFastQualifiers();
+ }
+
+ /// Determine whether this type has any qualifiers.
+ bool hasQualifiers() const;
+
+ /// Determine whether this particular QualType instance has any
+ /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType
+ /// instance.
+ bool hasLocalNonFastQualifiers() const {
+ return isa<const ExtQuals *>(Value.getPointer());
+ }
+
+ /// Retrieve the set of qualifiers local to this particular QualType
+ /// instance, not including any qualifiers acquired through typedefs or
+ /// other sugar.
+ Qualifiers getLocalQualifiers() const;
+
+ /// Retrieve the set of qualifiers applied to this type.
+ Qualifiers getQualifiers() const;
+
+ /// Retrieve the set of CVR (const-volatile-restrict) qualifiers
+ /// local to this particular QualType instance, not including any qualifiers
+ /// acquired through typedefs or other sugar.
+ unsigned getLocalCVRQualifiers() const {
+ return getLocalFastQualifiers();
+ }
+
+ /// Retrieve the set of CVR (const-volatile-restrict) qualifiers
+ /// applied to this type.
+ unsigned getCVRQualifiers() const;
+
+ bool isConstant(const ASTContext& Ctx) const {
+ return QualType::isConstant(*this, Ctx);
+ }
+
+ /// Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10).
+ bool isPODType(const ASTContext &Context) const;
+
+ /// Return true if this is a POD type according to the rules of the C++98
+ /// standard, regardless of the current compilation's language.
+ bool isCXX98PODType(const ASTContext &Context) const;
+
+ /// Return true if this is a POD type according to the more relaxed rules
+ /// of the C++11 standard, regardless of the current compilation's language.
+ /// (C++0x [basic.types]p9). Note that, unlike
+ /// CXXRecordDecl::isCXX11StandardLayout, this takes DRs into account.
+ bool isCXX11PODType(const ASTContext &Context) const;
+
+ /// Return true if this is a trivial type per (C++0x [basic.types]p9)
+ bool isTrivialType(const ASTContext &Context) const;
+
+ /// Return true if this is a trivially copyable type (C++0x [basic.types]p9)
+ bool isTriviallyCopyableType(const ASTContext &Context) const;
+
+ /// Return true if the type is safe to bitwise copy using memcpy/memmove.
+ ///
+ /// This is an extension in clang: bitwise cloneable types act as trivially
+ /// copyable types, meaning their underlying bytes can be safely copied by
+ /// memcpy or memmove. After the copy, the destination object has the same
+ /// object representation.
+ ///
+ /// However, there are cases where it is not safe to copy:
+ /// - When sanitizers, such as AddressSanitizer, add padding with poison,
+ /// which can cause issues if those poisoned padding bits are accessed.
+ /// - Types with Objective-C lifetimes, where specific runtime
+ /// semantics may not be preserved during a bitwise copy.
+ bool isBitwiseCloneableType(const ASTContext &Context) const;
+
+ /// Return true if this is a trivially copyable type
+ bool isTriviallyCopyConstructibleType(const ASTContext &Context) const;
+
+ /// Returns true if it is a class and it might be dynamic.
+ bool mayBeDynamicClass() const;
+
+ /// Returns true if it is not a class or if the class might not be dynamic.
+ bool mayBeNotDynamicClass() const;
+
+ /// Returns true if it is a WebAssembly Reference Type.
+ bool isWebAssemblyReferenceType() const;
+
+ /// Returns true if it is a WebAssembly Externref Type.
+ bool isWebAssemblyExternrefType() const;
+
+ /// Returns true if it is a WebAssembly Funcref Type.
+ bool isWebAssemblyFuncrefType() const;
+
+ // Don't promise in the API that anything besides 'const' can be
+ // easily added.
+
+ /// Add the `const` type qualifier to this QualType.
+ void addConst() {
+ addFastQualifiers(Qualifiers::Const);
+ }
+ QualType withConst() const {
+ return withFastQualifiers(Qualifiers::Const);
+ }
+
+ /// Add the `volatile` type qualifier to this QualType.
+ void addVolatile() {
+ addFastQualifiers(Qualifiers::Volatile);
+ }
+ QualType withVolatile() const {
+ return withFastQualifiers(Qualifiers::Volatile);
+ }
+
+ /// Add the `restrict` qualifier to this QualType.
+ void addRestrict() {
+ addFastQualifiers(Qualifiers::Restrict);
+ }
+ QualType withRestrict() const {
+ return withFastQualifiers(Qualifiers::Restrict);
+ }
+
+ QualType withCVRQualifiers(unsigned CVR) const {
+ return withFastQualifiers(CVR);
+ }
+
+ void addFastQualifiers(unsigned TQs) {
+ assert(!(TQs & ~Qualifiers::FastMask)
+ && "non-fast qualifier bits set in mask!");
+ Value.setInt(Value.getInt() | TQs);
+ }
+
+ void removeLocalConst();
+ void removeLocalVolatile();
+ void removeLocalRestrict();
+
+ void removeLocalFastQualifiers() { Value.setInt(0); }
+ void removeLocalFastQualifiers(unsigned Mask) {
+ assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers");
+ Value.setInt(Value.getInt() & ~Mask);
+ }
+
+ // Creates a type with the given qualifiers in addition to any
+ // qualifiers already on this type.
+ QualType withFastQualifiers(unsigned TQs) const {
+ QualType T = *this;
+ T.addFastQualifiers(TQs);
+ return T;
+ }
+
+ // Creates a type with exactly the given fast qualifiers, removing
+ // any existing fast qualifiers.
+ QualType withExactLocalFastQualifiers(unsigned TQs) const {
+ return withoutLocalFastQualifiers().withFastQualifiers(TQs);
+ }
+
+ // Removes fast qualifiers, but leaves any extended qualifiers in place.
+ QualType withoutLocalFastQualifiers() const {
+ QualType T = *this;
+ T.removeLocalFastQualifiers();
+ return T;
+ }
+
+ QualType getCanonicalType() const;
+
+ /// Return this type with all of the instance-specific qualifiers
+ /// removed, but without removing any qualifiers that may have been applied
+ /// through typedefs.
+ QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); }
+
+ /// Retrieve the unqualified variant of the given type,
+ /// removing as little sugar as possible.
+ ///
+ /// This routine looks through various kinds of sugar to find the
+ /// least-desugared type that is unqualified. For example, given:
+ ///
+ /// \code
+ /// typedef int Integer;
+ /// typedef const Integer CInteger;
+ /// typedef CInteger DifferenceType;
+ /// \endcode
+ ///
+ /// Executing \c getUnqualifiedType() on the type \c DifferenceType will
+ /// desugar until we hit the type \c Integer, which has no qualifiers on it.
+ ///
+ /// The resulting type might still be qualified if it's sugar for an array
+ /// type. To strip qualifiers even from within a sugared array type, use
+ /// ASTContext::getUnqualifiedArrayType.
+ ///
+ /// Note: In C, the _Atomic qualifier is special (see C23 6.2.5p32 for
+ /// details), and it is not stripped by this function. Use
+ /// getAtomicUnqualifiedType() to strip qualifiers including _Atomic.
+ inline QualType getUnqualifiedType() const;
+
+ /// Retrieve the unqualified variant of the given type, removing as little
+ /// sugar as possible.
+ ///
+ /// Like getUnqualifiedType(), but also returns the set of
+ /// qualifiers that were built up.
+ ///
+ /// The resulting type might still be qualified if it's sugar for an array
+ /// type. To strip qualifiers even from within a sugared array type, use
+ /// ASTContext::getUnqualifiedArrayType.
+ inline SplitQualType getSplitUnqualifiedType() const;
+
+ /// Determine whether this type is more qualified than the other
+ /// given type, requiring exact equality for non-CVR qualifiers.
+ bool isMoreQualifiedThan(QualType Other, const ASTContext &Ctx) const;
+
+ /// Determine whether this type is at least as qualified as the other
+ /// given type, requiring exact equality for non-CVR qualifiers.
+ bool isAtLeastAsQualifiedAs(QualType Other, const ASTContext &Ctx) const;
+
+ QualType getNonReferenceType() const;
+
+ /// Determine the type of a (typically non-lvalue) expression with the
+ /// specified result type.
+ ///
+ /// This routine should be used for expressions for which the return type is
+ /// explicitly specified (e.g., in a cast or call) and isn't necessarily
+ /// an lvalue. It removes a top-level reference (since there are no
+ /// expressions of reference type) and deletes top-level cvr-qualifiers
+ /// from non-class types (in C++) or all types (in C).
+ QualType getNonLValueExprType(const ASTContext &Context) const;
+
+ /// Remove an outer pack expansion type (if any) from this type. Used as part
+ /// of converting the type of a declaration to the type of an expression that
+ /// references that expression. It's meaningless for an expression to have a
+ /// pack expansion type.
+ QualType getNonPackExpansionType() const;
+
+ /// Return the specified type with any "sugar" removed from
+ /// the type. This takes off typedefs, typeof's etc. If the outer level of
+ /// the type is already concrete, it returns it unmodified. This is similar
+ /// to getting the canonical type, but it doesn't remove *all* typedefs. For
+ /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
+ /// concrete.
+ ///
+ /// Qualifiers are left in place.
+ QualType getDesugaredType(const ASTContext &Context) const {
+ return getDesugaredType(*this, Context);
+ }
+
+ SplitQualType getSplitDesugaredType() const {
+ return getSplitDesugaredType(*this);
+ }
+
+ /// Return the specified type with one level of "sugar" removed from
+ /// the type.
+ ///
+ /// This routine takes off the first typedef, typeof, etc. If the outer level
+ /// of the type is already concrete, it returns it unmodified.
+ QualType getSingleStepDesugaredType(const ASTContext &Context) const {
+ return getSingleStepDesugaredTypeImpl(*this, Context);
+ }
+
+ /// Returns the specified type after dropping any
+ /// outer-level parentheses.
+ QualType IgnoreParens() const {
+ if (isa<ParenType>(*this))
+ return QualType::IgnoreParens(*this);
+ return *this;
+ }
+
+ /// Indicate whether the specified types and qualifiers are identical.
+ friend bool operator==(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value == RHS.Value;
+ }
+ friend bool operator!=(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value != RHS.Value;
+ }
+ friend bool operator<(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value < RHS.Value;
+ }
+
+ static std::string getAsString(SplitQualType split,
+ const PrintingPolicy &Policy) {
+ return getAsString(split.Ty, split.Quals, Policy);
+ }
+ static std::string getAsString(const Type *ty, Qualifiers qs,
+ const PrintingPolicy &Policy);
+
+ std::string getAsString() const;
+ std::string getAsString(const PrintingPolicy &Policy) const;
+
+ void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ const Twine &PlaceHolder = Twine(),
+ unsigned Indentation = 0) const;
+
+ static void print(SplitQualType split, raw_ostream &OS,
+ const PrintingPolicy &policy, const Twine &PlaceHolder,
+ unsigned Indentation = 0) {
+ return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation);
+ }
+
+ static void print(const Type *ty, Qualifiers qs,
+ raw_ostream &OS, const PrintingPolicy &policy,
+ const Twine &PlaceHolder,
+ unsigned Indentation = 0);
+
+ void getAsStringInternal(std::string &Str,
+ const PrintingPolicy &Policy) const;
+
+ static void getAsStringInternal(SplitQualType split, std::string &out,
+ const PrintingPolicy &policy) {
+ return getAsStringInternal(split.Ty, split.Quals, out, policy);
+ }
+
+ static void getAsStringInternal(const Type *ty, Qualifiers qs,
+ std::string &out,
+ const PrintingPolicy &policy);
+
+ class StreamedQualTypeHelper {
+ const QualType &T;
+ const PrintingPolicy &Policy;
+ const Twine &PlaceHolder;
+ unsigned Indentation;
+
+ public:
+ StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy,
+ const Twine &PlaceHolder, unsigned Indentation)
+ : T(T), Policy(Policy), PlaceHolder(PlaceHolder),
+ Indentation(Indentation) {}
+
+ friend raw_ostream &operator<<(raw_ostream &OS,
+ const StreamedQualTypeHelper &SQT) {
+ SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation);
+ return OS;
+ }
+ };
+
+ StreamedQualTypeHelper stream(const PrintingPolicy &Policy,
+ const Twine &PlaceHolder = Twine(),
+ unsigned Indentation = 0) const {
+ return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation);
+ }
+
+ void dump(const char *s) const;
+ void dump() const;
+ void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(getAsOpaquePtr());
+ }
+
+ /// Check if this type has any address space qualifier.
+ inline bool hasAddressSpace() const;
+
+ /// Return the address space of this type.
+ inline LangAS getAddressSpace() const;
+
+ /// Returns true if address space qualifiers overlap with T address space
+ /// qualifiers.
+ /// OpenCL C defines conversion rules for pointers to different address spaces
+ /// and notion of overlapping address spaces.
+ /// CL1.1 or CL1.2:
+ /// address spaces overlap iff they are they same.
+ /// OpenCL C v2.0 s6.5.5 adds:
+ /// __generic overlaps with any address space except for __constant.
+ bool isAddressSpaceOverlapping(QualType T, const ASTContext &Ctx) const {
+ Qualifiers Q = getQualifiers();
+ Qualifiers TQ = T.getQualifiers();
+ // Address spaces overlap if at least one of them is a superset of another
+ return Q.isAddressSpaceSupersetOf(TQ, Ctx) ||
+ TQ.isAddressSpaceSupersetOf(Q, Ctx);
+ }
+
+ /// Returns gc attribute of this type.
+ inline Qualifiers::GC getObjCGCAttr() const;
+
+ /// true when Type is objc's weak.
+ bool isObjCGCWeak() const {
+ return getObjCGCAttr() == Qualifiers::Weak;
+ }
+
+ /// true when Type is objc's strong.
+ bool isObjCGCStrong() const {
+ return getObjCGCAttr() == Qualifiers::Strong;
+ }
+
+ /// Returns lifetime attribute of this type.
+ Qualifiers::ObjCLifetime getObjCLifetime() const {
+ return getQualifiers().getObjCLifetime();
+ }
+
+ bool hasNonTrivialObjCLifetime() const {
+ return getQualifiers().hasNonTrivialObjCLifetime();
+ }
+
+ bool hasStrongOrWeakObjCLifetime() const {
+ return getQualifiers().hasStrongOrWeakObjCLifetime();
+ }
+
+ // true when Type is objc's weak and weak is enabled but ARC isn't.
+ bool isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const;
+
+ PointerAuthQualifier getPointerAuth() const {
+ return getQualifiers().getPointerAuth();
+ }
+
+ bool hasAddressDiscriminatedPointerAuth() const {
+ if (PointerAuthQualifier PtrAuth = getPointerAuth())
+ return PtrAuth.isAddressDiscriminated();
+ return false;
+ }
+
+ enum PrimitiveDefaultInitializeKind {
+ /// The type does not fall into any of the following categories. Note that
+ /// this case is zero-valued so that values of this enum can be used as a
+ /// boolean condition for non-triviality.
+ PDIK_Trivial,
+
+ /// The type is an Objective-C retainable pointer type that is qualified
+ /// with the ARC __strong qualifier.
+ PDIK_ARCStrong,
+
+ /// The type is an Objective-C retainable pointer type that is qualified
+ /// with the ARC __weak qualifier.
+ PDIK_ARCWeak,
+
+ /// The type is a struct containing a field whose type is not PCK_Trivial.
+ PDIK_Struct
+ };
+
+ /// Functions to query basic properties of non-trivial C struct types.
+
+ /// Check if this is a non-trivial type that would cause a C struct
+ /// transitively containing this type to be non-trivial to default initialize
+ /// and return the kind.
+ PrimitiveDefaultInitializeKind
+ isNonTrivialToPrimitiveDefaultInitialize() const;
+
+ enum PrimitiveCopyKind {
+ /// The type does not fall into any of the following categories. Note that
+ /// this case is zero-valued so that values of this enum can be used as a
+ /// boolean condition for non-triviality.
+ PCK_Trivial,
+
+ /// The type would be trivial except that it is volatile-qualified. Types
+ /// that fall into one of the other non-trivial cases may additionally be
+ /// volatile-qualified.
+ PCK_VolatileTrivial,
+
+ /// The type is an Objective-C retainable pointer type that is qualified
+ /// with the ARC __strong qualifier.
+ PCK_ARCStrong,
+
+ /// The type is an Objective-C retainable pointer type that is qualified
+ /// with the ARC __weak qualifier.
+ PCK_ARCWeak,
+
+ /// The type is an address-discriminated signed pointer type.
+ PCK_PtrAuth,
+
+ /// The type is a struct containing a field whose type is neither
+ /// PCK_Trivial nor PCK_VolatileTrivial.
+ /// Note that a C++ struct type does not necessarily match this; C++ copying
+ /// semantics are too complex to express here, in part because they depend
+ /// on the exact constructor or assignment operator that is chosen by
+ /// overload resolution to do the copy.
+ PCK_Struct
+ };
+
+ /// Check if this is a non-trivial type that would cause a C struct
+ /// transitively containing this type to be non-trivial to copy and return the
+ /// kind.
+ PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const;
+
+ /// Check if this is a non-trivial type that would cause a C struct
+ /// transitively containing this type to be non-trivial to destructively
+ /// move and return the kind. Destructive move in this context is a C++-style
+ /// move in which the source object is placed in a valid but unspecified state
+ /// after it is moved, as opposed to a truly destructive move in which the
+ /// source object is placed in an uninitialized state.
+ PrimitiveCopyKind isNonTrivialToPrimitiveDestructiveMove() const;
+
+ enum DestructionKind {
+ DK_none,
+ DK_cxx_destructor,
+ DK_objc_strong_lifetime,
+ DK_objc_weak_lifetime,
+ DK_nontrivial_c_struct
+ };
+
+ /// Returns a nonzero value if objects of this type require
+ /// non-trivial work to clean up after. Non-zero because it's
+ /// conceivable that qualifiers (objc_gc(weak)?) could make
+ /// something require destruction.
+ DestructionKind isDestructedType() const {
+ return isDestructedTypeImpl(*this);
+ }
+
+ /// Check if this is or contains a C union that is non-trivial to
+ /// default-initialize, which is a union that has a member that is non-trivial
+ /// to default-initialize. If this returns true,
+ /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct.
+ bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const;
+
+ /// Check if this is or contains a C union that is non-trivial to destruct,
+ /// which is a union that has a member that is non-trivial to destruct. If
+ /// this returns true, isDestructedType returns DK_nontrivial_c_struct.
+ bool hasNonTrivialToPrimitiveDestructCUnion() const;
+
+ /// Check if this is or contains a C union that is non-trivial to copy, which
+ /// is a union that has a member that is non-trivial to copy. If this returns
+ /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct.
+ bool hasNonTrivialToPrimitiveCopyCUnion() const;
+
+ /// Determine whether expressions of the given type are forbidden
+ /// from being lvalues in C.
+ ///
+ /// The expression types that are forbidden to be lvalues are:
+ /// - 'void', but not qualified void
+ /// - function types
+ ///
+ /// The exact rule here is C99 6.3.2.1:
+ /// An lvalue is an expression with an object type or an incomplete
+ /// type other than void.
+ bool isCForbiddenLValueType() const;
+
+ /// Substitute type arguments for the Objective-C type parameters used in the
+ /// subject type.
+ ///
+ /// \param ctx ASTContext in which the type exists.
+ ///
+ /// \param typeArgs The type arguments that will be substituted for the
+ /// Objective-C type parameters in the subject type, which are generally
+ /// computed via \c Type::getObjCSubstitutions. If empty, the type
+ /// parameters will be replaced with their bounds or id/Class, as appropriate
+ /// for the context.
+ ///
+ /// \param context The context in which the subject type was written.
+ ///
+ /// \returns the resulting type.
+ QualType substObjCTypeArgs(ASTContext &ctx,
+ ArrayRef<QualType> typeArgs,
+ ObjCSubstitutionContext context) const;
+
+ /// Substitute type arguments from an object type for the Objective-C type
+ /// parameters used in the subject type.
+ ///
+ /// This operation combines the computation of type arguments for
+ /// substitution (\c Type::getObjCSubstitutions) with the actual process of
+ /// substitution (\c QualType::substObjCTypeArgs) for the convenience of
+ /// callers that need to perform a single substitution in isolation.
+ ///
+ /// \param objectType The type of the object whose member type we're
+ /// substituting into. For example, this might be the receiver of a message
+ /// or the base of a property access.
+ ///
+ /// \param dc The declaration context from which the subject type was
+ /// retrieved, which indicates (for example) which type parameters should
+ /// be substituted.
+ ///
+ /// \param context The context in which the subject type was written.
+ ///
+ /// \returns the subject type after replacing all of the Objective-C type
+ /// parameters with their corresponding arguments.
+ QualType substObjCMemberType(QualType objectType,
+ const DeclContext *dc,
+ ObjCSubstitutionContext context) const;
+
+ /// Strip Objective-C "__kindof" types from the given type.
+ QualType stripObjCKindOfType(const ASTContext &ctx) const;
+
+ /// Remove all qualifiers including _Atomic.
+ ///
+ /// Like getUnqualifiedType(), the type may still be qualified if it is a
+ /// sugared array type. To strip qualifiers even from within a sugared array
+ /// type, use in conjunction with ASTContext::getUnqualifiedArrayType.
+ QualType getAtomicUnqualifiedType() const;
+
+private:
+ // These methods are implemented in a separate translation unit;
+ // "static"-ize them to avoid creating temporary QualTypes in the
+ // caller.
+ static bool isConstant(QualType T, const ASTContext& Ctx);
+ static QualType getDesugaredType(QualType T, const ASTContext &Context);
+ static SplitQualType getSplitDesugaredType(QualType T);
+ static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
+ static QualType getSingleStepDesugaredTypeImpl(QualType type,
+ const ASTContext &C);
+ static QualType IgnoreParens(QualType T);
+ static DestructionKind isDestructedTypeImpl(QualType type);
+
+ /// Check if \param RD is or contains a non-trivial C union.
+ static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD);
+ static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD);
+ static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD);
+};
+
+raw_ostream &operator<<(raw_ostream &OS, QualType QT);
+
+} // namespace clang
+
+namespace llvm {
+
+/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
+/// to a specific Type class.
+template<> struct simplify_type< ::clang::QualType> {
+ using SimpleType = const ::clang::Type *;
+
+ static SimpleType getSimplifiedValue(::clang::QualType Val) {
+ return Val.getTypePtr();
+ }
+};
+
+// Teach SmallPtrSet that QualType is "basically a pointer".
+template<>
+struct PointerLikeTypeTraits<clang::QualType> {
+ static inline void *getAsVoidPointer(clang::QualType P) {
+ return P.getAsOpaquePtr();
+ }
+
+ static inline clang::QualType getFromVoidPointer(void *P) {
+ return clang::QualType::getFromOpaquePtr(P);
+ }
+
+ // Various qualifiers go in low bits.
+ static constexpr int NumLowBitsAvailable = 0;
+};
+
+} // namespace llvm
+
+namespace clang {
+
+/// Base class that is common to both the \c ExtQuals and \c Type
+/// classes, which allows \c QualType to access the common fields between the
+/// two.
+class ExtQualsTypeCommonBase {
+ friend class ExtQuals;
+ friend class QualType;
+ friend class Type;
+ friend class ASTReader;
+
+ /// The "base" type of an extended qualifiers type (\c ExtQuals) or
+ /// a self-referential pointer (for \c Type).
+ ///
+ /// This pointer allows an efficient mapping from a QualType to its
+ /// underlying type pointer.
+ const Type *const BaseType;
+
+ /// The canonical type of this type. A QualType.
+ QualType CanonicalType;
+
+ ExtQualsTypeCommonBase(const Type *baseType, QualType canon)
+ : BaseType(baseType), CanonicalType(canon) {}
+};
+
+/// We can encode up to four bits in the low bits of a
+/// type pointer, but there are many more type qualifiers that we want
+/// to be able to apply to an arbitrary type. Therefore we have this
+/// struct, intended to be heap-allocated and used by QualType to
+/// store qualifiers.
+///
+/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers
+/// in three low bits on the QualType pointer; a fourth bit records whether
+/// the pointer is an ExtQuals node. The extended qualifiers (address spaces,
+/// Objective-C GC attributes) are much more rare.
+class alignas(TypeAlignment) ExtQuals : public ExtQualsTypeCommonBase,
+ public llvm::FoldingSetNode {
+ // NOTE: changing the fast qualifiers should be straightforward as
+ // long as you don't make 'const' non-fast.
+ // 1. Qualifiers:
+ // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ).
+ // Fast qualifiers must occupy the low-order bits.
+ // b) Update Qualifiers::FastWidth and FastMask.
+ // 2. QualType:
+ // a) Update is{Volatile,Restrict}Qualified(), defined inline.
+ // b) Update remove{Volatile,Restrict}, defined near the end of
+ // this header.
+ // 3. ASTContext:
+ // a) Update get{Volatile,Restrict}Type.
+
+ /// The immutable set of qualifiers applied by this node. Always contains
+ /// extended qualifiers.
+ Qualifiers Quals;
+
+ ExtQuals *this_() { return this; }
+
+public:
+ ExtQuals(const Type *baseType, QualType canon, Qualifiers quals)
+ : ExtQualsTypeCommonBase(baseType,
+ canon.isNull() ? QualType(this_(), 0) : canon),
+ Quals(quals) {
+ assert(Quals.hasNonFastQualifiers()
+ && "ExtQuals created with no fast qualifiers");
+ assert(!Quals.hasFastQualifiers()
+ && "ExtQuals created with fast qualifiers");
+ }
+
+ Qualifiers getQualifiers() const { return Quals; }
+
+ bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); }
+ Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); }
+
+ bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); }
+ Qualifiers::ObjCLifetime getObjCLifetime() const {
+ return Quals.getObjCLifetime();
+ }
+
+ bool hasAddressSpace() const { return Quals.hasAddressSpace(); }
+ LangAS getAddressSpace() const { return Quals.getAddressSpace(); }
+
+ const Type *getBaseType() const { return BaseType; }
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getBaseType(), Quals);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const Type *BaseType,
+ Qualifiers Quals) {
+ assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!");
+ ID.AddPointer(BaseType);
+ Quals.Profile(ID);
+ }
+};
+
+/// The kind of C++11 ref-qualifier associated with a function type.
+/// This determines whether a member function's "this" object can be an
+/// lvalue, rvalue, or neither.
+enum RefQualifierKind {
+ /// No ref-qualifier was provided.
+ RQ_None = 0,
+
+ /// An lvalue ref-qualifier was provided (\c &).
+ RQ_LValue,
+
+ /// An rvalue ref-qualifier was provided (\c &&).
+ RQ_RValue
+};
+
+/// Which keyword(s) were used to create an AutoType.
+enum class AutoTypeKeyword {
+ /// auto
+ Auto,
+
+ /// decltype(auto)
+ DecltypeAuto,
+
+ /// __auto_type (GNU extension)
+ GNUAutoType
+};
+
+enum class ArraySizeModifier;
+enum class ElaboratedTypeKeyword;
+enum class VectorKind;
+
+/// The base class of the type hierarchy.
+///
+/// A central concept with types is that each type always has a canonical
+/// type. A canonical type is the type with any typedef names stripped out
+/// of it or the types it references. For example, consider:
+///
+/// typedef int foo;
+/// typedef foo* bar;
+/// 'int *' 'foo *' 'bar'
+///
+/// There will be a Type object created for 'int'. Since int is canonical, its
+/// CanonicalType pointer points to itself. There is also a Type for 'foo' (a
+/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next
+/// there is a PointerType that represents 'int*', which, like 'int', is
+/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical
+/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type
+/// is also 'int*'.
+///
+/// Non-canonical types are useful for emitting diagnostics, without losing
+/// information about typedefs being used. Canonical types are useful for type
+/// comparisons (they allow by-pointer equality tests) and useful for reasoning
+/// about whether something has a particular form (e.g. is a function type),
+/// because they implicitly, recursively, strip all typedefs out of a type.
+///
+/// Types, once created, are immutable.
+///
+class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
+public:
+ enum TypeClass {
+#define TYPE(Class, Base) Class,
+#define LAST_TYPE(Class) TypeLast = Class
+#define ABSTRACT_TYPE(Class, Base)
+#include "clang/AST/TypeNodes.inc"
+ };
+
+private:
+ /// Bitfields required by the Type class.
+ class TypeBitfields {
+ friend class Type;
+ template <class T> friend class TypePropertyCache;
+
+ /// TypeClass bitfield - Enum that specifies what subclass this belongs to.
+ LLVM_PREFERRED_TYPE(TypeClass)
+ unsigned TC : 8;
+
+ /// Store information on the type dependency.
+ LLVM_PREFERRED_TYPE(TypeDependence)
+ unsigned Dependence : llvm::BitWidth<TypeDependence>;
+
+ /// True if the cache (i.e. the bitfields here starting with
+ /// 'Cache') is valid.
+ LLVM_PREFERRED_TYPE(bool)
+ mutable unsigned CacheValid : 1;
+
+ /// Linkage of this type.
+ LLVM_PREFERRED_TYPE(Linkage)
+ mutable unsigned CachedLinkage : 3;
+
+ /// Whether this type involves and local or unnamed types.
+ LLVM_PREFERRED_TYPE(bool)
+ mutable unsigned CachedLocalOrUnnamed : 1;
+
+ /// Whether this type comes from an AST file.
+ LLVM_PREFERRED_TYPE(bool)
+ mutable unsigned FromAST : 1;
+
+ bool isCacheValid() const {
+ return CacheValid;
+ }
+
+ Linkage getLinkage() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return static_cast<Linkage>(CachedLinkage);
+ }
+
+ bool hasLocalOrUnnamedType() const {
+ assert(isCacheValid() && "getting linkage from invalid cache");
+ return CachedLocalOrUnnamed;
+ }
+ };
+ enum { NumTypeBits = 8 + llvm::BitWidth<TypeDependence> + 6 };
+
+protected:
+ // These classes allow subclasses to somewhat cleanly pack bitfields
+ // into Type.
+
+ class ArrayTypeBitfields {
+ friend class ArrayType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// CVR qualifiers from declarations like
+ /// 'int X[static restrict 4]'. For function parameters only.
+ LLVM_PREFERRED_TYPE(Qualifiers)
+ unsigned IndexTypeQuals : 3;
+
+ /// Storage class qualifiers from declarations like
+ /// 'int X[static restrict 4]'. For function parameters only.
+ LLVM_PREFERRED_TYPE(ArraySizeModifier)
+ unsigned SizeModifier : 3;
+ };
+ enum { NumArrayTypeBits = NumTypeBits + 6 };
+
+ class ConstantArrayTypeBitfields {
+ friend class ConstantArrayType;
+
+ LLVM_PREFERRED_TYPE(ArrayTypeBitfields)
+ unsigned : NumArrayTypeBits;
+
+ /// Whether we have a stored size expression.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasExternalSize : 1;
+
+ LLVM_PREFERRED_TYPE(unsigned)
+ unsigned SizeWidth : 5;
+ };
+
+ class BuiltinTypeBitfields {
+ friend class BuiltinType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The kind (BuiltinType::Kind) of builtin type this is.
+ static constexpr unsigned NumOfBuiltinTypeBits = 9;
+ unsigned Kind : NumOfBuiltinTypeBits;
+ };
+
+public:
+ static constexpr int FunctionTypeNumParamsWidth = 16;
+ static constexpr int FunctionTypeNumParamsLimit = (1 << 16) - 1;
+
+protected:
+ /// FunctionTypeBitfields store various bits belonging to FunctionProtoType.
+ /// Only common bits are stored here. Additional uncommon bits are stored
+ /// in a trailing object after FunctionProtoType.
+ class FunctionTypeBitfields {
+ friend class FunctionProtoType;
+ friend class FunctionType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The ref-qualifier associated with a \c FunctionProtoType.
+ ///
+ /// This is a value of type \c RefQualifierKind.
+ LLVM_PREFERRED_TYPE(RefQualifierKind)
+ unsigned RefQualifier : 2;
+
+ /// Used only by FunctionProtoType, put here to pack with the
+ /// other bitfields.
+ /// The qualifiers are part of FunctionProtoType because...
+ ///
+ /// C++ 8.3.5p4: The return type, the parameter type list and the
+ /// cv-qualifier-seq, [...], are part of the function type.
+ LLVM_PREFERRED_TYPE(Qualifiers)
+ unsigned FastTypeQuals : Qualifiers::FastWidth;
+ /// Whether this function has extended Qualifiers.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasExtQuals : 1;
+
+ /// The type of exception specification this function has.
+ LLVM_PREFERRED_TYPE(ExceptionSpecificationType)
+ unsigned ExceptionSpecType : 4;
+
+ /// Whether this function has extended parameter information.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasExtParameterInfos : 1;
+
+ /// Whether this function has extra bitfields for the prototype.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasExtraBitfields : 1;
+
+ /// Whether the function is variadic.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Variadic : 1;
+
+ /// Whether this function has a trailing return type.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasTrailingReturn : 1;
+
+ /// Whether this function has is a cfi unchecked callee.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned CFIUncheckedCallee : 1;
+
+ /// Extra information which affects how the function is called, like
+ /// regparm and the calling convention.
+ LLVM_PREFERRED_TYPE(CallingConv)
+ unsigned ExtInfo : 14;
+
+ /// The number of parameters this function has, not counting '...'.
+ /// According to [implimits] 8 bits should be enough here but this is
+ /// somewhat easy to exceed with metaprogramming and so we would like to
+ /// keep NumParams as wide as reasonably possible.
+ unsigned NumParams : FunctionTypeNumParamsWidth;
+ };
+
+ class ObjCObjectTypeBitfields {
+ friend class ObjCObjectType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The number of type arguments stored directly on this object type.
+ unsigned NumTypeArgs : 7;
+
+ /// The number of protocols stored directly on this object type.
+ unsigned NumProtocols : 6;
+
+ /// Whether this is a "kindof" type.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsKindOf : 1;
+ };
+
+ class ReferenceTypeBitfields {
+ friend class ReferenceType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// True if the type was originally spelled with an lvalue sigil.
+ /// This is never true of rvalue references but can also be false
+ /// on lvalue references because of C++0x [dcl.typedef]p9,
+ /// as follows:
+ ///
+ /// typedef int &ref; // lvalue, spelled lvalue
+ /// typedef int &&rvref; // rvalue
+ /// ref &a; // lvalue, inner ref, spelled lvalue
+ /// ref &&a; // lvalue, inner ref
+ /// rvref &a; // lvalue, inner ref, spelled lvalue
+ /// rvref &&a; // rvalue, inner ref
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned SpelledAsLValue : 1;
+
+ /// True if the inner type is a reference type. This only happens
+ /// in non-canonical forms.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned InnerRef : 1;
+ };
+
+ class KeywordWrapperBitfields {
+ template <class> friend class KeywordWrapper;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// An ElaboratedTypeKeyword. 8 bits for efficient access.
+ LLVM_PREFERRED_TYPE(ElaboratedTypeKeyword)
+ unsigned Keyword : 8;
+ };
+
+ enum { NumTypeWithKeywordBits = NumTypeBits + 8 };
+
+ class TagTypeBitfields {
+ friend class TagType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// Whether the TagType has a trailing Qualifier.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasQualifier : 1;
+
+ /// Whether the TagType owns the Tag.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned OwnsTag : 1;
+
+ /// Whether the TagType was created from an injected name.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsInjected : 1;
+ };
+
+ class VectorTypeBitfields {
+ friend class VectorType;
+ friend class DependentVectorType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The kind of vector, either a generic vector type or some
+ /// target-specific vector type such as for AltiVec or Neon.
+ LLVM_PREFERRED_TYPE(VectorKind)
+ unsigned VecKind : 4;
+ /// The number of elements in the vector.
+ uint32_t NumElements;
+ };
+
+ class AttributedTypeBitfields {
+ friend class AttributedType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ LLVM_PREFERRED_TYPE(attr::Kind)
+ unsigned AttrKind : 32 - NumTypeBits;
+ };
+
+ class AutoTypeBitfields {
+ friend class AutoType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// Was this placeholder type spelled as 'auto', 'decltype(auto)',
+ /// or '__auto_type'? AutoTypeKeyword value.
+ LLVM_PREFERRED_TYPE(AutoTypeKeyword)
+ unsigned Keyword : 2;
+
+ /// The number of template arguments in the type-constraints, which is
+ /// expected to be able to hold at least 1024 according to [implimits].
+ /// However as this limit is somewhat easy to hit with template
+ /// metaprogramming we'd prefer to keep it as large as possible.
+ /// At the moment it has been left as a non-bitfield since this type
+ /// safely fits in 64 bits as an unsigned, so there is no reason to
+ /// introduce the performance impact of a bitfield.
+ unsigned NumArgs;
+ };
+
+ class TypeOfBitfields {
+ friend class TypeOfType;
+ friend class TypeOfExprType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+ LLVM_PREFERRED_TYPE(TypeOfKind)
+ unsigned Kind : 1;
+ };
+
+ class UnresolvedUsingBitfields {
+ friend class UnresolvedUsingType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// True if there is a non-null qualifier.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned hasQualifier : 1;
+ };
+
+ class UsingBitfields {
+ friend class UsingType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// True if there is a non-null qualifier.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned hasQualifier : 1;
+ };
+
+ class TypedefBitfields {
+ friend class TypedefType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// True if there is a non-null qualifier.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned hasQualifier : 1;
+
+ /// True if the underlying type is different from the declared one.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned hasTypeDifferentFromDecl : 1;
+ };
+
+ class TemplateTypeParmTypeBitfields {
+ friend class TemplateTypeParmType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The depth of the template parameter.
+ unsigned Depth : 15;
+
+ /// Whether this is a template parameter pack.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ParameterPack : 1;
+
+ /// The index of the template parameter.
+ unsigned Index : 16;
+ };
+
+ class SubstTemplateTypeParmTypeBitfields {
+ friend class SubstTemplateTypeParmType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasNonCanonicalUnderlyingType : 1;
+
+ // The index of the template parameter this substitution represents.
+ unsigned Index : 15;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Final : 1;
+
+ /// Represents the index within a pack if this represents a substitution
+ /// from a pack expansion. This index starts at the end of the pack and
+ /// increments towards the beginning.
+ /// Positive non-zero number represents the index + 1.
+ /// Zero means this is not substituted from an expansion.
+ unsigned PackIndex : 15;
+ };
+
+ class SubstPackTypeBitfields {
+ friend class SubstPackType;
+ friend class SubstTemplateTypeParmPackType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The number of template arguments in \c Arguments, which is
+ /// expected to be able to hold at least 1024 according to [implimits].
+ /// However as this limit is somewhat easy to hit with template
+ /// metaprogramming we'd prefer to keep it as large as possible.
+ unsigned NumArgs : 16;
+
+ // The index of the template parameter this substitution represents.
+ // Only used by SubstTemplateTypeParmPackType. We keep it in the same
+ // class to avoid dealing with complexities of bitfields that go over
+ // the size of `unsigned`.
+ unsigned SubstTemplTypeParmPackIndex : 16;
+ };
+
+ class TemplateSpecializationTypeBitfields {
+ friend class TemplateSpecializationType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// Whether this template specialization type is a substituted type alias.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned TypeAlias : 1;
+
+ /// The number of template arguments named in this class template
+ /// specialization, which is expected to be able to hold at least 1024
+ /// according to [implimits]. However, as this limit is somewhat easy to
+ /// hit with template metaprogramming we'd prefer to keep it as large
+ /// as possible. At the moment it has been left as a non-bitfield since
+ /// this type safely fits in 64 bits as an unsigned, so there is no reason
+ /// to introduce the performance impact of a bitfield.
+ unsigned NumArgs;
+ };
+
+ class DependentTemplateSpecializationTypeBitfields {
+ friend class DependentTemplateSpecializationType;
+
+ LLVM_PREFERRED_TYPE(KeywordWrapperBitfields)
+ unsigned : NumTypeWithKeywordBits;
+
+ /// The number of template arguments named in this class template
+ /// specialization, which is expected to be able to hold at least 1024
+ /// according to [implimits]. However, as this limit is somewhat easy to
+ /// hit with template metaprogramming we'd prefer to keep it as large
+ /// as possible. At the moment it has been left as a non-bitfield since
+ /// this type safely fits in 64 bits as an unsigned, so there is no reason
+ /// to introduce the performance impact of a bitfield.
+ unsigned NumArgs;
+ };
+
+ class PackExpansionTypeBitfields {
+ friend class PackExpansionType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ /// The number of expansions that this pack expansion will
+ /// generate when substituted (+1), which is expected to be able to
+ /// hold at least 1024 according to [implimits]. However, as this limit
+ /// is somewhat easy to hit with template metaprogramming we'd prefer to
+ /// keep it as large as possible. At the moment it has been left as a
+ /// non-bitfield since this type safely fits in 64 bits as an unsigned, so
+ /// there is no reason to introduce the performance impact of a bitfield.
+ ///
+ /// This field will only have a non-zero value when some of the parameter
+ /// packs that occur within the pattern have been substituted but others
+ /// have not.
+ unsigned NumExpansions;
+ };
+
+ enum class PredefinedSugarKind {
+ /// The "size_t" type.
+ SizeT,
+
+ /// The signed integer type corresponding to "size_t".
+ SignedSizeT,
+
+ /// The "ptrdiff_t" type.
+ PtrdiffT,
+
+ // Indicates how many items the enum has.
+ Last = PtrdiffT
+ };
+
+ class PresefinedSugarTypeBitfields {
+ friend class PredefinedSugarType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ LLVM_PREFERRED_TYPE(PredefinedSugarKind)
+ unsigned Kind : 8;
+ };
+
+ class CountAttributedTypeBitfields {
+ friend class CountAttributedType;
+
+ LLVM_PREFERRED_TYPE(TypeBitfields)
+ unsigned : NumTypeBits;
+
+ static constexpr unsigned NumCoupledDeclsBits = 4;
+ unsigned NumCoupledDecls : NumCoupledDeclsBits;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned CountInBytes : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned OrNull : 1;
+ };
+ static_assert(sizeof(CountAttributedTypeBitfields) <= sizeof(unsigned));
+
+ union {
+ TypeBitfields TypeBits;
+ ArrayTypeBitfields ArrayTypeBits;
+ ConstantArrayTypeBitfields ConstantArrayTypeBits;
+ AttributedTypeBitfields AttributedTypeBits;
+ AutoTypeBitfields AutoTypeBits;
+ TypeOfBitfields TypeOfBits;
+ TypedefBitfields TypedefBits;
+ UnresolvedUsingBitfields UnresolvedUsingBits;
+ UsingBitfields UsingBits;
+ BuiltinTypeBitfields BuiltinTypeBits;
+ FunctionTypeBitfields FunctionTypeBits;
+ ObjCObjectTypeBitfields ObjCObjectTypeBits;
+ ReferenceTypeBitfields ReferenceTypeBits;
+ KeywordWrapperBitfields KeywordWrapperBits;
+ TagTypeBitfields TagTypeBits;
+ VectorTypeBitfields VectorTypeBits;
+ TemplateTypeParmTypeBitfields TemplateTypeParmTypeBits;
+ SubstTemplateTypeParmTypeBitfields SubstTemplateTypeParmTypeBits;
+ SubstPackTypeBitfields SubstPackTypeBits;
+ TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits;
+ DependentTemplateSpecializationTypeBitfields
+ DependentTemplateSpecializationTypeBits;
+ PackExpansionTypeBitfields PackExpansionTypeBits;
+ CountAttributedTypeBitfields CountAttributedTypeBits;
+ PresefinedSugarTypeBitfields PredefinedSugarTypeBits;
+ };
+
+private:
+ template <class T> friend class TypePropertyCache;
+
+ /// Set whether this type comes from an AST file.
+ void setFromAST(bool V = true) const {
+ TypeBits.FromAST = V;
+ }
+
+protected:
+ friend class ASTContext;
+
+ Type(TypeClass tc, QualType canon, TypeDependence Dependence)
+ : ExtQualsTypeCommonBase(this,
+ canon.isNull() ? QualType(this_(), 0) : canon) {
+ static_assert(sizeof(*this) <=
+ alignof(decltype(*this)) + sizeof(ExtQualsTypeCommonBase),
+ "changing bitfields changed sizeof(Type)!");
+ static_assert(alignof(decltype(*this)) % TypeAlignment == 0,
+ "Insufficient alignment!");
+ TypeBits.TC = tc;
+ TypeBits.Dependence = static_cast<unsigned>(Dependence);
+ TypeBits.CacheValid = false;
+ TypeBits.CachedLocalOrUnnamed = false;
+ TypeBits.CachedLinkage = llvm::to_underlying(Linkage::Invalid);
+ TypeBits.FromAST = false;
+ }
+
+ // silence VC++ warning C4355: 'this' : used in base member initializer list
+ Type *this_() { return this; }
+
+ void setDependence(TypeDependence D) {
+ TypeBits.Dependence = static_cast<unsigned>(D);
+ }
+
+ void addDependence(TypeDependence D) { setDependence(getDependence() | D); }
+
+public:
+ friend class ASTReader;
+ friend class ASTWriter;
+ template <class T> friend class serialization::AbstractTypeReader;
+ template <class T> friend class serialization::AbstractTypeWriter;
+
+ Type(const Type &) = delete;
+ Type(Type &&) = delete;
+ Type &operator=(const Type &) = delete;
+ Type &operator=(Type &&) = delete;
+
+ TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); }
+
+ /// Whether this type comes from an AST file.
+ bool isFromAST() const { return TypeBits.FromAST; }
+
+ /// Whether this type is or contains an unexpanded parameter
+ /// pack, used to support C++0x variadic templates.
+ ///
+ /// A type that contains a parameter pack shall be expanded by the
+ /// ellipsis operator at some point. For example, the typedef in the
+ /// following example contains an unexpanded parameter pack 'T':
+ ///
+ /// \code
+ /// template<typename ...T>
+ /// struct X {
+ /// typedef T* pointer_types; // ill-formed; T is a parameter pack.
+ /// };
+ /// \endcode
+ ///
+ /// Note that this routine does not specify which
+ bool containsUnexpandedParameterPack() const {
+ return getDependence() & TypeDependence::UnexpandedPack;
+ }
+
+ /// Determines if this type would be canonical if it had no further
+ /// qualification.
+ bool isCanonicalUnqualified() const {
+ return CanonicalType == QualType(this, 0);
+ }
+
+ /// Pull a single level of sugar off of this locally-unqualified type.
+ /// Users should generally prefer SplitQualType::getSingleStepDesugaredType()
+ /// or QualType::getSingleStepDesugaredType(const ASTContext&).
+ QualType getLocallyUnqualifiedSingleStepDesugaredType() const;
+
+ /// As an extension, we classify types as one of "sized" or "sizeless";
+ /// every type is one or the other. Standard types are all sized;
+ /// sizeless types are purely an extension.
+ ///
+ /// Sizeless types contain data with no specified size, alignment,
+ /// or layout.
+ bool isSizelessType() const;
+ bool isSizelessBuiltinType() const;
+
+ /// Returns true for all scalable vector types.
+ bool isSizelessVectorType() const;
+
+ /// Returns true for SVE scalable vector types.
+ bool isSVESizelessBuiltinType() const;
+
+ /// Returns true for RVV scalable vector types.
+ bool isRVVSizelessBuiltinType() const;
+
+ /// Check if this is a WebAssembly Externref Type.
+ bool isWebAssemblyExternrefType() const;
+
+ /// Returns true if this is a WebAssembly table type: either an array of
+ /// reference types, or a pointer to a reference type (which can only be
+ /// created by array to pointer decay).
+ bool isWebAssemblyTableType() const;
+
+ /// Determines if this is a sizeless type supported by the
+ /// 'arm_sve_vector_bits' type attribute, which can be applied to a single
+ /// SVE vector or predicate, excluding tuple types such as svint32x4_t.
+ bool isSveVLSBuiltinType() const;
+
+ /// Returns the representative type for the element of an SVE builtin type.
+ /// This is used to represent fixed-length SVE vectors created with the
+ /// 'arm_sve_vector_bits' type attribute as VectorType.
+ QualType getSveEltType(const ASTContext &Ctx) const;
+
+ /// Determines if this is a sizeless type supported by the
+ /// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single
+ /// RVV vector or mask.
+ bool isRVVVLSBuiltinType() const;
+
+ /// Returns the representative type for the element of an RVV builtin type.
+ /// This is used to represent fixed-length RVV vectors created with the
+ /// 'riscv_rvv_vector_bits' type attribute as VectorType.
+ QualType getRVVEltType(const ASTContext &Ctx) const;
+
+ /// Returns the representative type for the element of a sizeless vector
+ /// builtin type.
+ QualType getSizelessVectorEltType(const ASTContext &Ctx) const;
+
+ /// Types are partitioned into 3 broad categories (C99 6.2.5p1):
+ /// object types, function types, and incomplete types.
+
+ /// Return true if this is an incomplete type.
+ /// A type that can describe objects, but which lacks information needed to
+ /// determine its size (e.g. void, or a fwd declared struct). Clients of this
+ /// routine will need to determine if the size is actually required.
+ ///
+ /// Def If non-null, and the type refers to some kind of declaration
+ /// that can be completed (such as a C struct, C++ class, or Objective-C
+ /// class), will be set to the declaration.
+ bool isIncompleteType(NamedDecl **Def = nullptr) const;
+
+ /// Return true if this is an incomplete or object
+ /// type, in other words, not a function type.
+ bool isIncompleteOrObjectType() const {
+ return !isFunctionType();
+ }
+
+ /// \returns True if the type is incomplete and it is also a type that
+ /// cannot be completed by a later type definition.
+ ///
+ /// E.g. For `void` this is true but for `struct ForwardDecl;` this is false
+ /// because a definition for `ForwardDecl` could be provided later on in the
+ /// translation unit.
+ ///
+ /// Note even for types that this function returns true for it is still
+ /// possible for the declarations that contain this type to later have a
+ /// complete type in a translation unit. E.g.:
+ ///
+ /// \code{.c}
+ /// // This decl has type 'char[]' which is incomplete and cannot be later
+ /// // completed by another by another type declaration.
+ /// extern char foo[];
+ /// // This decl now has complete type 'char[5]'.
+ /// char foo[5]; // foo has a complete type
+ /// \endcode
+ bool isAlwaysIncompleteType() const;
+
+ /// Determine whether this type is an object type.
+ bool isObjectType() const {
+ // C++ [basic.types]p8:
+ // An object type is a (possibly cv-qualified) type that is not a
+ // function type, not a reference type, and not a void type.
+ return !isReferenceType() && !isFunctionType() && !isVoidType();
+ }
+
+ /// Return true if this is a literal type
+ /// (C++11 [basic.types]p10)
+ bool isLiteralType(const ASTContext &Ctx) const;
+
+ /// Determine if this type is a structural type, per C++20 [temp.param]p7.
+ bool isStructuralType() const;
+
+ /// Test if this type is a standard-layout type.
+ /// (C++0x [basic.type]p9)
+ bool isStandardLayoutType() const;
+
+ /// Helper methods to distinguish type categories. All type predicates
+ /// operate on the canonical type, ignoring typedefs and qualifiers.
+
+ /// Returns true if the type is a builtin type.
+ bool isBuiltinType() const;
+
+ /// Test for a particular builtin type.
+ bool isSpecificBuiltinType(unsigned K) const;
+
+ /// Test for a type which does not represent an actual type-system type but
+ /// is instead used as a placeholder for various convenient purposes within
+ /// Clang. All such types are BuiltinTypes.
+ bool isPlaceholderType() const;
+ const BuiltinType *getAsPlaceholderType() const;
+
+ /// Test for a specific placeholder type.
+ bool isSpecificPlaceholderType(unsigned K) const;
+
+ /// Test for a placeholder type other than Overload; see
+ /// BuiltinType::isNonOverloadPlaceholderType.
+ bool isNonOverloadPlaceholderType() const;
+
+ /// isIntegerType() does *not* include complex integers (a GCC extension).
+ /// isComplexIntegerType() can be used to test for complex integers.
+ bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum)
+ bool isEnumeralType() const;
+
+ /// Determine whether this type is a scoped enumeration type.
+ bool isScopedEnumeralType() const;
+ bool isBooleanType() const;
+ bool isCharType() const;
+ bool isWideCharType() const;
+ bool isChar8Type() const;
+ bool isChar16Type() const;
+ bool isChar32Type() const;
+ bool isAnyCharacterType() const;
+ bool isUnicodeCharacterType() const;
+ bool isIntegralType(const ASTContext &Ctx) const;
+
+ /// Determine whether this type is an integral or enumeration type.
+ bool isIntegralOrEnumerationType() const;
+
+ /// Determine whether this type is an integral or unscoped enumeration type.
+ bool isIntegralOrUnscopedEnumerationType() const;
+ bool isUnscopedEnumerationType() const;
+
+ /// Floating point categories.
+ bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
+ /// isComplexType() does *not* include complex integers (a GCC extension).
+ /// isComplexIntegerType() can be used to test for complex integers.
+ bool isComplexType() const; // C99 6.2.5p11 (complex)
+ bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int.
+ bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex)
+ bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
+ bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
+ bool isFloat32Type() const;
+ bool isDoubleType() const;
+ bool isBFloat16Type() const;
+ bool isMFloat8Type() const;
+ bool isFloat128Type() const;
+ bool isIbm128Type() const;
+ bool isRealType() const; // C99 6.2.5p17 (real floating + integer)
+ bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating)
+ bool isVoidType() const; // C99 6.2.5p19
+ bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers)
+ bool isAggregateType() const;
+ bool isFundamentalType() const;
+ bool isCompoundType() const;
+
+ // Type Predicates: Check to see if this type is structurally the specified
+ // type, ignoring typedefs and qualifiers.
+ bool isFunctionType() const;
+ bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); }
+ bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
+ bool isPointerType() const;
+ bool isPointerOrReferenceType() const;
+ bool isSignableType(const ASTContext &Ctx) const;
+ bool isSignablePointerType() const;
+ bool isSignableIntegerType(const ASTContext &Ctx) const;
+ bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
+ bool isCountAttributedType() const;
+ bool isCFIUncheckedCalleeFunctionType() const;
+ bool hasPointeeToToCFIUncheckedCalleeFunctionType() const;
+ bool isBlockPointerType() const;
+ bool isVoidPointerType() const;
+ bool isReferenceType() const;
+ bool isLValueReferenceType() const;
+ bool isRValueReferenceType() const;
+ bool isObjectPointerType() const;
+ bool isFunctionPointerType() const;
+ bool isFunctionReferenceType() const;
+ bool isMemberPointerType() const;
+ bool isMemberFunctionPointerType() const;
+ bool isMemberDataPointerType() const;
+ bool isArrayType() const;
+ bool isConstantArrayType() const;
+ bool isIncompleteArrayType() const;
+ bool isVariableArrayType() const;
+ bool isArrayParameterType() const;
+ bool isDependentSizedArrayType() const;
+ bool isRecordType() const;
+ bool isClassType() const;
+ bool isStructureType() const;
+ bool isStructureTypeWithFlexibleArrayMember() const;
+ bool isObjCBoxableRecordType() const;
+ bool isInterfaceType() const;
+ bool isStructureOrClassType() const;
+ bool isUnionType() const;
+ bool isComplexIntegerType() const; // GCC _Complex integer type.
+ bool isVectorType() const; // GCC vector type.
+ bool isExtVectorType() const; // Extended vector type.
+ bool isExtVectorBoolType() const; // Extended vector type with bool element.
+ // Extended vector type with bool element that is packed. HLSL doesn't pack
+ // its bool vectors.
+ bool isPackedVectorBoolType(const ASTContext &ctx) const;
+ bool isSubscriptableVectorType() const;
+ bool isMatrixType() const; // Matrix type.
+ bool isConstantMatrixType() const; // Constant matrix type.
+ bool isDependentAddressSpaceType() const; // value-dependent address space qualifier
+ bool isObjCObjectPointerType() const; // pointer to ObjC object
+ bool isObjCRetainableType() const; // ObjC object or block pointer
+ bool isObjCLifetimeType() const; // (array of)* retainable type
+ bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type
+ bool isObjCNSObjectType() const; // __attribute__((NSObject))
+ bool isObjCIndependentClassType() const; // __attribute__((objc_independent_class))
+ // FIXME: change this to 'raw' interface type, so we can used 'interface' type
+ // for the common case.
+ bool isObjCObjectType() const; // NSString or typeof(*(id)0)
+ bool isObjCQualifiedInterfaceType() const; // NSString<foo>
+ bool isObjCQualifiedIdType() const; // id<foo>
+ bool isObjCQualifiedClassType() const; // Class<foo>
+ bool isObjCObjectOrInterfaceType() const;
+ bool isObjCIdType() const; // id
+ bool isDecltypeType() const;
+ /// Was this type written with the special inert-in-ARC __unsafe_unretained
+ /// qualifier?
+ ///
+ /// This approximates the answer to the following question: if this
+ /// translation unit were compiled in ARC, would this type be qualified
+ /// with __unsafe_unretained?
+ bool isObjCInertUnsafeUnretainedType() const {
+ return hasAttr(attr::ObjCInertUnsafeUnretained);
+ }
+
+ /// Whether the type is Objective-C 'id' or a __kindof type of an
+ /// object type, e.g., __kindof NSView * or __kindof id
+ /// <NSCopying>.
+ ///
+ /// \param bound Will be set to the bound on non-id subtype types,
+ /// which will be (possibly specialized) Objective-C class type, or
+ /// null for 'id.
+ bool isObjCIdOrObjectKindOfType(const ASTContext &ctx,
+ const ObjCObjectType *&bound) const;
+
+ bool isObjCClassType() const; // Class
+
+ /// Whether the type is Objective-C 'Class' or a __kindof type of an
+ /// Class type, e.g., __kindof Class <NSCopying>.
+ ///
+ /// Unlike \c isObjCIdOrObjectKindOfType, there is no relevant bound
+ /// here because Objective-C's type system cannot express "a class
+ /// object for a subclass of NSFoo".
+ bool isObjCClassOrClassKindOfType() const;
+
+ bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const;
+ bool isObjCSelType() const; // Class
+ bool isObjCBuiltinType() const; // 'id' or 'Class'
+ bool isObjCARCBridgableType() const;
+ bool isCARCBridgableType() const;
+ bool isTemplateTypeParmType() const; // C++ template type parameter
+ bool isNullPtrType() const; // C++11 std::nullptr_t or
+ // C23 nullptr_t
+ bool isNothrowT() const; // C++ std::nothrow_t
+ bool isAlignValT() const; // C++17 std::align_val_t
+ bool isStdByteType() const; // C++17 std::byte
+ bool isAtomicType() const; // C11 _Atomic()
+ bool isUndeducedAutoType() const; // C++11 auto or
+ // C++14 decltype(auto)
+ bool isTypedefNameType() const; // typedef or alias template
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ bool is##Id##Type() const;
+#include "clang/Basic/OpenCLImageTypes.def"
+
+ bool isImageType() const; // Any OpenCL image type
+
+ bool isSamplerT() const; // OpenCL sampler_t
+ bool isEventT() const; // OpenCL event_t
+ bool isClkEventT() const; // OpenCL clk_event_t
+ bool isQueueT() const; // OpenCL queue_t
+ bool isReserveIDT() const; // OpenCL reserve_id_t
+
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ bool is##Id##Type() const;
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ // Type defined in cl_intel_device_side_avc_motion_estimation OpenCL extension
+ bool isOCLIntelSubgroupAVCType() const;
+ bool isOCLExtOpaqueType() const; // Any OpenCL extension type
+
+ bool isPipeType() const; // OpenCL pipe type
+ bool isBitIntType() const; // Bit-precise integer type
+ bool isOpenCLSpecificType() const; // Any OpenCL specific type
+
+#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) bool is##Id##Type() const;
+#include "clang/Basic/HLSLIntangibleTypes.def"
+ bool isHLSLSpecificType() const; // Any HLSL specific type
+ bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type
+ bool isHLSLAttributedResourceType() const;
+ bool isHLSLInlineSpirvType() const;
+ bool isHLSLResourceRecord() const;
+ bool isHLSLResourceRecordArray() const;
+ bool isHLSLIntangibleType()
+ const; // Any HLSL intangible type (builtin, array, class)
+
+ /// Determines if this type, which must satisfy
+ /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
+ /// than implicitly __strong.
+ bool isObjCARCImplicitlyUnretainedType() const;
+
+ /// Check if the type is the CUDA device builtin surface type.
+ bool isCUDADeviceBuiltinSurfaceType() const;
+ /// Check if the type is the CUDA device builtin texture type.
+ bool isCUDADeviceBuiltinTextureType() const;
+
+ /// Return the implicit lifetime for this type, which must not be dependent.
+ Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
+
+ enum ScalarTypeKind {
+ STK_CPointer,
+ STK_BlockPointer,
+ STK_ObjCObjectPointer,
+ STK_MemberPointer,
+ STK_Bool,
+ STK_Integral,
+ STK_Floating,
+ STK_IntegralComplex,
+ STK_FloatingComplex,
+ STK_FixedPoint
+ };
+
+ /// Given that this is a scalar type, classify it.
+ ScalarTypeKind getScalarTypeKind() const;
+
+ TypeDependence getDependence() const {
+ return static_cast<TypeDependence>(TypeBits.Dependence);
+ }
+
+ /// Whether this type is an error type.
+ bool containsErrors() const {
+ return getDependence() & TypeDependence::Error;
+ }
+
+ /// Whether this type is a dependent type, meaning that its definition
+ /// somehow depends on a template parameter (C++ [temp.dep.type]).
+ bool isDependentType() const {
+ return getDependence() & TypeDependence::Dependent;
+ }
+
+ /// Determine whether this type is an instantiation-dependent type,
+ /// meaning that the type involves a template parameter (even if the
+ /// definition does not actually depend on the type substituted for that
+ /// template parameter).
+ bool isInstantiationDependentType() const {
+ return getDependence() & TypeDependence::Instantiation;
+ }
+
+ /// Determine whether this type is an undeduced type, meaning that
+ /// it somehow involves a C++11 'auto' type or similar which has not yet been
+ /// deduced.
+ bool isUndeducedType() const;
+
+ /// Whether this type is a variably-modified type (C99 6.7.5).
+ bool isVariablyModifiedType() const {
+ return getDependence() & TypeDependence::VariablyModified;
+ }
+
+ /// Whether this type involves a variable-length array type
+ /// with a definite size.
+ bool hasSizedVLAType() const;
+
+ /// Whether this type is or contains a local or unnamed type.
+ bool hasUnnamedOrLocalType() const;
+
+ bool isOverloadableType() const;
+
+ /// Determine wither this type is a C++ elaborated-type-specifier.
+ bool isElaboratedTypeSpecifier() const;
+
+ bool canDecayToPointerType() const;
+
+ /// Whether this type is represented natively as a pointer. This includes
+ /// pointers, references, block pointers, and Objective-C interface,
+ /// qualified id, and qualified interface types, as well as nullptr_t.
+ bool hasPointerRepresentation() const;
+
+ /// Whether this type can represent an objective pointer type for the
+ /// purpose of GC'ability
+ bool hasObjCPointerRepresentation() const;
+
+ /// Determine whether this type has an integer representation
+ /// of some sort, e.g., it is an integer type or a vector.
+ bool hasIntegerRepresentation() const;
+
+ /// Determine whether this type has an signed integer representation
+ /// of some sort, e.g., it is an signed integer type or a vector.
+ bool hasSignedIntegerRepresentation() const;
+
+ /// Determine whether this type has an unsigned integer representation
+ /// of some sort, e.g., it is an unsigned integer type or a vector.
+ bool hasUnsignedIntegerRepresentation() const;
+
+ /// Determine whether this type has a floating-point representation
+ /// of some sort, e.g., it is a floating-point type or a vector thereof.
+ bool hasFloatingRepresentation() const;
+
+ /// Determine whether this type has a boolean representation -- i.e., it is a
+ /// boolean type, an enum type whose underlying type is a boolean type, or a
+ /// vector of booleans.
+ bool hasBooleanRepresentation() const;
+
+ // Type Checking Functions: Check to see if this type is structurally the
+ // specified type, ignoring typedefs and qualifiers, and return a pointer to
+ // the best type we can.
+ const RecordType *getAsStructureType() const;
+ /// NOTE: getAs*ArrayType are methods on ASTContext.
+ const RecordType *getAsUnionType() const;
+ const ComplexType *getAsComplexIntegerType() const; // GCC complex int type.
+ const ObjCObjectType *getAsObjCInterfaceType() const;
+
+ // The following is a convenience method that returns an ObjCObjectPointerType
+ // for object declared using an interface.
+ const ObjCObjectPointerType *getAsObjCInterfacePointerType() const;
+ const ObjCObjectPointerType *getAsObjCQualifiedIdType() const;
+ const ObjCObjectPointerType *getAsObjCQualifiedClassType() const;
+ const ObjCObjectType *getAsObjCQualifiedInterfaceType() const;
+
+ /// Retrieves the CXXRecordDecl that this type refers to, either
+ /// because the type is a RecordType or because it is the injected-class-name
+ /// type of a class template or class template partial specialization.
+ inline CXXRecordDecl *getAsCXXRecordDecl() const;
+ inline CXXRecordDecl *castAsCXXRecordDecl() const;
+
+ /// Retrieves the RecordDecl this type refers to.
+ inline RecordDecl *getAsRecordDecl() const;
+ inline RecordDecl *castAsRecordDecl() const;
+
+ /// Retrieves the EnumDecl this type refers to.
+ inline EnumDecl *getAsEnumDecl() const;
+ inline EnumDecl *castAsEnumDecl() const;
+
+ /// Retrieves the TagDecl that this type refers to, either
+ /// because the type is a TagType or because it is the injected-class-name
+ /// type of a class template or class template partial specialization.
+ inline TagDecl *getAsTagDecl() const;
+ inline TagDecl *castAsTagDecl() const;
+
+ /// If this is a pointer or reference to a RecordType, return the
+ /// CXXRecordDecl that the type refers to.
+ ///
+ /// If this is not a pointer or reference, or the type being pointed to does
+ /// not refer to a CXXRecordDecl, returns NULL.
+ const CXXRecordDecl *getPointeeCXXRecordDecl() const;
+
+ /// Get the DeducedType whose type will be deduced for a variable with
+ /// an initializer of this type. This looks through declarators like pointer
+ /// types, but not through decltype or typedefs.
+ DeducedType *getContainedDeducedType() const;
+
+ /// Get the AutoType whose type will be deduced for a variable with
+ /// an initializer of this type. This looks through declarators like pointer
+ /// types, but not through decltype or typedefs.
+ AutoType *getContainedAutoType() const {
+ return dyn_cast_or_null<AutoType>(getContainedDeducedType());
+ }
+
+ /// Determine whether this type was written with a leading 'auto'
+ /// corresponding to a trailing return type (possibly for a nested
+ /// function type within a pointer to function type or similar).
+ bool hasAutoForTrailingReturnType() const;
+
+ /// Member-template getAs<specific type>'. Look through sugar for
+ /// an instance of \<specific type>. This scheme will eventually
+ /// replace the specific getAsXXXX methods above.
+ ///
+ /// There are some specializations of this member template listed
+ /// immediately following this class.
+ ///
+ /// If you are interested only in the canonical properties of this type,
+ /// consider using getAsCanonical instead, as that is much faster.
+ template <typename T> const T *getAs() const;
+
+ /// If this type is canonically the specified type, return its canonical type
+ /// cast to that specified type, otherwise returns null.
+ template <typename T> const T *getAsCanonical() const {
+ return dyn_cast<T>(CanonicalType);
+ }
+
+ /// Return this type's canonical type cast to the specified type.
+ /// If the type is not canonically that specified type, the behaviour is
+ /// undefined.
+ template <typename T> const T *castAsCanonical() const {
+ return cast<T>(CanonicalType);
+ }
+
+// It is not helpful to use these on types which are never canonical
+#define TYPE(Class, Base)
+#define NEVER_CANONICAL_TYPE(Class) \
+ template <> inline const Class##Type *Type::getAsCanonical() const = delete; \
+ template <> inline const Class##Type *Type::castAsCanonical() const = delete;
+#include "clang/AST/TypeNodes.inc"
+
+ /// Look through sugar for an instance of TemplateSpecializationType which
+ /// is not a type alias, or null if there is no such type.
+ /// This is used when you want as-written template arguments or the template
+ /// name for a class template specialization.
+ const TemplateSpecializationType *
+ getAsNonAliasTemplateSpecializationType() const;
+
+ const TemplateSpecializationType *
+ castAsNonAliasTemplateSpecializationType() const {
+ const auto *TST = getAsNonAliasTemplateSpecializationType();
+ assert(TST && "not a TemplateSpecializationType");
+ return TST;
+ }
+
+ /// Member-template getAsAdjusted<specific type>. Look through specific kinds
+ /// of sugar (parens, attributes, etc) for an instance of \<specific type>.
+ /// This is used when you need to walk over sugar nodes that represent some
+ /// kind of type adjustment from a type that was written as a \<specific type>
+ /// to another type that is still canonically a \<specific type>.
+ template <typename T> const T *getAsAdjusted() const;
+
+ /// A variant of getAs<> for array types which silently discards
+ /// qualifiers from the outermost type.
+ const ArrayType *getAsArrayTypeUnsafe() const;
+
+ /// Member-template castAs<specific type>. Look through sugar for
+ /// the underlying instance of \<specific type>.
+ ///
+ /// This method has the same relationship to getAs<T> as cast<T> has
+ /// to dyn_cast<T>; which is to say, the underlying type *must*
+ /// have the intended type, and this method will never return null.
+ template <typename T> const T *castAs() const;
+
+ /// A variant of castAs<> for array type which silently discards
+ /// qualifiers from the outermost type.
+ const ArrayType *castAsArrayTypeUnsafe() const;
+
+ /// If this type represents a qualified-id, this returns its nested name
+ /// specifier. For example, for the qualified-id "foo::bar::baz", this returns
+ /// "foo::bar". Returns null if this type represents an unqualified-id.
+ NestedNameSpecifier getPrefix() const;
+
+ /// Determine whether this type had the specified attribute applied to it
+ /// (looking through top-level type sugar).
+ bool hasAttr(attr::Kind AK) const;
+
+ /// Get the base element type of this type, potentially discarding type
+ /// qualifiers. This should never be used when type qualifiers
+ /// are meaningful.
+ const Type *getBaseElementTypeUnsafe() const;
+
+ /// If this is an array type, return the element type of the array,
+ /// potentially with type qualifiers missing.
+ /// This should never be used when type qualifiers are meaningful.
+ const Type *getArrayElementTypeNoTypeQual() const;
+
+ /// If this is a pointer type, return the pointee type.
+ /// If this is an array type, return the array element type.
+ /// This should never be used when type qualifiers are meaningful.
+ const Type *getPointeeOrArrayElementType() const;
+
+ /// If this is a pointer, ObjC object pointer, or block
+ /// pointer, this returns the respective pointee.
+ QualType getPointeeType() const;
+
+ /// Return the specified type with any "sugar" removed from the type,
+ /// removing any typedefs, typeofs, etc., as well as any qualifiers.
+ const Type *getUnqualifiedDesugaredType() const;
+
+ /// Return true if this is an integer type that is
+ /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..],
+ /// or an enum decl which has a signed representation.
+ bool isSignedIntegerType() const;
+
+ /// Return true if this is an integer type that is
+ /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool],
+ /// or an enum decl which has an unsigned representation.
+ bool isUnsignedIntegerType() const;
+
+ /// Determines whether this is an integer type that is signed or an
+ /// enumeration types whose underlying type is a signed integer type.
+ bool isSignedIntegerOrEnumerationType() const;
+
+ /// Determines whether this is an integer type that is unsigned or an
+ /// enumeration types whose underlying type is a unsigned integer type.
+ bool isUnsignedIntegerOrEnumerationType() const;
+
+ /// Return true if this is a fixed point type according to
+ /// ISO/IEC JTC1 SC22 WG14 N1169.
+ bool isFixedPointType() const;
+
+ /// Return true if this is a fixed point or integer type.
+ bool isFixedPointOrIntegerType() const;
+
+ /// Return true if this can be converted to (or from) a fixed point type.
+ bool isConvertibleToFixedPointType() const;
+
+ /// Return true if this is a saturated fixed point type according to
+ /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned.
+ bool isSaturatedFixedPointType() const;
+
+ /// Return true if this is a saturated fixed point type according to
+ /// ISO/IEC JTC1 SC22 WG14 N1169. This type can be signed or unsigned.
+ bool isUnsaturatedFixedPointType() const;
+
+ /// Return true if this is a fixed point type that is signed according
+ /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated.
+ bool isSignedFixedPointType() const;
+
+ /// Return true if this is a fixed point type that is unsigned according
+ /// to ISO/IEC JTC1 SC22 WG14 N1169. This type can also be saturated.
+ bool isUnsignedFixedPointType() const;
+
+ /// Return true if this is not a variable sized type,
+ /// according to the rules of C99 6.7.5p3. It is not legal to call this on
+ /// incomplete types.
+ bool isConstantSizeType() const;
+
+ /// Returns true if this type can be represented by some
+ /// set of type specifiers.
+ bool isSpecifierType() const;
+
+ /// Determine the linkage of this type.
+ Linkage getLinkage() const;
+
+ /// Determine the visibility of this type.
+ Visibility getVisibility() const {
+ return getLinkageAndVisibility().getVisibility();
+ }
+
+ /// Return true if the visibility was explicitly set is the code.
+ bool isVisibilityExplicit() const {
+ return getLinkageAndVisibility().isVisibilityExplicit();
+ }
+
+ /// Determine the linkage and visibility of this type.
+ LinkageInfo getLinkageAndVisibility() const;
+
+ /// True if the computed linkage is valid. Used for consistency
+ /// checking. Should always return true.
+ bool isLinkageValid() const;
+
+ /// Determine the nullability of the given type.
+ ///
+ /// Note that nullability is only captured as sugar within the type
+ /// system, not as part of the canonical type, so nullability will
+ /// be lost by canonicalization and desugaring.
+ std::optional<NullabilityKind> getNullability() const;
+
+ /// Determine whether the given type can have a nullability
+ /// specifier applied to it, i.e., if it is any kind of pointer type.
+ ///
+ /// \param ResultIfUnknown The value to return if we don't yet know whether
+ /// this type can have nullability because it is dependent.
+ bool canHaveNullability(bool ResultIfUnknown = true) const;
+
+ /// Retrieve the set of substitutions required when accessing a member
+ /// of the Objective-C receiver type that is declared in the given context.
+ ///
+ /// \c *this is the type of the object we're operating on, e.g., the
+ /// receiver for a message send or the base of a property access, and is
+ /// expected to be of some object or object pointer type.
+ ///
+ /// \param dc The declaration context for which we are building up a
+ /// substitution mapping, which should be an Objective-C class, extension,
+ /// category, or method within.
+ ///
+ /// \returns an array of type arguments that can be substituted for
+ /// the type parameters of the given declaration context in any type described
+ /// within that context, or an empty optional to indicate that no
+ /// substitution is required.
+ std::optional<ArrayRef<QualType>>
+ getObjCSubstitutions(const DeclContext *dc) const;
+
+ /// Determines if this is an ObjC interface type that may accept type
+ /// parameters.
+ bool acceptsObjCTypeParams() const;
+
+ const char *getTypeClassName() const;
+
+ QualType getCanonicalTypeInternal() const {
+ return CanonicalType;
+ }
+
+ CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h
+ void dump() const;
+ void dump(llvm::raw_ostream &OS, const ASTContext &Context) const;
+};
+
+/// This will check for a TypedefType by removing any existing sugar
+/// until it reaches a TypedefType or a non-sugared type.
+template <> const TypedefType *Type::getAs() const;
+template <> const UsingType *Type::getAs() const;
+
+/// This will check for a TemplateSpecializationType by removing any
+/// existing sugar until it reaches a TemplateSpecializationType or a
+/// non-sugared type.
+template <> const TemplateSpecializationType *Type::getAs() const;
+
+/// This will check for an AttributedType by removing any existing sugar
+/// until it reaches an AttributedType or a non-sugared type.
+template <> const AttributedType *Type::getAs() const;
+
+/// This will check for a BoundsAttributedType by removing any existing
+/// sugar until it reaches an BoundsAttributedType or a non-sugared type.
+template <> const BoundsAttributedType *Type::getAs() const;
+
+/// This will check for a CountAttributedType by removing any existing
+/// sugar until it reaches an CountAttributedType or a non-sugared type.
+template <> const CountAttributedType *Type::getAs() const;
+
+// We can do always canonical types faster, because we don't have to
+// worry about preserving decoration.
+#define TYPE(Class, Base)
+#define ALWAYS_CANONICAL_TYPE(Class) \
+ template <> inline const Class##Type *Type::getAs() const { \
+ return dyn_cast<Class##Type>(CanonicalType); \
+ } \
+ template <> inline const Class##Type *Type::castAs() const { \
+ return cast<Class##Type>(CanonicalType); \
+ }
+#include "clang/AST/TypeNodes.inc"
+
+/// This class is used for builtin types like 'int'. Builtin
+/// types are always canonical and have a literal name field.
+class BuiltinType : public Type {
+public:
+ enum Kind {
+// OpenCL image types
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) Id,
+#include "clang/Basic/OpenCLImageTypes.def"
+// OpenCL extension types
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id,
+#include "clang/Basic/OpenCLExtensionTypes.def"
+// SVE Types
+#define SVE_TYPE(Name, Id, SingletonId) Id,
+#include "clang/Basic/AArch64ACLETypes.def"
+// PPC MMA Types
+#define PPC_VECTOR_TYPE(Name, Id, Size) Id,
+#include "clang/Basic/PPCTypes.def"
+// RVV Types
+#define RVV_TYPE(Name, Id, SingletonId) Id,
+#include "clang/Basic/RISCVVTypes.def"
+// WebAssembly reference types
+#define WASM_TYPE(Name, Id, SingletonId) Id,
+#include "clang/Basic/WebAssemblyReferenceTypes.def"
+// AMDGPU types
+#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) Id,
+#include "clang/Basic/AMDGPUTypes.def"
+// HLSL intangible Types
+#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id,
+#include "clang/Basic/HLSLIntangibleTypes.def"
+// All other builtin types
+#define BUILTIN_TYPE(Id, SingletonId) Id,
+#define LAST_BUILTIN_TYPE(Id) LastKind = Id
+#include "clang/AST/BuiltinTypes.def"
+ };
+
+private:
+ friend class ASTContext; // ASTContext creates these.
+
+ BuiltinType(Kind K)
+ : Type(Builtin, QualType(),
+ K == Dependent ? TypeDependence::DependentInstantiation
+ : TypeDependence::None) {
+ static_assert(Kind::LastKind <
+ (1 << BuiltinTypeBitfields::NumOfBuiltinTypeBits) &&
+ "Defined builtin type exceeds the allocated space for serial "
+ "numbering");
+ BuiltinTypeBits.Kind = K;
+ }
+
+public:
+ Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); }
+ StringRef getName(const PrintingPolicy &Policy) const;
+
+ const char *getNameAsCString(const PrintingPolicy &Policy) const {
+ // The StringRef is null-terminated.
+ StringRef str = getName(Policy);
+ assert(!str.empty() && str.data()[str.size()] == '\0');
+ return str.data();
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ bool isInteger() const {
+ return getKind() >= Bool && getKind() <= Int128;
+ }
+
+ bool isSignedInteger() const {
+ return getKind() >= Char_S && getKind() <= Int128;
+ }
+
+ bool isUnsignedInteger() const {
+ return getKind() >= Bool && getKind() <= UInt128;
+ }
+
+ bool isFloatingPoint() const {
+ return getKind() >= Half && getKind() <= Ibm128;
+ }
+
+ bool isSVEBool() const { return getKind() == Kind::SveBool; }
+
+ bool isSVECount() const { return getKind() == Kind::SveCount; }
+
+ /// Determines whether the given kind corresponds to a placeholder type.
+ static bool isPlaceholderTypeKind(Kind K) {
+ return K >= Overload;
+ }
+
+ /// Determines whether this type is a placeholder type, i.e. a type
+ /// which cannot appear in arbitrary positions in a fully-formed
+ /// expression.
+ bool isPlaceholderType() const {
+ return isPlaceholderTypeKind(getKind());
+ }
+
+ /// Determines whether this type is a placeholder type other than
+ /// Overload. Most placeholder types require only syntactic
+ /// information about their context in order to be resolved (e.g.
+ /// whether it is a call expression), which means they can (and
+ /// should) be resolved in an earlier "phase" of analysis.
+ /// Overload expressions sometimes pick up further information
+ /// from their context, like whether the context expects a
+ /// specific function-pointer type, and so frequently need
+ /// special treatment.
+ bool isNonOverloadPlaceholderType() const {
+ return getKind() > Overload;
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Builtin; }
+};
+
+/// Complex values, per C99 6.2.5p11. This supports the C99 complex
+/// types (_Complex float etc) as well as the GCC integer complex extensions.
+class ComplexType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType ElementType;
+
+ ComplexType(QualType Element, QualType CanonicalPtr)
+ : Type(Complex, CanonicalPtr, Element->getDependence()),
+ ElementType(Element) {}
+
+public:
+ QualType getElementType() const { return ElementType; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) {
+ ID.AddPointer(Element.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Complex; }
+};
+
+/// Sugar for parentheses used when specifying types.
+class ParenType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType Inner;
+
+ ParenType(QualType InnerType, QualType CanonType)
+ : Type(Paren, CanonType, InnerType->getDependence()), Inner(InnerType) {}
+
+public:
+ QualType getInnerType() const { return Inner; }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return getInnerType(); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getInnerType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) {
+ Inner.Profile(ID);
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Paren; }
+};
+
+/// PointerType - C99 6.7.5.1 - Pointer Declarators.
+class PointerType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType PointeeType;
+
+ PointerType(QualType Pointee, QualType CanonicalPtr)
+ : Type(Pointer, CanonicalPtr, Pointee->getDependence()),
+ PointeeType(Pointee) {}
+
+public:
+ QualType getPointeeType() const { return PointeeType; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
+ ID.AddPointer(Pointee.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
+};
+
+/// [BoundsSafety] Represents information of declarations referenced by the
+/// arguments of the `counted_by` attribute and the likes.
+class TypeCoupledDeclRefInfo {
+public:
+ using BaseTy = llvm::PointerIntPair<ValueDecl *, 1, unsigned>;
+
+private:
+ enum {
+ DerefShift = 0,
+ DerefMask = 1,
+ };
+ BaseTy Data;
+
+public:
+ /// \p D is to a declaration referenced by the argument of attribute. \p Deref
+ /// indicates whether \p D is referenced as a dereferenced form, e.g., \p
+ /// Deref is true for `*n` in `int *__counted_by(*n)`.
+ TypeCoupledDeclRefInfo(ValueDecl *D = nullptr, bool Deref = false);
+
+ bool isDeref() const;
+ ValueDecl *getDecl() const;
+ unsigned getInt() const;
+ void *getOpaqueValue() const;
+ bool operator==(const TypeCoupledDeclRefInfo &Other) const;
+ void setFromOpaqueValue(void *V);
+};
+
+/// [BoundsSafety] Represents a parent type class for CountAttributedType and
+/// similar sugar types that will be introduced to represent a type with a
+/// bounds attribute.
+///
+/// Provides a common interface to navigate declarations referred to by the
+/// bounds expression.
+
+class BoundsAttributedType : public Type, public llvm::FoldingSetNode {
+ QualType WrappedTy;
+
+protected:
+ ArrayRef<TypeCoupledDeclRefInfo> Decls; // stored in trailing objects
+
+ BoundsAttributedType(TypeClass TC, QualType Wrapped, QualType Canon);
+
+public:
+ bool isSugared() const { return true; }
+ QualType desugar() const { return WrappedTy; }
+
+ using decl_iterator = const TypeCoupledDeclRefInfo *;
+ using decl_range = llvm::iterator_range<decl_iterator>;
+
+ decl_iterator dependent_decl_begin() const { return Decls.begin(); }
+ decl_iterator dependent_decl_end() const { return Decls.end(); }
+
+ unsigned getNumCoupledDecls() const { return Decls.size(); }
+
+ decl_range dependent_decls() const {
+ return decl_range(dependent_decl_begin(), dependent_decl_end());
+ }
+
+ ArrayRef<TypeCoupledDeclRefInfo> getCoupledDecls() const {
+ return {dependent_decl_begin(), dependent_decl_end()};
+ }
+
+ bool referencesFieldDecls() const;
+
+ static bool classof(const Type *T) {
+ // Currently, only `class CountAttributedType` inherits
+ // `BoundsAttributedType` but the subclass will grow as we add more bounds
+ // annotations.
+ switch (T->getTypeClass()) {
+ case CountAttributed:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
+/// Represents a sugar type with `__counted_by` or `__sized_by` annotations,
+/// including their `_or_null` variants.
+class CountAttributedType final
+ : public BoundsAttributedType,
+ public llvm::TrailingObjects<CountAttributedType,
+ TypeCoupledDeclRefInfo> {
+ friend class ASTContext;
+
+ Expr *CountExpr;
+ /// \p CountExpr represents the argument of __counted_by or the likes. \p
+ /// CountInBytes indicates that \p CountExpr is a byte count (i.e.,
+ /// __sized_by(_or_null)) \p OrNull means it's an or_null variant (i.e.,
+ /// __counted_by_or_null or __sized_by_or_null) \p CoupledDecls contains the
+ /// list of declarations referenced by \p CountExpr, which the type depends on
+ /// for the bounds information.
+ CountAttributedType(QualType Wrapped, QualType Canon, Expr *CountExpr,
+ bool CountInBytes, bool OrNull,
+ ArrayRef<TypeCoupledDeclRefInfo> CoupledDecls);
+
+ unsigned numTrailingObjects(OverloadToken<TypeCoupledDeclRefInfo>) const {
+ return CountAttributedTypeBits.NumCoupledDecls;
+ }
+
+public:
+ enum DynamicCountPointerKind {
+ CountedBy = 0,
+ SizedBy,
+ CountedByOrNull,
+ SizedByOrNull,
+ };
+
+ Expr *getCountExpr() const { return CountExpr; }
+ bool isCountInBytes() const { return CountAttributedTypeBits.CountInBytes; }
+ bool isOrNull() const { return CountAttributedTypeBits.OrNull; }
+
+ DynamicCountPointerKind getKind() const {
+ if (isOrNull())
+ return isCountInBytes() ? SizedByOrNull : CountedByOrNull;
+ return isCountInBytes() ? SizedBy : CountedBy;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, desugar(), CountExpr, isCountInBytes(), isOrNull());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType WrappedTy,
+ Expr *CountExpr, bool CountInBytes, bool Nullable);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == CountAttributed;
+ }
+
+ StringRef getAttributeName(bool WithMacroPrefix) const;
+};
+
+/// Represents a type which was implicitly adjusted by the semantic
+/// engine for arbitrary reasons. For example, array and function types can
+/// decay, and function types can have their calling conventions adjusted.
+class AdjustedType : public Type, public llvm::FoldingSetNode {
+ QualType OriginalTy;
+ QualType AdjustedTy;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+
+ AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy,
+ QualType CanonicalPtr)
+ : Type(TC, CanonicalPtr, OriginalTy->getDependence()),
+ OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {}
+
+public:
+ QualType getOriginalType() const { return OriginalTy; }
+ QualType getAdjustedType() const { return AdjustedTy; }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return AdjustedTy; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, OriginalTy, AdjustedTy);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Orig, QualType New) {
+ ID.AddPointer(Orig.getAsOpaquePtr());
+ ID.AddPointer(New.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Adjusted || T->getTypeClass() == Decayed;
+ }
+};
+
+/// Represents a pointer type decayed from an array or function type.
+class DecayedType : public AdjustedType {
+ friend class ASTContext; // ASTContext creates these.
+
+ inline
+ DecayedType(QualType OriginalType, QualType Decayed, QualType Canonical);
+
+public:
+ QualType getDecayedType() const { return getAdjustedType(); }
+
+ inline QualType getPointeeType() const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Decayed; }
+};
+
+/// Pointer to a block type.
+/// This type is to represent types syntactically represented as
+/// "void (^)(int)", etc. Pointee is required to always be a function type.
+class BlockPointerType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ // Block is some kind of pointer type
+ QualType PointeeType;
+
+ BlockPointerType(QualType Pointee, QualType CanonicalCls)
+ : Type(BlockPointer, CanonicalCls, Pointee->getDependence()),
+ PointeeType(Pointee) {}
+
+public:
+ // Get the pointee type. Pointee is required to always be a function type.
+ QualType getPointeeType() const { return PointeeType; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) {
+ ID.AddPointer(Pointee.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == BlockPointer;
+ }
+};
+
+/// Base for LValueReferenceType and RValueReferenceType
+class ReferenceType : public Type, public llvm::FoldingSetNode {
+ QualType PointeeType;
+
+protected:
+ ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef,
+ bool SpelledAsLValue)
+ : Type(tc, CanonicalRef, Referencee->getDependence()),
+ PointeeType(Referencee) {
+ ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue;
+ ReferenceTypeBits.InnerRef = Referencee->isReferenceType();
+ }
+
+public:
+ bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; }
+ bool isInnerRef() const { return ReferenceTypeBits.InnerRef; }
+
+ QualType getPointeeTypeAsWritten() const { return PointeeType; }
+
+ QualType getPointeeType() const {
+ // FIXME: this might strip inner qualifiers; okay?
+ const ReferenceType *T = this;
+ while (T->isInnerRef())
+ T = T->PointeeType->castAs<ReferenceType>();
+ return T->PointeeType;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, PointeeType, isSpelledAsLValue());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ QualType Referencee,
+ bool SpelledAsLValue) {
+ ID.AddPointer(Referencee.getAsOpaquePtr());
+ ID.AddBoolean(SpelledAsLValue);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == LValueReference ||
+ T->getTypeClass() == RValueReference;
+ }
+};
+
+/// An lvalue reference type, per C++11 [dcl.ref].
+class LValueReferenceType : public ReferenceType {
+ friend class ASTContext; // ASTContext creates these
+
+ LValueReferenceType(QualType Referencee, QualType CanonicalRef,
+ bool SpelledAsLValue)
+ : ReferenceType(LValueReference, Referencee, CanonicalRef,
+ SpelledAsLValue) {}
+
+public:
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == LValueReference;
+ }
+};
+
+/// An rvalue reference type, per C++11 [dcl.ref].
+class RValueReferenceType : public ReferenceType {
+ friend class ASTContext; // ASTContext creates these
+
+ RValueReferenceType(QualType Referencee, QualType CanonicalRef)
+ : ReferenceType(RValueReference, Referencee, CanonicalRef, false) {}
+
+public:
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == RValueReference;
+ }
+};
+
+/// A pointer to member type per C++ 8.3.3 - Pointers to members.
+///
+/// This includes both pointers to data members and pointer to member functions.
+class MemberPointerType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType PointeeType;
+
+ /// The class of which the pointee is a member. Must ultimately be a
+ /// CXXRecordType, but could be a typedef or a template parameter too.
+ NestedNameSpecifier Qualifier;
+
+ MemberPointerType(QualType Pointee, NestedNameSpecifier Qualifier,
+ QualType CanonicalPtr)
+ : Type(MemberPointer, CanonicalPtr,
+ (toTypeDependence(Qualifier.getDependence()) &
+ ~TypeDependence::VariablyModified) |
+ Pointee->getDependence()),
+ PointeeType(Pointee), Qualifier(Qualifier) {}
+
+public:
+ QualType getPointeeType() const { return PointeeType; }
+
+ /// Returns true if the member type (i.e. the pointee type) is a
+ /// function type rather than a data-member type.
+ bool isMemberFunctionPointer() const {
+ return PointeeType->isFunctionProtoType();
+ }
+
+ /// Returns true if the member type (i.e. the pointee type) is a
+ /// data type rather than a function type.
+ bool isMemberDataPointer() const {
+ return !PointeeType->isFunctionProtoType();
+ }
+
+ NestedNameSpecifier getQualifier() const { return Qualifier; }
+ /// Note: this can trigger extra deserialization when external AST sources are
+ /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent
+ /// decl.
+ CXXRecordDecl *getMostRecentCXXRecordDecl() const;
+
+ bool isSugared() const;
+ QualType desugar() const {
+ return isSugared() ? getCanonicalTypeInternal() : QualType(this, 0);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ // FIXME: `getMostRecentCXXRecordDecl()` should be possible to use here,
+ // however when external AST sources are used it causes nondeterminism
+ // issues (see https://github.com/llvm/llvm-project/pull/137910).
+ Profile(ID, getPointeeType(), getQualifier(), getCXXRecordDecl());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
+ const NestedNameSpecifier Qualifier,
+ const CXXRecordDecl *Cls);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == MemberPointer;
+ }
+
+private:
+ CXXRecordDecl *getCXXRecordDecl() const;
+};
+
+/// Capture whether this is a normal array (e.g. int X[4])
+/// an array with a static size (e.g. int X[static 4]), or an array
+/// with a star size (e.g. int X[*]).
+/// 'static' is only allowed on function parameters.
+enum class ArraySizeModifier { Normal, Static, Star };
+
+/// Represents an array type, per C99 6.7.5.2 - Array Declarators.
+class ArrayType : public Type, public llvm::FoldingSetNode {
+private:
+ /// The element type of the array.
+ QualType ElementType;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+
+ ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm,
+ unsigned tq, const Expr *sz = nullptr);
+
+public:
+ QualType getElementType() const { return ElementType; }
+
+ ArraySizeModifier getSizeModifier() const {
+ return ArraySizeModifier(ArrayTypeBits.SizeModifier);
+ }
+
+ Qualifiers getIndexTypeQualifiers() const {
+ return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers());
+ }
+
+ unsigned getIndexTypeCVRQualifiers() const {
+ return ArrayTypeBits.IndexTypeQuals;
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArray ||
+ T->getTypeClass() == VariableArray ||
+ T->getTypeClass() == IncompleteArray ||
+ T->getTypeClass() == DependentSizedArray ||
+ T->getTypeClass() == ArrayParameter;
+ }
+};
+
+/// Represents the canonical version of C arrays with a specified constant size.
+/// For example, the canonical type for 'int A[4 + 4*100]' is a
+/// ConstantArrayType where the element type is 'int' and the size is 404.
+class ConstantArrayType : public ArrayType {
+ friend class ASTContext; // ASTContext creates these.
+
+ struct ExternalSize {
+ ExternalSize(const llvm::APInt &Sz, const Expr *SE)
+ : Size(Sz), SizeExpr(SE) {}
+ llvm::APInt Size; // Allows us to unique the type.
+ const Expr *SizeExpr;
+ };
+
+ union {
+ uint64_t Size;
+ ExternalSize *SizePtr;
+ };
+
+ ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz,
+ ArraySizeModifier SM, unsigned TQ)
+ : ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) {
+ ConstantArrayTypeBits.HasExternalSize = false;
+ ConstantArrayTypeBits.SizeWidth = Width / 8;
+ // The in-structure size stores the size in bytes rather than bits so we
+ // drop the three least significant bits since they're always zero anyways.
+ assert(Width < 0xFF && "Type width in bits must be less than 8 bits");
+ }
+
+ ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr,
+ ArraySizeModifier SM, unsigned TQ)
+ : ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr),
+ SizePtr(SzPtr) {
+ ConstantArrayTypeBits.HasExternalSize = true;
+ ConstantArrayTypeBits.SizeWidth = 0;
+
+ assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) &&
+ "canonical constant array should not have size expression");
+ }
+
+ static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET,
+ QualType Can, const llvm::APInt &Sz,
+ const Expr *SzExpr, ArraySizeModifier SzMod,
+ unsigned Qual);
+
+protected:
+ ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can)
+ : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(),
+ ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) {
+ ConstantArrayTypeBits.HasExternalSize =
+ ATy->ConstantArrayTypeBits.HasExternalSize;
+ if (!ConstantArrayTypeBits.HasExternalSize) {
+ ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth;
+ Size = ATy->Size;
+ } else
+ SizePtr = ATy->SizePtr;
+ }
+
+public:
+ /// Return the constant array size as an APInt.
+ llvm::APInt getSize() const {
+ return ConstantArrayTypeBits.HasExternalSize
+ ? SizePtr->Size
+ : llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size);
+ }
+
+ /// Return the bit width of the size type.
+ unsigned getSizeBitWidth() const {
+ return ConstantArrayTypeBits.HasExternalSize
+ ? SizePtr->Size.getBitWidth()
+ : static_cast<unsigned>(ConstantArrayTypeBits.SizeWidth * 8);
+ }
+
+ /// Return true if the size is zero.
+ bool isZeroSize() const {
+ return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero()
+ : 0 == Size;
+ }
+
+ /// Return the size zero-extended as a uint64_t.
+ uint64_t getZExtSize() const {
+ return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue()
+ : Size;
+ }
+
+ /// Return the size sign-extended as a uint64_t.
+ int64_t getSExtSize() const {
+ return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue()
+ : static_cast<int64_t>(Size);
+ }
+
+ /// Return the size zero-extended to uint64_t or UINT64_MAX if the value is
+ /// larger than UINT64_MAX.
+ uint64_t getLimitedSize() const {
+ return ConstantArrayTypeBits.HasExternalSize
+ ? SizePtr->Size.getLimitedValue()
+ : Size;
+ }
+
+ /// Return a pointer to the size expression.
+ const Expr *getSizeExpr() const {
+ return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ /// Determine the number of bits required to address a member of
+ // an array with the given element type and number of elements.
+ static unsigned getNumAddressingBits(const ASTContext &Context,
+ QualType ElementType,
+ const llvm::APInt &NumElements);
+
+ unsigned getNumAddressingBits(const ASTContext &Context) const;
+
+ /// Determine the maximum number of active bits that an array's size
+ /// can require, which limits the maximum size of the array.
+ static unsigned getMaxSizeBits(const ASTContext &Context);
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
+ Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(),
+ getSizeModifier(), getIndexTypeCVRQualifiers());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
+ QualType ET, uint64_t ArraySize, const Expr *SizeExpr,
+ ArraySizeModifier SizeMod, unsigned TypeQuals);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantArray ||
+ T->getTypeClass() == ArrayParameter;
+ }
+};
+
+/// Represents a constant array type that does not decay to a pointer when used
+/// as a function parameter.
+class ArrayParameterType : public ConstantArrayType {
+ friend class ASTContext; // ASTContext creates these.
+
+ ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy)
+ : ConstantArrayType(ArrayParameter, ATy, CanTy) {}
+
+public:
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ArrayParameter;
+ }
+
+ QualType getConstantArrayType(const ASTContext &Ctx) const;
+};
+
+/// Represents a C array with an unspecified size. For example 'int A[]' has
+/// an IncompleteArrayType where the element type is 'int' and the size is
+/// unspecified.
+class IncompleteArrayType : public ArrayType {
+ friend class ASTContext; // ASTContext creates these.
+
+ IncompleteArrayType(QualType et, QualType can,
+ ArraySizeModifier sm, unsigned tq)
+ : ArrayType(IncompleteArray, et, can, sm, tq) {}
+
+public:
+ friend class StmtIteratorBase;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == IncompleteArray;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getSizeModifier(),
+ getIndexTypeCVRQualifiers());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
+ ArraySizeModifier SizeMod, unsigned TypeQuals) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(llvm::to_underlying(SizeMod));
+ ID.AddInteger(TypeQuals);
+ }
+};
+
+/// Represents a C array with a specified size that is not an
+/// integer-constant-expression. For example, 'int s[x+foo()]'.
+/// Since the size expression is an arbitrary expression, we store it as such.
+///
+/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and
+/// should not be: two lexically equivalent variable array types could mean
+/// different things, for example, these variables do not have the same type
+/// dynamically:
+///
+/// void foo(int x) {
+/// int Y[x];
+/// ++x;
+/// int Z[x];
+/// }
+///
+/// FIXME: Even constant array types might be represented by a
+/// VariableArrayType, as in:
+///
+/// void func(int n) {
+/// int array[7][n];
+/// }
+///
+/// Even though 'array' is a constant-size array of seven elements of type
+/// variable-length array of size 'n', it will be represented as a
+/// VariableArrayType whose 'SizeExpr' is an IntegerLiteral whose value is 7.
+/// Instead, this should be a ConstantArrayType whose element is a
+/// VariableArrayType, which models the type better.
+class VariableArrayType : public ArrayType {
+ friend class ASTContext; // ASTContext creates these.
+
+ /// An assignment-expression. VLA's are only permitted within
+ /// a function block.
+ Stmt *SizeExpr;
+
+ VariableArrayType(QualType et, QualType can, Expr *e, ArraySizeModifier sm,
+ unsigned tq)
+ : ArrayType(VariableArray, et, can, sm, tq, e), SizeExpr((Stmt *)e) {}
+
+public:
+ friend class StmtIteratorBase;
+
+ Expr *getSizeExpr() const {
+ // We use C-style casts instead of cast<> here because we do not wish
+ // to have a dependency of Type.h on Stmt.h/Expr.h.
+ return (Expr*) SizeExpr;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == VariableArray;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ llvm_unreachable("Cannot unique VariableArrayTypes.");
+ }
+};
+
+/// Represents an array type in C++ whose size is a value-dependent expression.
+///
+/// For example:
+/// \code
+/// template<typename T, int Size>
+/// class array {
+/// T data[Size];
+/// };
+/// \endcode
+///
+/// For these types, we won't actually know what the array bound is
+/// until template instantiation occurs, at which point this will
+/// become either a ConstantArrayType or a VariableArrayType.
+class DependentSizedArrayType : public ArrayType {
+ friend class ASTContext; // ASTContext creates these.
+
+ /// An assignment expression that will instantiate to the
+ /// size of the array.
+ ///
+ /// The expression itself might be null, in which case the array
+ /// type will have its size deduced from an initializer.
+ Stmt *SizeExpr;
+
+ DependentSizedArrayType(QualType et, QualType can, Expr *e,
+ ArraySizeModifier sm, unsigned tq);
+
+public:
+ friend class StmtIteratorBase;
+
+ Expr *getSizeExpr() const {
+ // We use C-style casts instead of cast<> here because we do not wish
+ // to have a dependency of Type.h on Stmt.h/Expr.h.
+ return (Expr*) SizeExpr;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentSizedArray;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getElementType(),
+ getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType ET, ArraySizeModifier SizeMod,
+ unsigned TypeQuals, Expr *E);
+};
+
+/// Represents an extended address space qualifier where the input address space
+/// value is dependent. Non-dependent address spaces are not represented with a
+/// special Type subclass; they are stored on an ExtQuals node as part of a QualType.
+///
+/// For example:
+/// \code
+/// template<typename T, int AddrSpace>
+/// class AddressSpace {
+/// typedef T __attribute__((address_space(AddrSpace))) type;
+/// }
+/// \endcode
+class DependentAddressSpaceType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ Expr *AddrSpaceExpr;
+ QualType PointeeType;
+ SourceLocation loc;
+
+ DependentAddressSpaceType(QualType PointeeType, QualType can,
+ Expr *AddrSpaceExpr, SourceLocation loc);
+
+public:
+ Expr *getAddrSpaceExpr() const { return AddrSpaceExpr; }
+ QualType getPointeeType() const { return PointeeType; }
+ SourceLocation getAttributeLoc() const { return loc; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentAddressSpace;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getPointeeType(), getAddrSpaceExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType PointeeType, Expr *AddrSpaceExpr);
+};
+
+/// Represents an extended vector type where either the type or size is
+/// dependent.
+///
+/// For example:
+/// \code
+/// template<typename T, int Size>
+/// class vector {
+/// typedef T __attribute__((ext_vector_type(Size))) type;
+/// }
+/// \endcode
+class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ Expr *SizeExpr;
+
+ /// The element type of the array.
+ QualType ElementType;
+
+ SourceLocation loc;
+
+ DependentSizedExtVectorType(QualType ElementType, QualType can,
+ Expr *SizeExpr, SourceLocation loc);
+
+public:
+ Expr *getSizeExpr() const { return SizeExpr; }
+ QualType getElementType() const { return ElementType; }
+ SourceLocation getAttributeLoc() const { return loc; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentSizedExtVector;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getElementType(), getSizeExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType ElementType, Expr *SizeExpr);
+};
+
+enum class VectorKind {
+ /// not a target-specific vector type
+ Generic,
+
+ /// is AltiVec vector
+ AltiVecVector,
+
+ /// is AltiVec 'vector Pixel'
+ AltiVecPixel,
+
+ /// is AltiVec 'vector bool ...'
+ AltiVecBool,
+
+ /// is ARM Neon vector
+ Neon,
+
+ /// is ARM Neon polynomial vector
+ NeonPoly,
+
+ /// is AArch64 SVE fixed-length data vector
+ SveFixedLengthData,
+
+ /// is AArch64 SVE fixed-length predicate vector
+ SveFixedLengthPredicate,
+
+ /// is RISC-V RVV fixed-length data vector
+ RVVFixedLengthData,
+
+ /// is RISC-V RVV fixed-length mask vector
+ RVVFixedLengthMask,
+
+ RVVFixedLengthMask_1,
+ RVVFixedLengthMask_2,
+ RVVFixedLengthMask_4
+};
+
+/// Represents a GCC generic vector type. This type is created using
+/// __attribute__((vector_size(n)), where "n" specifies the vector size in
+/// bytes; or from an Altivec __vector or vector declaration.
+/// Since the constructor takes the number of vector elements, the
+/// client is responsible for converting the size into the number of elements.
+class VectorType : public Type, public llvm::FoldingSetNode {
+protected:
+ friend class ASTContext; // ASTContext creates these.
+
+ /// The element type of the vector.
+ QualType ElementType;
+
+ VectorType(QualType vecType, unsigned nElements, QualType canonType,
+ VectorKind vecKind);
+
+ VectorType(TypeClass tc, QualType vecType, unsigned nElements,
+ QualType canonType, VectorKind vecKind);
+
+public:
+ QualType getElementType() const { return ElementType; }
+ unsigned getNumElements() const { return VectorTypeBits.NumElements; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ VectorKind getVectorKind() const {
+ return VectorKind(VectorTypeBits.VecKind);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getNumElements(),
+ getTypeClass(), getVectorKind());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
+ unsigned NumElements, TypeClass TypeClass,
+ VectorKind VecKind) {
+ ID.AddPointer(ElementType.getAsOpaquePtr());
+ ID.AddInteger(NumElements);
+ ID.AddInteger(TypeClass);
+ ID.AddInteger(llvm::to_underlying(VecKind));
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector;
+ }
+};
+
+/// Represents a vector type where either the type or size is dependent.
+////
+/// For example:
+/// \code
+/// template<typename T, int Size>
+/// class vector {
+/// typedef T __attribute__((vector_size(Size))) type;
+/// }
+/// \endcode
+class DependentVectorType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ QualType ElementType;
+ Expr *SizeExpr;
+ SourceLocation Loc;
+
+ DependentVectorType(QualType ElementType, QualType CanonType, Expr *SizeExpr,
+ SourceLocation Loc, VectorKind vecKind);
+
+public:
+ Expr *getSizeExpr() const { return SizeExpr; }
+ QualType getElementType() const { return ElementType; }
+ SourceLocation getAttributeLoc() const { return Loc; }
+ VectorKind getVectorKind() const {
+ return VectorKind(VectorTypeBits.VecKind);
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentVector;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getElementType(), getSizeExpr(), getVectorKind());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType ElementType, const Expr *SizeExpr,
+ VectorKind VecKind);
+};
+
+/// ExtVectorType - Extended vector type. This type is created using
+/// __attribute__((ext_vector_type(n)), where "n" is the number of elements.
+/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This
+/// class enables syntactic extensions, like Vector Components for accessing
+/// points (as .xyzw), colors (as .rgba), and textures (modeled after OpenGL
+/// Shading Language).
+class ExtVectorType : public VectorType {
+ friend class ASTContext; // ASTContext creates these.
+
+ ExtVectorType(QualType vecType, unsigned nElements, QualType canonType)
+ : VectorType(ExtVector, vecType, nElements, canonType,
+ VectorKind::Generic) {}
+
+public:
+ static int getPointAccessorIdx(char c) {
+ switch (c) {
+ default: return -1;
+ case 'x': case 'r': return 0;
+ case 'y': case 'g': return 1;
+ case 'z': case 'b': return 2;
+ case 'w': case 'a': return 3;
+ }
+ }
+
+ static int getNumericAccessorIdx(char c) {
+ switch (c) {
+ default: return -1;
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'A':
+ case 'a': return 10;
+ case 'B':
+ case 'b': return 11;
+ case 'C':
+ case 'c': return 12;
+ case 'D':
+ case 'd': return 13;
+ case 'E':
+ case 'e': return 14;
+ case 'F':
+ case 'f': return 15;
+ }
+ }
+
+ static int getAccessorIdx(char c, bool isNumericAccessor) {
+ if (isNumericAccessor)
+ return getNumericAccessorIdx(c);
+ else
+ return getPointAccessorIdx(c);
+ }
+
+ bool isAccessorWithinNumElements(char c, bool isNumericAccessor) const {
+ if (int idx = getAccessorIdx(c, isNumericAccessor)+1)
+ return unsigned(idx-1) < getNumElements();
+ return false;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ExtVector;
+ }
+};
+
+/// Represents a matrix type, as defined in the Matrix Types clang extensions.
+/// __attribute__((matrix_type(rows, columns))), where "rows" specifies
+/// number of rows and "columns" specifies the number of columns.
+class MatrixType : public Type, public llvm::FoldingSetNode {
+protected:
+ friend class ASTContext;
+
+ /// The element type of the matrix.
+ QualType ElementType;
+
+ MatrixType(QualType ElementTy, QualType CanonElementTy);
+
+ MatrixType(TypeClass TypeClass, QualType ElementTy, QualType CanonElementTy,
+ const Expr *RowExpr = nullptr, const Expr *ColumnExpr = nullptr);
+
+public:
+ /// Returns type of the elements being stored in the matrix
+ QualType getElementType() const { return ElementType; }
+
+ /// Valid elements types are the following:
+ /// * an integer type (as in C23 6.2.5p22), but excluding enumerated types
+ /// and _Bool
+ /// * the standard floating types float or double
+ /// * a half-precision floating point type, if one is supported on the target
+ static bool isValidElementType(QualType T) {
+ return T->isDependentType() ||
+ (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType());
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantMatrix ||
+ T->getTypeClass() == DependentSizedMatrix;
+ }
+};
+
+/// Represents a concrete matrix type with constant number of rows and columns
+class ConstantMatrixType final : public MatrixType {
+protected:
+ friend class ASTContext;
+
+ /// Number of rows and columns.
+ unsigned NumRows;
+ unsigned NumColumns;
+
+ static constexpr unsigned MaxElementsPerDimension = (1 << 20) - 1;
+
+ ConstantMatrixType(QualType MatrixElementType, unsigned NRows,
+ unsigned NColumns, QualType CanonElementType);
+
+ ConstantMatrixType(TypeClass typeClass, QualType MatrixType, unsigned NRows,
+ unsigned NColumns, QualType CanonElementType);
+
+public:
+ /// Returns the number of rows in the matrix.
+ unsigned getNumRows() const { return NumRows; }
+
+ /// Returns the number of columns in the matrix.
+ unsigned getNumColumns() const { return NumColumns; }
+
+ /// Returns the number of elements required to embed the matrix into a vector.
+ unsigned getNumElementsFlattened() const {
+ return getNumRows() * getNumColumns();
+ }
+
+ /// Returns true if \p NumElements is a valid matrix dimension.
+ static constexpr bool isDimensionValid(size_t NumElements) {
+ return NumElements > 0 && NumElements <= MaxElementsPerDimension;
+ }
+
+ /// Returns the maximum number of elements per dimension.
+ static constexpr unsigned getMaxElementsPerDimension() {
+ return MaxElementsPerDimension;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), getNumRows(), getNumColumns(),
+ getTypeClass());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType,
+ unsigned NumRows, unsigned NumColumns,
+ TypeClass TypeClass) {
+ ID.AddPointer(ElementType.getAsOpaquePtr());
+ ID.AddInteger(NumRows);
+ ID.AddInteger(NumColumns);
+ ID.AddInteger(TypeClass);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ConstantMatrix;
+ }
+};
+
+/// Represents a matrix type where the type and the number of rows and columns
+/// is dependent on a template.
+class DependentSizedMatrixType final : public MatrixType {
+ friend class ASTContext;
+
+ Expr *RowExpr;
+ Expr *ColumnExpr;
+
+ SourceLocation loc;
+
+ DependentSizedMatrixType(QualType ElementType, QualType CanonicalType,
+ Expr *RowExpr, Expr *ColumnExpr, SourceLocation loc);
+
+public:
+ Expr *getRowExpr() const { return RowExpr; }
+ Expr *getColumnExpr() const { return ColumnExpr; }
+ SourceLocation getAttributeLoc() const { return loc; }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentSizedMatrix;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getElementType(), getRowExpr(), getColumnExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType ElementType, Expr *RowExpr, Expr *ColumnExpr);
+};
+
+/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base
+/// class of FunctionNoProtoType and FunctionProtoType.
+class FunctionType : public Type {
+ // The type returned by the function.
+ QualType ResultType;
+
+public:
+ /// Interesting information about a specific parameter that can't simply
+ /// be reflected in parameter's type. This is only used by FunctionProtoType
+ /// but is in FunctionType to make this class available during the
+ /// specification of the bases of FunctionProtoType.
+ ///
+ /// It makes sense to model language features this way when there's some
+ /// sort of parameter-specific override (such as an attribute) that
+ /// affects how the function is called. For example, the ARC ns_consumed
+ /// attribute changes whether a parameter is passed at +0 (the default)
+ /// or +1 (ns_consumed). This must be reflected in the function type,
+ /// but isn't really a change to the parameter type.
+ ///
+ /// One serious disadvantage of modelling language features this way is
+ /// that they generally do not work with language features that attempt
+ /// to destructure types. For example, template argument deduction will
+ /// not be able to match a parameter declared as
+ /// T (*)(U)
+ /// against an argument of type
+ /// void (*)(__attribute__((ns_consumed)) id)
+ /// because the substitution of T=void, U=id into the former will
+ /// not produce the latter.
+ class ExtParameterInfo {
+ enum {
+ ABIMask = 0x0F,
+ IsConsumed = 0x10,
+ HasPassObjSize = 0x20,
+ IsNoEscape = 0x40,
+ };
+ unsigned char Data = 0;
+
+ public:
+ ExtParameterInfo() = default;
+
+ /// Return the ABI treatment of this parameter.
+ ParameterABI getABI() const { return ParameterABI(Data & ABIMask); }
+ ExtParameterInfo withABI(ParameterABI kind) const {
+ ExtParameterInfo copy = *this;
+ copy.Data = (copy.Data & ~ABIMask) | unsigned(kind);
+ return copy;
+ }
+
+ /// Is this parameter considered "consumed" by Objective-C ARC?
+ /// Consumed parameters must have retainable object type.
+ bool isConsumed() const { return (Data & IsConsumed); }
+ ExtParameterInfo withIsConsumed(bool consumed) const {
+ ExtParameterInfo copy = *this;
+ if (consumed)
+ copy.Data |= IsConsumed;
+ else
+ copy.Data &= ~IsConsumed;
+ return copy;
+ }
+
+ bool hasPassObjectSize() const { return Data & HasPassObjSize; }
+ ExtParameterInfo withHasPassObjectSize() const {
+ ExtParameterInfo Copy = *this;
+ Copy.Data |= HasPassObjSize;
+ return Copy;
+ }
+
+ bool isNoEscape() const { return Data & IsNoEscape; }
+ ExtParameterInfo withIsNoEscape(bool NoEscape) const {
+ ExtParameterInfo Copy = *this;
+ if (NoEscape)
+ Copy.Data |= IsNoEscape;
+ else
+ Copy.Data &= ~IsNoEscape;
+ return Copy;
+ }
+
+ unsigned char getOpaqueValue() const { return Data; }
+ static ExtParameterInfo getFromOpaqueValue(unsigned char data) {
+ ExtParameterInfo result;
+ result.Data = data;
+ return result;
+ }
+
+ friend bool operator==(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data == rhs.Data;
+ }
+
+ friend bool operator!=(ExtParameterInfo lhs, ExtParameterInfo rhs) {
+ return lhs.Data != rhs.Data;
+ }
+ };
+
+ /// A class which abstracts out some details necessary for
+ /// making a call.
+ ///
+ /// It is not actually used directly for storing this information in
+ /// a FunctionType, although FunctionType does currently use the
+ /// same bit-pattern.
+ ///
+ // If you add a field (say Foo), other than the obvious places (both,
+ // constructors, compile failures), what you need to update is
+ // * Operator==
+ // * getFoo
+ // * withFoo
+ // * functionType. Add Foo, getFoo.
+ // * ASTContext::getFooType
+ // * ASTContext::mergeFunctionTypes
+ // * FunctionNoProtoType::Profile
+ // * FunctionProtoType::Profile
+ // * TypePrinter::PrintFunctionProto
+ // * AST read and write
+ // * Codegen
+ class ExtInfo {
+ friend class FunctionType;
+
+ // Feel free to rearrange or add bits, but if you go over 16, you'll need to
+ // adjust the Bits field below, and if you add bits, you'll need to adjust
+ // Type::FunctionTypeBitfields::ExtInfo as well.
+
+ // | CC |noreturn|produces|nocallersavedregs|regparm|nocfcheck|cmsenscall|
+ // |0 .. 5| 6 | 7 | 8 |9 .. 11| 12 | 13 |
+ //
+ // regparm is either 0 (no regparm attribute) or the regparm value+1.
+ enum { CallConvMask = 0x3F };
+ enum { NoReturnMask = 0x40 };
+ enum { ProducesResultMask = 0x80 };
+ enum { NoCallerSavedRegsMask = 0x100 };
+ enum { RegParmMask = 0xe00, RegParmOffset = 9 };
+ enum { NoCfCheckMask = 0x1000 };
+ enum { CmseNSCallMask = 0x2000 };
+ uint16_t Bits = CC_C;
+
+ ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {}
+
+ public:
+ // Constructor with no defaults. Use this when you know that you
+ // have all the elements (when reading an AST file for example).
+ ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc,
+ bool producesResult, bool noCallerSavedRegs, bool NoCfCheck,
+ bool cmseNSCall) {
+ assert((!hasRegParm || regParm < 7) && "Invalid regparm value");
+ Bits = ((unsigned)cc) | (noReturn ? NoReturnMask : 0) |
+ (producesResult ? ProducesResultMask : 0) |
+ (noCallerSavedRegs ? NoCallerSavedRegsMask : 0) |
+ (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0) |
+ (NoCfCheck ? NoCfCheckMask : 0) |
+ (cmseNSCall ? CmseNSCallMask : 0);
+ }
+
+ // Constructor with all defaults. Use when for example creating a
+ // function known to use defaults.
+ ExtInfo() = default;
+
+ // Constructor with just the calling convention, which is an important part
+ // of the canonical type.
+ ExtInfo(CallingConv CC) : Bits(CC) {}
+
+ bool getNoReturn() const { return Bits & NoReturnMask; }
+ bool getProducesResult() const { return Bits & ProducesResultMask; }
+ bool getCmseNSCall() const { return Bits & CmseNSCallMask; }
+ bool getNoCallerSavedRegs() const { return Bits & NoCallerSavedRegsMask; }
+ bool getNoCfCheck() const { return Bits & NoCfCheckMask; }
+ bool getHasRegParm() const { return ((Bits & RegParmMask) >> RegParmOffset) != 0; }
+
+ unsigned getRegParm() const {
+ unsigned RegParm = (Bits & RegParmMask) >> RegParmOffset;
+ if (RegParm > 0)
+ --RegParm;
+ return RegParm;
+ }
+
+ CallingConv getCC() const { return CallingConv(Bits & CallConvMask); }
+
+ bool operator==(ExtInfo Other) const {
+ return Bits == Other.Bits;
+ }
+ bool operator!=(ExtInfo Other) const {
+ return Bits != Other.Bits;
+ }
+
+ // Note that we don't have setters. That is by design, use
+ // the following with methods instead of mutating these objects.
+
+ ExtInfo withNoReturn(bool noReturn) const {
+ if (noReturn)
+ return ExtInfo(Bits | NoReturnMask);
+ else
+ return ExtInfo(Bits & ~NoReturnMask);
+ }
+
+ ExtInfo withProducesResult(bool producesResult) const {
+ if (producesResult)
+ return ExtInfo(Bits | ProducesResultMask);
+ else
+ return ExtInfo(Bits & ~ProducesResultMask);
+ }
+
+ ExtInfo withCmseNSCall(bool cmseNSCall) const {
+ if (cmseNSCall)
+ return ExtInfo(Bits | CmseNSCallMask);
+ else
+ return ExtInfo(Bits & ~CmseNSCallMask);
+ }
+
+ ExtInfo withNoCallerSavedRegs(bool noCallerSavedRegs) const {
+ if (noCallerSavedRegs)
+ return ExtInfo(Bits | NoCallerSavedRegsMask);
+ else
+ return ExtInfo(Bits & ~NoCallerSavedRegsMask);
+ }
+
+ ExtInfo withNoCfCheck(bool noCfCheck) const {
+ if (noCfCheck)
+ return ExtInfo(Bits | NoCfCheckMask);
+ else
+ return ExtInfo(Bits & ~NoCfCheckMask);
+ }
+
+ ExtInfo withRegParm(unsigned RegParm) const {
+ assert(RegParm < 7 && "Invalid regparm value");
+ return ExtInfo((Bits & ~RegParmMask) |
+ ((RegParm + 1) << RegParmOffset));
+ }
+
+ ExtInfo withCallingConv(CallingConv cc) const {
+ return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Bits);
+ }
+ };
+
+ /// A simple holder for a QualType representing a type in an
+ /// exception specification. Unfortunately needed by FunctionProtoType
+ /// because TrailingObjects cannot handle repeated types.
+ struct ExceptionType { QualType Type; };
+
+ /// A simple holder for various uncommon bits which do not fit in
+ /// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
+ /// alignment of subsequent objects in TrailingObjects.
+ struct alignas(void *) FunctionTypeExtraBitfields {
+ /// The number of types in the exception specification.
+ /// A whole unsigned is not needed here and according to
+ /// [implimits] 8 bits would be enough here.
+ unsigned NumExceptionType : 10;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasExtraAttributeInfo : 1;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasArmTypeAttributes : 1;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned EffectsHaveConditions : 1;
+ unsigned NumFunctionEffects : 4;
+
+ FunctionTypeExtraBitfields()
+ : NumExceptionType(0), HasExtraAttributeInfo(false),
+ HasArmTypeAttributes(false), EffectsHaveConditions(false),
+ NumFunctionEffects(0) {}
+ };
+
+ /// A holder for extra information from attributes which aren't part of an
+ /// \p AttributedType.
+ struct alignas(void *) FunctionTypeExtraAttributeInfo {
+ /// A CFI "salt" that differentiates functions with the same prototype.
+ StringRef CFISalt;
+
+ operator bool() const { return !CFISalt.empty(); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddString(CFISalt); }
+ };
+
+ /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number
+ /// of function type attributes that can be set on function types, including
+ /// function pointers.
+ enum AArch64SMETypeAttributes : uint16_t {
+ SME_NormalFunction = 0,
+ SME_PStateSMEnabledMask = 1 << 0,
+ SME_PStateSMCompatibleMask = 1 << 1,
+
+ // Describes the value of the state using ArmStateValue.
+ SME_ZAShift = 2,
+ SME_ZAMask = 0b111 << SME_ZAShift,
+ SME_ZT0Shift = 5,
+ SME_ZT0Mask = 0b111 << SME_ZT0Shift,
+
+ // A bit to tell whether a function is agnostic about sme ZA state.
+ SME_AgnosticZAStateShift = 8,
+ SME_AgnosticZAStateMask = 1 << SME_AgnosticZAStateShift,
+
+ SME_AttributeMask =
+ 0b1'111'111'11 // We can't support more than 9 bits because of
+ // the bitmask in FunctionTypeArmAttributes
+ // and ExtProtoInfo.
+ };
+
+ enum ArmStateValue : unsigned {
+ ARM_None = 0,
+ ARM_Preserves = 1,
+ ARM_In = 2,
+ ARM_Out = 3,
+ ARM_InOut = 4,
+ };
+
+ static ArmStateValue getArmZAState(unsigned AttrBits) {
+ return static_cast<ArmStateValue>((AttrBits & SME_ZAMask) >> SME_ZAShift);
+ }
+
+ static ArmStateValue getArmZT0State(unsigned AttrBits) {
+ return static_cast<ArmStateValue>((AttrBits & SME_ZT0Mask) >> SME_ZT0Shift);
+ }
+
+ /// A holder for Arm type attributes as described in the Arm C/C++
+ /// Language extensions which are not particularly common to all
+ /// types and therefore accounted separately from FunctionTypeBitfields.
+ struct alignas(void *) FunctionTypeArmAttributes {
+ /// Any AArch64 SME ACLE type attributes that need to be propagated
+ /// on declarations and function pointers.
+ LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes)
+ unsigned AArch64SMEAttributes : 9;
+
+ FunctionTypeArmAttributes() : AArch64SMEAttributes(SME_NormalFunction) {}
+ };
+
+protected:
+ FunctionType(TypeClass tc, QualType res, QualType Canonical,
+ TypeDependence Dependence, ExtInfo Info)
+ : Type(tc, Canonical, Dependence), ResultType(res) {
+ FunctionTypeBits.ExtInfo = Info.Bits;
+ }
+
+ Qualifiers getFastTypeQuals() const {
+ if (isFunctionProtoType())
+ return Qualifiers::fromFastMask(FunctionTypeBits.FastTypeQuals);
+
+ return Qualifiers();
+ }
+
+public:
+ QualType getReturnType() const { return ResultType; }
+
+ bool getHasRegParm() const { return getExtInfo().getHasRegParm(); }
+ unsigned getRegParmType() const { return getExtInfo().getRegParm(); }
+
+ /// Determine whether this function type includes the GNU noreturn
+ /// attribute. The C++11 [[noreturn]] attribute does not affect the function
+ /// type.
+ bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); }
+
+ /// Determine whether this is a function prototype that includes the
+ /// cfi_unchecked_callee attribute.
+ bool getCFIUncheckedCalleeAttr() const;
+
+ bool getCmseNSCallAttr() const { return getExtInfo().getCmseNSCall(); }
+ CallingConv getCallConv() const { return getExtInfo().getCC(); }
+ ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); }
+
+ static_assert((~Qualifiers::FastMask & Qualifiers::CVRMask) == 0,
+ "Const, volatile and restrict are assumed to be a subset of "
+ "the fast qualifiers.");
+
+ bool isConst() const { return getFastTypeQuals().hasConst(); }
+ bool isVolatile() const { return getFastTypeQuals().hasVolatile(); }
+ bool isRestrict() const { return getFastTypeQuals().hasRestrict(); }
+
+ /// Determine the type of an expression that calls a function of
+ /// this type.
+ QualType getCallResultType(const ASTContext &Context) const {
+ return getReturnType().getNonLValueExprType(Context);
+ }
+
+ static StringRef getNameForCallConv(CallingConv CC);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto ||
+ T->getTypeClass() == FunctionProto;
+ }
+};
+
+/// Represents a K&R-style 'int foo()' function, which has
+/// no information available about its arguments.
+class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
+ : FunctionType(FunctionNoProto, Result, Canonical,
+ Result->getDependence() &
+ ~(TypeDependence::DependentInstantiation |
+ TypeDependence::UnexpandedPack),
+ Info) {}
+
+public:
+ // No additional state past what FunctionType provides.
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getReturnType(), getExtInfo());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType,
+ ExtInfo Info) {
+ Info.Profile(ID);
+ ID.AddPointer(ResultType.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionNoProto;
+ }
+};
+
+// ------------------------------------------------------------------------------
+
+/// Represents an abstract function effect, using just an enumeration describing
+/// its kind.
+class FunctionEffect {
+public:
+ /// Identifies the particular effect.
+ enum class Kind : uint8_t {
+ NonBlocking,
+ NonAllocating,
+ Blocking,
+ Allocating,
+ Last = Allocating
+ };
+ constexpr static size_t KindCount = static_cast<size_t>(Kind::Last) + 1;
+
+ /// Flags describing some behaviors of the effect.
+ using Flags = unsigned;
+ enum FlagBit : Flags {
+ // Can verification inspect callees' implementations? (e.g. nonblocking:
+ // yes, tcb+types: no). This also implies the need for 2nd-pass
+ // verification.
+ FE_InferrableOnCallees = 0x1,
+
+ // Language constructs which effects can diagnose as disallowed.
+ FE_ExcludeThrow = 0x2,
+ FE_ExcludeCatch = 0x4,
+ FE_ExcludeObjCMessageSend = 0x8,
+ FE_ExcludeStaticLocalVars = 0x10,
+ FE_ExcludeThreadLocalVars = 0x20
+ };
+
+private:
+ Kind FKind;
+
+ // Expansion: for hypothetical TCB+types, there could be one Kind for TCB,
+ // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would
+ // be considered for uniqueness.
+
+public:
+ explicit FunctionEffect(Kind K) : FKind(K) {}
+
+ /// The kind of the effect.
+ Kind kind() const { return FKind; }
+
+ /// Return the opposite kind, for effects which have opposites.
+ Kind oppositeKind() const;
+
+ /// For serialization.
+ uint32_t toOpaqueInt32() const { return uint32_t(FKind); }
+ static FunctionEffect fromOpaqueInt32(uint32_t Value) {
+ return FunctionEffect(Kind(Value));
+ }
+
+ /// Flags describing some behaviors of the effect.
+ Flags flags() const {
+ switch (kind()) {
+ case Kind::NonBlocking:
+ return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeStaticLocalVars |
+ FE_ExcludeThreadLocalVars;
+ case Kind::NonAllocating:
+ // Same as NonBlocking, except without FE_ExcludeStaticLocalVars.
+ return FE_InferrableOnCallees | FE_ExcludeThrow | FE_ExcludeCatch |
+ FE_ExcludeObjCMessageSend | FE_ExcludeThreadLocalVars;
+ case Kind::Blocking:
+ case Kind::Allocating:
+ return 0;
+ }
+ llvm_unreachable("unknown effect kind");
+ }
+
+ /// The description printed in diagnostics, e.g. 'nonblocking'.
+ StringRef name() const;
+
+ friend raw_ostream &operator<<(raw_ostream &OS,
+ const FunctionEffect &Effect) {
+ OS << Effect.name();
+ return OS;
+ }
+
+ /// Determine whether the effect is allowed to be inferred on the callee,
+ /// which is either a FunctionDecl or BlockDecl. If the returned optional
+ /// is empty, inference is permitted; otherwise it holds the effect which
+ /// blocked inference.
+ /// Example: This allows nonblocking(false) to prevent inference for the
+ /// function.
+ std::optional<FunctionEffect>
+ effectProhibitingInference(const Decl &Callee,
+ FunctionEffectKindSet CalleeFX) const;
+
+ // Return false for success. When true is returned for a direct call, then the
+ // FE_InferrableOnCallees flag may trigger inference rather than an immediate
+ // diagnostic. Caller should be assumed to have the effect (it may not have it
+ // explicitly when inferring).
+ bool shouldDiagnoseFunctionCall(bool Direct,
+ FunctionEffectKindSet CalleeFX) const;
+
+ friend bool operator==(FunctionEffect LHS, FunctionEffect RHS) {
+ return LHS.FKind == RHS.FKind;
+ }
+ friend bool operator!=(FunctionEffect LHS, FunctionEffect RHS) {
+ return !(LHS == RHS);
+ }
+ friend bool operator<(FunctionEffect LHS, FunctionEffect RHS) {
+ return LHS.FKind < RHS.FKind;
+ }
+};
+
+/// Wrap a function effect's condition expression in another struct so
+/// that FunctionProtoType's TrailingObjects can treat it separately.
+class EffectConditionExpr {
+ Expr *Cond = nullptr; // if null, unconditional.
+
+public:
+ EffectConditionExpr() = default;
+ EffectConditionExpr(Expr *E) : Cond(E) {}
+
+ Expr *getCondition() const { return Cond; }
+
+ bool operator==(const EffectConditionExpr &RHS) const {
+ return Cond == RHS.Cond;
+ }
+};
+
+/// A FunctionEffect plus a potential boolean expression determining whether
+/// the effect is declared (e.g. nonblocking(expr)). Generally the condition
+/// expression when present, is dependent.
+struct FunctionEffectWithCondition {
+ FunctionEffect Effect;
+ EffectConditionExpr Cond;
+
+ FunctionEffectWithCondition(FunctionEffect E, const EffectConditionExpr &C)
+ : Effect(E), Cond(C) {}
+
+ /// Return a textual description of the effect, and its condition, if any.
+ std::string description() const;
+
+ friend raw_ostream &operator<<(raw_ostream &OS,
+ const FunctionEffectWithCondition &CFE);
+};
+
+/// Support iteration in parallel through a pair of FunctionEffect and
+/// EffectConditionExpr containers.
+template <typename Container> class FunctionEffectIterator {
+ friend Container;
+
+ const Container *Outer = nullptr;
+ size_t Idx = 0;
+
+public:
+ FunctionEffectIterator();
+ FunctionEffectIterator(const Container &O, size_t I) : Outer(&O), Idx(I) {}
+ bool operator==(const FunctionEffectIterator &Other) const {
+ return Idx == Other.Idx;
+ }
+ bool operator!=(const FunctionEffectIterator &Other) const {
+ return Idx != Other.Idx;
+ }
+
+ FunctionEffectIterator operator++() {
+ ++Idx;
+ return *this;
+ }
+
+ FunctionEffectWithCondition operator*() const {
+ assert(Outer != nullptr && "invalid FunctionEffectIterator");
+ bool HasConds = !Outer->Conditions.empty();
+ return FunctionEffectWithCondition{Outer->Effects[Idx],
+ HasConds ? Outer->Conditions[Idx]
+ : EffectConditionExpr()};
+ }
+};
+
+/// An immutable set of FunctionEffects and possibly conditions attached to
+/// them. The effects and conditions reside in memory not managed by this object
+/// (typically, trailing objects in FunctionProtoType, or borrowed references
+/// from a FunctionEffectSet).
+///
+/// Invariants:
+/// - there is never more than one instance of any given effect.
+/// - the array of conditions is either empty or has the same size as the
+/// array of effects.
+/// - some conditions may be null expressions; each condition pertains to
+/// the effect at the same array index.
+///
+/// Also, if there are any conditions, at least one of those expressions will be
+/// dependent, but this is only asserted in the constructor of
+/// FunctionProtoType.
+///
+/// See also FunctionEffectSet, in Sema, which provides a mutable set.
+class FunctionEffectsRef {
+ // Restrict classes which can call the private constructor -- these friends
+ // all maintain the required invariants. FunctionEffectSet is generally the
+ // only way in which the arrays are created; FunctionProtoType will not
+ // reorder them.
+ friend FunctionProtoType;
+ friend FunctionEffectSet;
+
+ ArrayRef<FunctionEffect> Effects;
+ ArrayRef<EffectConditionExpr> Conditions;
+
+ // The arrays are expected to have been sorted by the caller, with the
+ // effects in order. The conditions array must be empty or the same size
+ // as the effects array, since the conditions are associated with the effects
+ // at the same array indices.
+ FunctionEffectsRef(ArrayRef<FunctionEffect> FX,
+ ArrayRef<EffectConditionExpr> Conds)
+ : Effects(FX), Conditions(Conds) {}
+
+public:
+ /// Extract the effects from a Type if it is a function, block, or member
+ /// function pointer, or a reference or pointer to one.
+ static FunctionEffectsRef get(QualType QT);
+
+ /// Asserts invariants.
+ static FunctionEffectsRef create(ArrayRef<FunctionEffect> FX,
+ ArrayRef<EffectConditionExpr> Conds);
+
+ FunctionEffectsRef() = default;
+
+ bool empty() const { return Effects.empty(); }
+ size_t size() const { return Effects.size(); }
+
+ ArrayRef<FunctionEffect> effects() const { return Effects; }
+ ArrayRef<EffectConditionExpr> conditions() const { return Conditions; }
+
+ using iterator = FunctionEffectIterator<FunctionEffectsRef>;
+ friend iterator;
+ iterator begin() const { return iterator(*this, 0); }
+ iterator end() const { return iterator(*this, size()); }
+
+ friend bool operator==(const FunctionEffectsRef &LHS,
+ const FunctionEffectsRef &RHS) {
+ return LHS.Effects == RHS.Effects && LHS.Conditions == RHS.Conditions;
+ }
+ friend bool operator!=(const FunctionEffectsRef &LHS,
+ const FunctionEffectsRef &RHS) {
+ return !(LHS == RHS);
+ }
+
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+/// A mutable set of FunctionEffect::Kind.
+class FunctionEffectKindSet {
+ // For now this only needs to be a bitmap.
+ constexpr static size_t EndBitPos = FunctionEffect::KindCount;
+ using KindBitsT = std::bitset<EndBitPos>;
+
+ KindBitsT KindBits{};
+
+ explicit FunctionEffectKindSet(KindBitsT KB) : KindBits(KB) {}
+
+ // Functions to translate between an effect kind, starting at 1, and a
+ // position in the bitset.
+
+ constexpr static size_t kindToPos(FunctionEffect::Kind K) {
+ return static_cast<size_t>(K);
+ }
+
+ constexpr static FunctionEffect::Kind posToKind(size_t Pos) {
+ return static_cast<FunctionEffect::Kind>(Pos);
+ }
+
+ // Iterates through the bits which are set.
+ class iterator {
+ const FunctionEffectKindSet *Outer = nullptr;
+ size_t Idx = 0;
+
+ // If Idx does not reference a set bit, advance it until it does,
+ // or until it reaches EndBitPos.
+ void advanceToNextSetBit() {
+ while (Idx < EndBitPos && !Outer->KindBits.test(Idx))
+ ++Idx;
+ }
+
+ public:
+ iterator();
+ iterator(const FunctionEffectKindSet &O, size_t I) : Outer(&O), Idx(I) {
+ advanceToNextSetBit();
+ }
+ bool operator==(const iterator &Other) const { return Idx == Other.Idx; }
+ bool operator!=(const iterator &Other) const { return Idx != Other.Idx; }
+
+ iterator operator++() {
+ ++Idx;
+ advanceToNextSetBit();
+ return *this;
+ }
+
+ FunctionEffect operator*() const {
+ assert(Idx < EndBitPos && "Dereference of end iterator");
+ return FunctionEffect(posToKind(Idx));
+ }
+ };
+
+public:
+ FunctionEffectKindSet() = default;
+ explicit FunctionEffectKindSet(FunctionEffectsRef FX) { insert(FX); }
+
+ iterator begin() const { return iterator(*this, 0); }
+ iterator end() const { return iterator(*this, EndBitPos); }
+
+ void insert(FunctionEffect Effect) { KindBits.set(kindToPos(Effect.kind())); }
+ void insert(FunctionEffectsRef FX) {
+ for (FunctionEffect Item : FX.effects())
+ insert(Item);
+ }
+ void insert(FunctionEffectKindSet Set) { KindBits |= Set.KindBits; }
+
+ bool empty() const { return KindBits.none(); }
+ bool contains(const FunctionEffect::Kind EK) const {
+ return KindBits.test(kindToPos(EK));
+ }
+ void dump(llvm::raw_ostream &OS) const;
+
+ static FunctionEffectKindSet difference(FunctionEffectKindSet LHS,
+ FunctionEffectKindSet RHS) {
+ return FunctionEffectKindSet(LHS.KindBits & ~RHS.KindBits);
+ }
+};
+
+/// A mutable set of FunctionEffects and possibly conditions attached to them.
+/// Used to compare and merge effects on declarations.
+///
+/// Has the same invariants as FunctionEffectsRef.
+class FunctionEffectSet {
+ SmallVector<FunctionEffect> Effects;
+ SmallVector<EffectConditionExpr> Conditions;
+
+public:
+ FunctionEffectSet() = default;
+
+ explicit FunctionEffectSet(const FunctionEffectsRef &FX)
+ : Effects(FX.effects()), Conditions(FX.conditions()) {}
+
+ bool empty() const { return Effects.empty(); }
+ size_t size() const { return Effects.size(); }
+
+ using iterator = FunctionEffectIterator<FunctionEffectSet>;
+ friend iterator;
+ iterator begin() const { return iterator(*this, 0); }
+ iterator end() const { return iterator(*this, size()); }
+
+ operator FunctionEffectsRef() const { return {Effects, Conditions}; }
+
+ void dump(llvm::raw_ostream &OS) const;
+
+ // Mutators
+
+ // On insertion, a conflict occurs when attempting to insert an
+ // effect which is opposite an effect already in the set, or attempting
+ // to insert an effect which is already in the set but with a condition
+ // which is not identical.
+ struct Conflict {
+ FunctionEffectWithCondition Kept;
+ FunctionEffectWithCondition Rejected;
+ };
+ using Conflicts = SmallVector<Conflict>;
+
+ // Returns true for success (obviating a check of Errs.empty()).
+ bool insert(const FunctionEffectWithCondition &NewEC, Conflicts &Errs);
+
+ // Returns true for success (obviating a check of Errs.empty()).
+ bool insert(const FunctionEffectsRef &Set, Conflicts &Errs);
+
+ // Set operations
+
+ static FunctionEffectSet getUnion(FunctionEffectsRef LHS,
+ FunctionEffectsRef RHS, Conflicts &Errs);
+ static FunctionEffectSet getIntersection(FunctionEffectsRef LHS,
+ FunctionEffectsRef RHS);
+};
+
+/// Represents a prototype with parameter type info, e.g.
+/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no
+/// parameters, not as having a single void parameter. Such a type can have
+/// an exception specification, but this specification is not part of the
+/// canonical type. FunctionProtoType has several trailing objects, some of
+/// which optional. For more information about the trailing objects see
+/// the first comment inside FunctionProtoType.
+class FunctionProtoType final
+ : public FunctionType,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<
+ FunctionProtoType, QualType, SourceLocation,
+ FunctionType::FunctionTypeExtraBitfields,
+ FunctionType::FunctionTypeExtraAttributeInfo,
+ FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
+ Expr *, FunctionDecl *, FunctionType::ExtParameterInfo, Qualifiers,
+ FunctionEffect, EffectConditionExpr> {
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
+
+ // FunctionProtoType is followed by several trailing objects, some of
+ // which optional. They are in order:
+ //
+ // * An array of getNumParams() QualType holding the parameter types.
+ // Always present. Note that for the vast majority of FunctionProtoType,
+ // these will be the only trailing objects.
+ //
+ // * Optionally if the function is variadic, the SourceLocation of the
+ // ellipsis.
+ //
+ // * Optionally if some extra data is stored in FunctionTypeExtraBitfields
+ // (see FunctionTypeExtraBitfields and FunctionTypeBitfields):
+ // a single FunctionTypeExtraBitfields. Present if and only if
+ // hasExtraBitfields() is true.
+ //
+ // * Optionally exactly one of:
+ // * an array of getNumExceptions() ExceptionType,
+ // * a single Expr *,
+ // * a pair of FunctionDecl *,
+ // * a single FunctionDecl *
+ // used to store information about the various types of exception
+ // specification. See getExceptionSpecSize for the details.
+ //
+ // * Optionally an array of getNumParams() ExtParameterInfo holding
+ // an ExtParameterInfo for each of the parameters. Present if and
+ // only if hasExtParameterInfos() is true.
+ //
+ // * Optionally a Qualifiers object to represent extra qualifiers that can't
+ // be represented by FunctionTypeBitfields.FastTypeQuals. Present if and
+ // only if hasExtQualifiers() is true.
+ //
+ // * Optionally, an array of getNumFunctionEffects() FunctionEffect.
+ // Present only when getNumFunctionEffects() > 0
+ //
+ // * Optionally, an array of getNumFunctionEffects() EffectConditionExpr.
+ // Present only when getNumFunctionEffectConditions() > 0.
+ //
+ // The optional FunctionTypeExtraBitfields has to be before the data
+ // related to the exception specification since it contains the number
+ // of exception types.
+ //
+ // We put the ExtParameterInfos later. If all were equal, it would make
+ // more sense to put these before the exception specification, because
+ // it's much easier to skip past them compared to the elaborate switch
+ // required to skip the exception specification. However, all is not
+ // equal; ExtParameterInfos are used to model very uncommon features,
+ // and it's better not to burden the more common paths.
+
+public:
+ /// Holds information about the various types of exception specification.
+ /// ExceptionSpecInfo is not stored as such in FunctionProtoType but is
+ /// used to group together the various bits of information about the
+ /// exception specification.
+ struct ExceptionSpecInfo {
+ /// The kind of exception specification this is.
+ ExceptionSpecificationType Type = EST_None;
+
+ /// Explicitly-specified list of exception types.
+ ArrayRef<QualType> Exceptions;
+
+ /// Noexcept expression, if this is a computed noexcept specification.
+ Expr *NoexceptExpr = nullptr;
+
+ /// The function whose exception specification this is, for
+ /// EST_Unevaluated and EST_Uninstantiated.
+ FunctionDecl *SourceDecl = nullptr;
+
+ /// The function template whose exception specification this is instantiated
+ /// from, for EST_Uninstantiated.
+ FunctionDecl *SourceTemplate = nullptr;
+
+ ExceptionSpecInfo() = default;
+
+ ExceptionSpecInfo(ExceptionSpecificationType EST) : Type(EST) {}
+
+ void instantiate();
+ };
+
+ /// Extra information about a function prototype. ExtProtoInfo is not
+ /// stored as such in FunctionProtoType but is used to group together
+ /// the various bits of extra information about a function prototype.
+ struct ExtProtoInfo {
+ FunctionType::ExtInfo ExtInfo;
+ Qualifiers TypeQuals;
+ RefQualifierKind RefQualifier = RQ_None;
+ ExceptionSpecInfo ExceptionSpec;
+ const ExtParameterInfo *ExtParameterInfos = nullptr;
+ SourceLocation EllipsisLoc;
+ FunctionEffectsRef FunctionEffects;
+ FunctionTypeExtraAttributeInfo ExtraAttributeInfo;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Variadic : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned HasTrailingReturn : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned CFIUncheckedCallee : 1;
+ LLVM_PREFERRED_TYPE(AArch64SMETypeAttributes)
+ unsigned AArch64SMEAttributes : 9;
+
+ ExtProtoInfo()
+ : Variadic(false), HasTrailingReturn(false), CFIUncheckedCallee(false),
+ AArch64SMEAttributes(SME_NormalFunction) {}
+
+ ExtProtoInfo(CallingConv CC)
+ : ExtInfo(CC), Variadic(false), HasTrailingReturn(false),
+ CFIUncheckedCallee(false), AArch64SMEAttributes(SME_NormalFunction) {}
+
+ ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
+ ExtProtoInfo Result(*this);
+ Result.ExceptionSpec = ESI;
+ return Result;
+ }
+
+ ExtProtoInfo withCFIUncheckedCallee(bool CFIUncheckedCallee) {
+ ExtProtoInfo Result(*this);
+ Result.CFIUncheckedCallee = CFIUncheckedCallee;
+ return Result;
+ }
+
+ bool requiresFunctionProtoTypeExtraBitfields() const {
+ return ExceptionSpec.Type == EST_Dynamic ||
+ requiresFunctionProtoTypeArmAttributes() ||
+ requiresFunctionProtoTypeExtraAttributeInfo() ||
+ !FunctionEffects.empty();
+ }
+
+ bool requiresFunctionProtoTypeArmAttributes() const {
+ return AArch64SMEAttributes != SME_NormalFunction;
+ }
+
+ bool requiresFunctionProtoTypeExtraAttributeInfo() const {
+ return static_cast<bool>(ExtraAttributeInfo);
+ }
+
+ void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) {
+ if (Enable)
+ AArch64SMEAttributes |= Kind;
+ else
+ AArch64SMEAttributes &= ~Kind;
+ }
+ };
+
+private:
+ unsigned numTrailingObjects(OverloadToken<QualType>) const {
+ return getNumParams();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+ return isVariadic();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionTypeArmAttributes>) const {
+ return hasArmTypeAttributes();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionTypeExtraBitfields>) const {
+ return hasExtraBitfields();
+ }
+
+ unsigned
+ numTrailingObjects(OverloadToken<FunctionTypeExtraAttributeInfo>) const {
+ return hasExtraAttributeInfo();
+ }
+
+ unsigned numTrailingObjects(OverloadToken<ExceptionType>) const {
+ return getExceptionSpecSize().NumExceptionType;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<Expr *>) const {
+ return getExceptionSpecSize().NumExprPtr;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionDecl *>) const {
+ return getExceptionSpecSize().NumFunctionDeclPtr;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<ExtParameterInfo>) const {
+ return hasExtParameterInfos() ? getNumParams() : 0;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<Qualifiers>) const {
+ return hasExtQualifiers() ? 1 : 0;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<FunctionEffect>) const {
+ return getNumFunctionEffects();
+ }
+
+ /// Determine whether there are any argument types that
+ /// contain an unexpanded parameter pack.
+ static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray,
+ unsigned numArgs) {
+ for (unsigned Idx = 0; Idx < numArgs; ++Idx)
+ if (ArgArray[Idx]->containsUnexpandedParameterPack())
+ return true;
+
+ return false;
+ }
+
+ FunctionProtoType(QualType result, ArrayRef<QualType> params,
+ QualType canonical, const ExtProtoInfo &epi);
+
+ /// This struct is returned by getExceptionSpecSize and is used to
+ /// translate an ExceptionSpecificationType to the number and kind
+ /// of trailing objects related to the exception specification.
+ struct ExceptionSpecSizeHolder {
+ unsigned NumExceptionType;
+ unsigned NumExprPtr;
+ unsigned NumFunctionDeclPtr;
+ };
+
+ /// Return the number and kind of trailing objects
+ /// related to the exception specification.
+ static ExceptionSpecSizeHolder
+ getExceptionSpecSize(ExceptionSpecificationType EST, unsigned NumExceptions) {
+ switch (EST) {
+ case EST_None:
+ case EST_DynamicNone:
+ case EST_MSAny:
+ case EST_BasicNoexcept:
+ case EST_Unparsed:
+ case EST_NoThrow:
+ return {0, 0, 0};
+
+ case EST_Dynamic:
+ return {NumExceptions, 0, 0};
+
+ case EST_DependentNoexcept:
+ case EST_NoexceptFalse:
+ case EST_NoexceptTrue:
+ return {0, 1, 0};
+
+ case EST_Uninstantiated:
+ return {0, 0, 2};
+
+ case EST_Unevaluated:
+ return {0, 0, 1};
+ }
+ llvm_unreachable("bad exception specification kind");
+ }
+
+ /// Return the number and kind of trailing objects
+ /// related to the exception specification.
+ ExceptionSpecSizeHolder getExceptionSpecSize() const {
+ return getExceptionSpecSize(getExceptionSpecType(), getNumExceptions());
+ }
+
+ /// Whether the trailing FunctionTypeExtraBitfields is present.
+ bool hasExtraBitfields() const {
+ assert((getExceptionSpecType() != EST_Dynamic ||
+ FunctionTypeBits.HasExtraBitfields) &&
+ "ExtraBitfields are required for given ExceptionSpecType");
+ return FunctionTypeBits.HasExtraBitfields;
+
+ }
+
+ bool hasExtraAttributeInfo() const {
+ return FunctionTypeBits.HasExtraBitfields &&
+ getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->HasExtraAttributeInfo;
+ }
+
+ bool hasArmTypeAttributes() const {
+ return FunctionTypeBits.HasExtraBitfields &&
+ getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->HasArmTypeAttributes;
+ }
+
+ bool hasExtQualifiers() const {
+ return FunctionTypeBits.HasExtQuals;
+ }
+
+public:
+ unsigned getNumParams() const { return FunctionTypeBits.NumParams; }
+
+ QualType getParamType(unsigned i) const {
+ assert(i < getNumParams() && "invalid parameter index");
+ return param_type_begin()[i];
+ }
+
+ ArrayRef<QualType> getParamTypes() const {
+ return {param_type_begin(), param_type_end()};
+ }
+
+ ExtProtoInfo getExtProtoInfo() const {
+ ExtProtoInfo EPI;
+ EPI.ExtInfo = getExtInfo();
+ EPI.Variadic = isVariadic();
+ EPI.EllipsisLoc = getEllipsisLoc();
+ EPI.HasTrailingReturn = hasTrailingReturn();
+ EPI.CFIUncheckedCallee = hasCFIUncheckedCallee();
+ EPI.ExceptionSpec = getExceptionSpecInfo();
+ EPI.TypeQuals = getMethodQuals();
+ EPI.RefQualifier = getRefQualifier();
+ EPI.ExtParameterInfos = getExtParameterInfosOrNull();
+ EPI.ExtraAttributeInfo = getExtraAttributeInfo();
+ EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
+ EPI.FunctionEffects = getFunctionEffects();
+ return EPI;
+ }
+
+ /// Get the kind of exception specification on this function.
+ ExceptionSpecificationType getExceptionSpecType() const {
+ return static_cast<ExceptionSpecificationType>(
+ FunctionTypeBits.ExceptionSpecType);
+ }
+
+ /// Return whether this function has any kind of exception spec.
+ bool hasExceptionSpec() const { return getExceptionSpecType() != EST_None; }
+
+ /// Return whether this function has a dynamic (throw) exception spec.
+ bool hasDynamicExceptionSpec() const {
+ return isDynamicExceptionSpec(getExceptionSpecType());
+ }
+
+ /// Return whether this function has a noexcept exception spec.
+ bool hasNoexceptExceptionSpec() const {
+ return isNoexceptExceptionSpec(getExceptionSpecType());
+ }
+
+ /// Return whether this function has a dependent exception spec.
+ bool hasDependentExceptionSpec() const;
+
+ /// Return whether this function has an instantiation-dependent exception
+ /// spec.
+ bool hasInstantiationDependentExceptionSpec() const;
+
+ /// Return all the available information about this type's exception spec.
+ ExceptionSpecInfo getExceptionSpecInfo() const {
+ ExceptionSpecInfo Result;
+ Result.Type = getExceptionSpecType();
+ if (Result.Type == EST_Dynamic) {
+ Result.Exceptions = exceptions();
+ } else if (isComputedNoexcept(Result.Type)) {
+ Result.NoexceptExpr = getNoexceptExpr();
+ } else if (Result.Type == EST_Uninstantiated) {
+ Result.SourceDecl = getExceptionSpecDecl();
+ Result.SourceTemplate = getExceptionSpecTemplate();
+ } else if (Result.Type == EST_Unevaluated) {
+ Result.SourceDecl = getExceptionSpecDecl();
+ }
+ return Result;
+ }
+
+ /// Return the number of types in the exception specification.
+ unsigned getNumExceptions() const {
+ return getExceptionSpecType() == EST_Dynamic
+ ? getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->NumExceptionType
+ : 0;
+ }
+
+ /// Return the ith exception type, where 0 <= i < getNumExceptions().
+ QualType getExceptionType(unsigned i) const {
+ assert(i < getNumExceptions() && "Invalid exception number!");
+ return exception_begin()[i];
+ }
+
+ /// Return the expression inside noexcept(expression), or a null pointer
+ /// if there is none (because the exception spec is not of this form).
+ Expr *getNoexceptExpr() const {
+ if (!isComputedNoexcept(getExceptionSpecType()))
+ return nullptr;
+ return *getTrailingObjects<Expr *>();
+ }
+
+ /// If this function type has an exception specification which hasn't
+ /// been determined yet (either because it has not been evaluated or because
+ /// it has not been instantiated), this is the function whose exception
+ /// specification is represented by this type.
+ FunctionDecl *getExceptionSpecDecl() const {
+ if (getExceptionSpecType() != EST_Uninstantiated &&
+ getExceptionSpecType() != EST_Unevaluated)
+ return nullptr;
+ return getTrailingObjects<FunctionDecl *>()[0];
+ }
+
+ /// If this function type has an uninstantiated exception
+ /// specification, this is the function whose exception specification
+ /// should be instantiated to find the exception specification for
+ /// this type.
+ FunctionDecl *getExceptionSpecTemplate() const {
+ if (getExceptionSpecType() != EST_Uninstantiated)
+ return nullptr;
+ return getTrailingObjects<FunctionDecl *>()[1];
+ }
+
+ /// Determine whether this function type has a non-throwing exception
+ /// specification.
+ CanThrowResult canThrow() const;
+
+ /// Determine whether this function type has a non-throwing exception
+ /// specification. If this depends on template arguments, returns
+ /// \c ResultIfDependent.
+ bool isNothrow(bool ResultIfDependent = false) const {
+ return ResultIfDependent ? canThrow() != CT_Can : canThrow() == CT_Cannot;
+ }
+
+ /// Whether this function prototype is variadic.
+ bool isVariadic() const { return FunctionTypeBits.Variadic; }
+
+ SourceLocation getEllipsisLoc() const {
+ return isVariadic() ? *getTrailingObjects<SourceLocation>()
+ : SourceLocation();
+ }
+
+ /// Determines whether this function prototype contains a
+ /// parameter pack at the end.
+ ///
+ /// A function template whose last parameter is a parameter pack can be
+ /// called with an arbitrary number of arguments, much like a variadic
+ /// function.
+ bool isTemplateVariadic() const;
+
+ /// Whether this function prototype has a trailing return type.
+ bool hasTrailingReturn() const { return FunctionTypeBits.HasTrailingReturn; }
+
+ bool hasCFIUncheckedCallee() const {
+ return FunctionTypeBits.CFIUncheckedCallee;
+ }
+
+ Qualifiers getMethodQuals() const {
+ if (hasExtQualifiers())
+ return *getTrailingObjects<Qualifiers>();
+ else
+ return getFastTypeQuals();
+ }
+
+ /// Retrieve the ref-qualifier associated with this function type.
+ RefQualifierKind getRefQualifier() const {
+ return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
+ }
+
+ using param_type_iterator = const QualType *;
+
+ ArrayRef<QualType> param_types() const {
+ return {param_type_begin(), param_type_end()};
+ }
+
+ param_type_iterator param_type_begin() const {
+ return getTrailingObjects<QualType>();
+ }
+
+ param_type_iterator param_type_end() const {
+ return param_type_begin() + getNumParams();
+ }
+
+ using exception_iterator = const QualType *;
+
+ ArrayRef<QualType> exceptions() const {
+ return {exception_begin(), exception_end()};
+ }
+
+ exception_iterator exception_begin() const {
+ return reinterpret_cast<exception_iterator>(
+ getTrailingObjects<ExceptionType>());
+ }
+
+ exception_iterator exception_end() const {
+ return exception_begin() + getNumExceptions();
+ }
+
+ /// Is there any interesting extra information for any of the parameters
+ /// of this function type?
+ bool hasExtParameterInfos() const {
+ return FunctionTypeBits.HasExtParameterInfos;
+ }
+
+ ArrayRef<ExtParameterInfo> getExtParameterInfos() const {
+ assert(hasExtParameterInfos());
+ return ArrayRef<ExtParameterInfo>(getTrailingObjects<ExtParameterInfo>(),
+ getNumParams());
+ }
+
+ /// Return a pointer to the beginning of the array of extra parameter
+ /// information, if present, or else null if none of the parameters
+ /// carry it. This is equivalent to getExtProtoInfo().ExtParameterInfos.
+ const ExtParameterInfo *getExtParameterInfosOrNull() const {
+ if (!hasExtParameterInfos())
+ return nullptr;
+ return getTrailingObjects<ExtParameterInfo>();
+ }
+
+ /// Return the extra attribute information.
+ FunctionTypeExtraAttributeInfo getExtraAttributeInfo() const {
+ if (hasExtraAttributeInfo())
+ return *getTrailingObjects<FunctionTypeExtraAttributeInfo>();
+ return FunctionTypeExtraAttributeInfo();
+ }
+
+ /// Return a bitmask describing the SME attributes on the function type, see
+ /// AArch64SMETypeAttributes for their values.
+ unsigned getAArch64SMEAttributes() const {
+ if (!hasArmTypeAttributes())
+ return SME_NormalFunction;
+ return getTrailingObjects<FunctionTypeArmAttributes>()
+ ->AArch64SMEAttributes;
+ }
+
+ ExtParameterInfo getExtParameterInfo(unsigned I) const {
+ assert(I < getNumParams() && "parameter index out of range");
+ if (hasExtParameterInfos())
+ return getTrailingObjects<ExtParameterInfo>()[I];
+ return ExtParameterInfo();
+ }
+
+ ParameterABI getParameterABI(unsigned I) const {
+ assert(I < getNumParams() && "parameter index out of range");
+ if (hasExtParameterInfos())
+ return getTrailingObjects<ExtParameterInfo>()[I].getABI();
+ return ParameterABI::Ordinary;
+ }
+
+ bool isParamConsumed(unsigned I) const {
+ assert(I < getNumParams() && "parameter index out of range");
+ if (hasExtParameterInfos())
+ return getTrailingObjects<ExtParameterInfo>()[I].isConsumed();
+ return false;
+ }
+
+ unsigned getNumFunctionEffects() const {
+ return hasExtraBitfields()
+ ? getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->NumFunctionEffects
+ : 0;
+ }
+
+ // For serialization.
+ ArrayRef<FunctionEffect> getFunctionEffectsWithoutConditions() const {
+ if (hasExtraBitfields()) {
+ const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
+ if (Bitfields->NumFunctionEffects > 0)
+ return getTrailingObjects<FunctionEffect>(
+ Bitfields->NumFunctionEffects);
+ }
+ return {};
+ }
+
+ unsigned getNumFunctionEffectConditions() const {
+ if (hasExtraBitfields()) {
+ const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
+ if (Bitfields->EffectsHaveConditions)
+ return Bitfields->NumFunctionEffects;
+ }
+ return 0;
+ }
+
+ // For serialization.
+ ArrayRef<EffectConditionExpr> getFunctionEffectConditions() const {
+ if (hasExtraBitfields()) {
+ const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
+ if (Bitfields->EffectsHaveConditions)
+ return getTrailingObjects<EffectConditionExpr>(
+ Bitfields->NumFunctionEffects);
+ }
+ return {};
+ }
+
+ // Combines effects with their conditions.
+ FunctionEffectsRef getFunctionEffects() const {
+ if (hasExtraBitfields()) {
+ const auto *Bitfields = getTrailingObjects<FunctionTypeExtraBitfields>();
+ if (Bitfields->NumFunctionEffects > 0) {
+ const size_t NumConds = Bitfields->EffectsHaveConditions
+ ? Bitfields->NumFunctionEffects
+ : 0;
+ return FunctionEffectsRef(
+ getTrailingObjects<FunctionEffect>(Bitfields->NumFunctionEffects),
+ {NumConds ? getTrailingObjects<EffectConditionExpr>() : nullptr,
+ NumConds});
+ }
+ }
+ return {};
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void printExceptionSpecification(raw_ostream &OS,
+ const PrintingPolicy &Policy) const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == FunctionProto;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Result,
+ param_type_iterator ArgTys, unsigned NumArgs,
+ const ExtProtoInfo &EPI, const ASTContext &Context,
+ bool Canonical);
+};
+
+/// The elaboration keyword that precedes a qualified type name or
+/// introduces an elaborated-type-specifier.
+enum class ElaboratedTypeKeyword {
+ /// The "struct" keyword introduces the elaborated-type-specifier.
+ Struct,
+
+ /// The "__interface" keyword introduces the elaborated-type-specifier.
+ Interface,
+
+ /// The "union" keyword introduces the elaborated-type-specifier.
+ Union,
+
+ /// The "class" keyword introduces the elaborated-type-specifier.
+ Class,
+
+ /// The "enum" keyword introduces the elaborated-type-specifier.
+ Enum,
+
+ /// The "typename" keyword precedes the qualified type name, e.g.,
+ /// \c typename T::type.
+ Typename,
+
+ /// No keyword precedes the qualified type name.
+ None
+};
+
+/// The kind of a tag type.
+enum class TagTypeKind {
+ /// The "struct" keyword.
+ Struct,
+
+ /// The "__interface" keyword.
+ Interface,
+
+ /// The "union" keyword.
+ Union,
+
+ /// The "class" keyword.
+ Class,
+
+ /// The "enum" keyword.
+ Enum
+};
+
+/// Provides a few static helpers for converting and printing
+/// elaborated type keyword and tag type kind enumerations.
+struct KeywordHelpers {
+ /// Converts a type specifier (DeclSpec::TST) into an elaborated type keyword.
+ static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec);
+
+ /// Converts a type specifier (DeclSpec::TST) into a tag type kind.
+ /// It is an error to provide a type specifier which *isn't* a tag kind here.
+ static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec);
+
+ /// Converts a TagTypeKind into an elaborated type keyword.
+ static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag);
+
+ /// Converts an elaborated type keyword into a TagTypeKind.
+ /// It is an error to provide an elaborated type keyword
+ /// which *isn't* a tag kind here.
+ static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword);
+
+ static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword);
+
+ static StringRef getKeywordName(ElaboratedTypeKeyword Keyword);
+
+ static StringRef getTagTypeKindName(TagTypeKind Kind) {
+ return getKeywordName(getKeywordForTagTypeKind(Kind));
+ }
+};
+
+template <class T> class KeywordWrapper : public T, public KeywordHelpers {
+protected:
+ template <class... As>
+ KeywordWrapper(ElaboratedTypeKeyword Keyword, As &&...as)
+ : T(std::forward<As>(as)...) {
+ this->KeywordWrapperBits.Keyword = llvm::to_underlying(Keyword);
+ }
+
+public:
+ ElaboratedTypeKeyword getKeyword() const {
+ return static_cast<ElaboratedTypeKeyword>(this->KeywordWrapperBits.Keyword);
+ }
+
+ class CannotCastToThisType {};
+ static CannotCastToThisType classof(const T *);
+};
+
+/// A helper class for Type nodes having an ElaboratedTypeKeyword.
+/// The keyword in stored in the free bits of the base class.
+class TypeWithKeyword : public KeywordWrapper<Type> {
+protected:
+ TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc,
+ QualType Canonical, TypeDependence Dependence)
+ : KeywordWrapper(Keyword, tc, Canonical, Dependence) {}
+};
+
+template <class T> struct FoldingSetPlaceholder : llvm::FoldingSetNode {
+ void Profile(llvm::FoldingSetNodeID &ID) { getType()->Profile(ID); }
+
+ inline const T *getType() const {
+ constexpr unsigned long Offset =
+ llvm::alignTo(sizeof(T), alignof(FoldingSetPlaceholder));
+ const auto *Addr = reinterpret_cast<const T *>(
+ reinterpret_cast<const char *>(this) - Offset);
+ assert(llvm::isAddrAligned(llvm::Align(alignof(T)), Addr));
+ return Addr;
+ }
+};
+
+/// Represents the dependent type named by a dependently-scoped
+/// typename using declaration, e.g.
+/// using typename Base<T>::foo;
+///
+/// Template instantiation turns these into the underlying type.
+class UnresolvedUsingType final
+ : public TypeWithKeyword,
+ private llvm::TrailingObjects<UnresolvedUsingType,
+ FoldingSetPlaceholder<UnresolvedUsingType>,
+ NestedNameSpecifier> {
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
+
+ UnresolvedUsingTypenameDecl *Decl;
+
+ unsigned numTrailingObjects(
+ OverloadToken<FoldingSetPlaceholder<UnresolvedUsingType>>) const {
+ assert(UnresolvedUsingBits.hasQualifier ||
+ getKeyword() != ElaboratedTypeKeyword::None);
+ return 1;
+ }
+
+ FoldingSetPlaceholder<UnresolvedUsingType> *getFoldingSetPlaceholder() {
+ assert(numTrailingObjects(
+ OverloadToken<FoldingSetPlaceholder<UnresolvedUsingType>>{}) ==
+ 1);
+ return getTrailingObjects<FoldingSetPlaceholder<UnresolvedUsingType>>();
+ }
+
+ UnresolvedUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D,
+ const Type *CanonicalType);
+
+public:
+ NestedNameSpecifier getQualifier() const {
+ return UnresolvedUsingBits.hasQualifier
+ ? *getTrailingObjects<NestedNameSpecifier>()
+ : std::nullopt;
+ }
+
+ UnresolvedUsingTypenameDecl *getDecl() const { return Decl; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D) {
+ static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7);
+ ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword));
+ if (Qualifier)
+ Qualifier.Profile(ID);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getKeyword(), getQualifier(), getDecl());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == UnresolvedUsing;
+ }
+};
+
+class UsingType final : public TypeWithKeyword,
+ public llvm::FoldingSetNode,
+ llvm::TrailingObjects<UsingType, NestedNameSpecifier> {
+ UsingShadowDecl *D;
+ QualType UnderlyingType;
+
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
+
+ UsingType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
+ const UsingShadowDecl *D, QualType UnderlyingType);
+
+public:
+ NestedNameSpecifier getQualifier() const {
+ return UsingBits.hasQualifier ? *getTrailingObjects() : std::nullopt;
+ }
+
+ UsingShadowDecl *getDecl() const { return D; }
+
+ QualType desugar() const { return UnderlyingType; }
+ bool isSugared() const { return true; }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const UsingShadowDecl *D,
+ QualType UnderlyingType) {
+ static_assert(llvm::to_underlying(ElaboratedTypeKeyword::None) <= 7);
+ ID.AddInteger(uintptr_t(D) | llvm::to_underlying(Keyword));
+ UnderlyingType.Profile(ID);
+ if (Qualifier)
+ Qualifier.Profile(ID);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getKeyword(), getQualifier(), D, desugar());
+ }
+ static bool classof(const Type *T) { return T->getTypeClass() == Using; }
+};
+
+class TypedefType final
+ : public TypeWithKeyword,
+ private llvm::TrailingObjects<TypedefType,
+ FoldingSetPlaceholder<TypedefType>,
+ NestedNameSpecifier, QualType> {
+ TypedefNameDecl *Decl;
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
+
+ unsigned
+ numTrailingObjects(OverloadToken<FoldingSetPlaceholder<TypedefType>>) const {
+ assert(TypedefBits.hasQualifier || TypedefBits.hasTypeDifferentFromDecl ||
+ getKeyword() != ElaboratedTypeKeyword::None);
+ return 1;
+ }
+
+ unsigned numTrailingObjects(OverloadToken<NestedNameSpecifier>) const {
+ return TypedefBits.hasQualifier;
+ }
+
+ TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TypedefNameDecl *D,
+ QualType UnderlyingType, bool HasTypeDifferentFromDecl);
+
+ FoldingSetPlaceholder<TypedefType> *getFoldingSetPlaceholder() {
+ assert(numTrailingObjects(
+ OverloadToken<FoldingSetPlaceholder<TypedefType>>{}) == 1);
+ return getTrailingObjects<FoldingSetPlaceholder<TypedefType>>();
+ }
+
+public:
+ NestedNameSpecifier getQualifier() const {
+ return TypedefBits.hasQualifier ? *getTrailingObjects<NestedNameSpecifier>()
+ : std::nullopt;
+ }
+
+ TypedefNameDecl *getDecl() const { return Decl; }
+
+ bool isSugared() const { return true; }
+
+ // This always has the 'same' type as declared, but not necessarily identical.
+ QualType desugar() const;
+
+ // Internal helper, for debugging purposes.
+ bool typeMatchesDecl() const { return !TypedefBits.hasTypeDifferentFromDecl; }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TypedefNameDecl *Decl, QualType Underlying) {
+
+ ID.AddInteger(uintptr_t(Decl) | (Keyword != ElaboratedTypeKeyword::None) |
+ (!Qualifier << 1));
+ if (Keyword != ElaboratedTypeKeyword::None)
+ ID.AddInteger(llvm::to_underlying(Keyword));
+ if (Qualifier)
+ Qualifier.Profile(ID);
+ if (!Underlying.isNull())
+ Underlying.Profile(ID);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getKeyword(), getQualifier(), getDecl(),
+ typeMatchesDecl() ? QualType() : desugar());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
+};
+
+/// Sugar type that represents a type that was qualified by a qualifier written
+/// as a macro invocation.
+class MacroQualifiedType : public Type {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType UnderlyingTy;
+ const IdentifierInfo *MacroII;
+
+ MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy,
+ const IdentifierInfo *MacroII)
+ : Type(MacroQualified, CanonTy, UnderlyingTy->getDependence()),
+ UnderlyingTy(UnderlyingTy), MacroII(MacroII) {
+ assert(isa<AttributedType>(UnderlyingTy) &&
+ "Expected a macro qualified type to only wrap attributed types.");
+ }
+
+public:
+ const IdentifierInfo *getMacroIdentifier() const { return MacroII; }
+ QualType getUnderlyingType() const { return UnderlyingTy; }
+
+ /// Return this attributed type's modified type with no qualifiers attached to
+ /// it.
+ QualType getModifiedType() const;
+
+ bool isSugared() const { return true; }
+ QualType desugar() const;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == MacroQualified;
+ }
+};
+
+/// Represents a `typeof` (or __typeof__) expression (a C23 feature and GCC
+/// extension) or a `typeof_unqual` expression (a C23 feature).
+class TypeOfExprType : public Type {
+ Expr *TOExpr;
+ const ASTContext &Context;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+
+ TypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind,
+ QualType Can = QualType());
+
+public:
+ Expr *getUnderlyingExpr() const { return TOExpr; }
+
+ /// Returns the kind of 'typeof' type this is.
+ TypeOfKind getKind() const {
+ return static_cast<TypeOfKind>(TypeOfBits.Kind);
+ }
+
+ /// Remove a single level of sugar.
+ QualType desugar() const;
+
+ /// Returns whether this type directly provides sugar.
+ bool isSugared() const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; }
+};
+
+/// Internal representation of canonical, dependent
+/// `typeof(expr)` types.
+///
+/// This class is used internally by the ASTContext to manage
+/// canonical, dependent types, only. Clients will only see instances
+/// of this class via TypeOfExprType nodes.
+class DependentTypeOfExprType : public TypeOfExprType,
+ public llvm::FoldingSetNode {
+public:
+ DependentTypeOfExprType(const ASTContext &Context, Expr *E, TypeOfKind Kind)
+ : TypeOfExprType(Context, E, Kind) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getUnderlyingExpr(),
+ getKind() == TypeOfKind::Unqualified);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ Expr *E, bool IsUnqual);
+};
+
+/// Represents `typeof(type)`, a C23 feature and GCC extension, or
+/// `typeof_unqual(type), a C23 feature.
+class TypeOfType : public Type {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType TOType;
+ const ASTContext &Context;
+
+ TypeOfType(const ASTContext &Context, QualType T, QualType Can,
+ TypeOfKind Kind);
+
+public:
+ QualType getUnmodifiedType() const { return TOType; }
+
+ /// Remove a single level of sugar.
+ QualType desugar() const;
+
+ /// Returns whether this type directly provides sugar.
+ bool isSugared() const { return true; }
+
+ /// Returns the kind of 'typeof' type this is.
+ TypeOfKind getKind() const {
+ return static_cast<TypeOfKind>(TypeOfBits.Kind);
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; }
+};
+
+/// Represents the type `decltype(expr)` (C++11).
+class DecltypeType : public Type {
+ Expr *E;
+ QualType UnderlyingType;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+
+ DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType());
+
+public:
+ Expr *getUnderlyingExpr() const { return E; }
+ QualType getUnderlyingType() const { return UnderlyingType; }
+
+ /// Remove a single level of sugar.
+ QualType desugar() const;
+
+ /// Returns whether this type directly provides sugar.
+ bool isSugared() const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Decltype; }
+};
+
+/// Internal representation of canonical, dependent
+/// decltype(expr) types.
+///
+/// This class is used internally by the ASTContext to manage
+/// canonical, dependent types, only. Clients will only see instances
+/// of this class via DecltypeType nodes.
+class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
+public:
+ DependentDecltypeType(Expr *E);
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getUnderlyingExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ Expr *E);
+};
+
+class PackIndexingType final
+ : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<PackIndexingType, QualType> {
+ friend TrailingObjects;
+
+ QualType Pattern;
+ Expr *IndexExpr;
+
+ unsigned Size : 31;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned FullySubstituted : 1;
+
+protected:
+ friend class ASTContext; // ASTContext creates these.
+ PackIndexingType(QualType Canonical, QualType Pattern, Expr *IndexExpr,
+ bool FullySubstituted, ArrayRef<QualType> Expansions = {});
+
+public:
+ Expr *getIndexExpr() const { return IndexExpr; }
+ QualType getPattern() const { return Pattern; }
+
+ bool isSugared() const { return hasSelectedType(); }
+
+ QualType desugar() const {
+ if (hasSelectedType())
+ return getSelectedType();
+ return QualType(this, 0);
+ }
+
+ QualType getSelectedType() const {
+ assert(hasSelectedType() && "Type is dependant");
+ return *(getExpansionsPtr() + *getSelectedIndex());
+ }
+
+ UnsignedOrNone getSelectedIndex() const;
+
+ bool hasSelectedType() const { return getSelectedIndex() != std::nullopt; }
+
+ bool isFullySubstituted() const { return FullySubstituted; }
+
+ bool expandsToEmptyPack() const { return isFullySubstituted() && Size == 0; }
+
+ ArrayRef<QualType> getExpansions() const {
+ return {getExpansionsPtr(), Size};
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == PackIndexing;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Pattern, Expr *E, bool FullySubstituted,
+ ArrayRef<QualType> Expansions);
+
+private:
+ const QualType *getExpansionsPtr() const { return getTrailingObjects(); }
+
+ static TypeDependence computeDependence(QualType Pattern, Expr *IndexExpr,
+ ArrayRef<QualType> Expansions = {});
+};
+
+/// A unary type transform, which is a type constructed from another.
+class UnaryTransformType : public Type, public llvm::FoldingSetNode {
+public:
+ enum UTTKind {
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, _) Enum,
+#include "clang/Basic/TransformTypeTraits.def"
+ };
+
+private:
+ /// The untransformed type.
+ QualType BaseType;
+
+ /// The transformed type if not dependent, otherwise the same as BaseType.
+ QualType UnderlyingType;
+
+ UTTKind UKind;
+
+protected:
+ friend class ASTContext;
+
+ UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind,
+ QualType CanonicalTy);
+
+public:
+ bool isSugared() const { return !isDependentType(); }
+ QualType desugar() const { return UnderlyingType; }
+
+ QualType getUnderlyingType() const { return UnderlyingType; }
+ QualType getBaseType() const { return BaseType; }
+
+ UTTKind getUTTKind() const { return UKind; }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == UnaryTransform;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getBaseType(), getUnderlyingType(), getUTTKind());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType BaseType,
+ QualType UnderlyingType, UTTKind UKind) {
+ BaseType.Profile(ID);
+ UnderlyingType.Profile(ID);
+ ID.AddInteger(UKind);
+ }
+};
+
+class TagType : public TypeWithKeyword {
+ friend class ASTContext; // ASTContext creates these.
+
+ /// Stores the TagDecl associated with this type. The decl may point to any
+ /// TagDecl that declares the entity.
+ TagDecl *decl;
+
+ void *getTrailingPointer() const;
+ NestedNameSpecifier &getTrailingQualifier() const;
+
+protected:
+ TagType(TypeClass TC, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag,
+ bool IsInjected, const Type *CanonicalType);
+
+public:
+ // FIXME: Temporarily renamed from `getDecl` in order to facilitate
+ // rebasing, due to change in behaviour. This should be renamed back
+ // to `getDecl` once the change is settled.
+ TagDecl *getOriginalDecl() const { return decl; }
+
+ NestedNameSpecifier getQualifier() const;
+
+ /// Does the TagType own this declaration of the Tag?
+ bool isTagOwned() const { return TagTypeBits.OwnsTag; }
+
+ bool isInjected() const { return TagTypeBits.IsInjected; }
+
+ ClassTemplateDecl *getTemplateDecl() const;
+ TemplateName getTemplateName(const ASTContext &Ctx) const;
+ ArrayRef<TemplateArgument> getTemplateArgs(const ASTContext &Ctx) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return getCanonicalTypeInternal(); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Enum || T->getTypeClass() == Record ||
+ T->getTypeClass() == InjectedClassName;
+ }
+};
+
+struct TagTypeFoldingSetPlaceholder : public llvm::FoldingSetNode {
+ static constexpr size_t getOffset() {
+ return alignof(TagType) -
+ (sizeof(TagTypeFoldingSetPlaceholder) % alignof(TagType));
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *Tag,
+ bool OwnsTag, bool IsInjected) {
+ ID.AddInteger(uintptr_t(Tag) | OwnsTag | (IsInjected << 1) |
+ ((Keyword != ElaboratedTypeKeyword::None) << 2));
+ if (Keyword != ElaboratedTypeKeyword::None)
+ ID.AddInteger(llvm::to_underlying(Keyword));
+ if (Qualifier)
+ Qualifier.Profile(ID);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ const TagType *T = getTagType();
+ Profile(ID, T->getKeyword(), T->getQualifier(), T->getOriginalDecl(),
+ T->isTagOwned(), T->isInjected());
+ }
+
+ TagType *getTagType() {
+ return reinterpret_cast<TagType *>(reinterpret_cast<char *>(this + 1) +
+ getOffset());
+ }
+ const TagType *getTagType() const {
+ return const_cast<TagTypeFoldingSetPlaceholder *>(this)->getTagType();
+ }
+ static TagTypeFoldingSetPlaceholder *fromTagType(TagType *T) {
+ return reinterpret_cast<TagTypeFoldingSetPlaceholder *>(
+ reinterpret_cast<char *>(T) - getOffset()) -
+ 1;
+ }
+};
+
+/// A helper class that allows the use of isa/cast/dyncast
+/// to detect TagType objects of structs/unions/classes.
+class RecordType final : public TagType {
+ using TagType::TagType;
+
+public:
+ // FIXME: Temporarily renamed from `getDecl` in order to facilitate
+ // rebasing, due to change in behaviour. This should be renamed back
+ // to `getDecl` once the change is settled.
+ RecordDecl *getOriginalDecl() const {
+ return reinterpret_cast<RecordDecl *>(TagType::getOriginalDecl());
+ }
+
+ /// Recursively check all fields in the record for const-ness. If any field
+ /// is declared const, return true. Otherwise, return false.
+ bool hasConstFields() const;
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Record; }
+};
+
+/// A helper class that allows the use of isa/cast/dyncast
+/// to detect TagType objects of enums.
+class EnumType final : public TagType {
+ using TagType::TagType;
+
+public:
+ // FIXME: Temporarily renamed from `getDecl` in order to facilitate
+ // rebasing, due to change in behaviour. This should be renamed back
+ // to `getDecl` once the change is settled.
+ EnumDecl *getOriginalDecl() const {
+ return reinterpret_cast<EnumDecl *>(TagType::getOriginalDecl());
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == Enum; }
+};
+
+/// The injected class name of a C++ class template or class
+/// template partial specialization. Used to record that a type was
+/// spelled with a bare identifier rather than as a template-id; the
+/// equivalent for non-templated classes is just RecordType.
+///
+/// Injected class name types are always dependent. Template
+/// instantiation turns these into RecordTypes.
+///
+/// Injected class name types are always canonical. This works
+/// because it is impossible to compare an injected class name type
+/// with the corresponding non-injected template type, for the same
+/// reason that it is impossible to directly compare template
+/// parameters from different dependent contexts: injected class name
+/// types can only occur within the scope of a particular templated
+/// declaration, and within that scope every template specialization
+/// will canonicalize to the injected class name (when appropriate
+/// according to the rules of the language).
+class InjectedClassNameType final : public TagType {
+ friend class ASTContext; // ASTContext creates these.
+
+ InjectedClassNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *TD,
+ bool IsInjected, const Type *CanonicalType);
+
+public:
+ // FIXME: Temporarily renamed from `getDecl` in order to facilitate
+ // rebasing, due to change in behaviour. This should be renamed back
+ // to `getDecl` once the change is settled.
+ CXXRecordDecl *getOriginalDecl() const {
+ return reinterpret_cast<CXXRecordDecl *>(TagType::getOriginalDecl());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == InjectedClassName;
+ }
+};
+
+/// An attributed type is a type to which a type attribute has been applied.
+///
+/// The "modified type" is the fully-sugared type to which the attributed
+/// type was applied; generally it is not canonically equivalent to the
+/// attributed type. The "equivalent type" is the minimally-desugared type
+/// which the type is canonically equivalent to.
+///
+/// For example, in the following attributed type:
+/// int32_t __attribute__((vector_size(16)))
+/// - the modified type is the TypedefType for int32_t
+/// - the equivalent type is VectorType(16, int32_t)
+/// - the canonical type is VectorType(16, int)
+class AttributedType : public Type, public llvm::FoldingSetNode {
+public:
+ using Kind = attr::Kind;
+
+private:
+ friend class ASTContext; // ASTContext creates these
+
+ const Attr *Attribute;
+
+ QualType ModifiedType;
+ QualType EquivalentType;
+
+ AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
+ QualType equivalent)
+ : AttributedType(canon, attrKind, nullptr, modified, equivalent) {}
+
+ AttributedType(QualType canon, const Attr *attr, QualType modified,
+ QualType equivalent);
+
+private:
+ AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr,
+ QualType modified, QualType equivalent);
+
+public:
+ Kind getAttrKind() const {
+ return static_cast<Kind>(AttributedTypeBits.AttrKind);
+ }
+
+ const Attr *getAttr() const { return Attribute; }
+
+ QualType getModifiedType() const { return ModifiedType; }
+ QualType getEquivalentType() const { return EquivalentType; }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return getEquivalentType(); }
+
+ /// Does this attribute behave like a type qualifier?
+ ///
+ /// A type qualifier adjusts a type to provide specialized rules for
+ /// a specific object, like the standard const and volatile qualifiers.
+ /// This includes attributes controlling things like nullability,
+ /// address spaces, and ARC ownership. The value of the object is still
+ /// largely described by the modified type.
+ ///
+ /// In contrast, many type attributes "rewrite" their modified type to
+ /// produce a fundamentally different type, not necessarily related in any
+ /// formalizable way to the original type. For example, calling convention
+ /// and vector attributes are not simple type qualifiers.
+ ///
+ /// Type qualifiers are often, but not always, reflected in the canonical
+ /// type.
+ bool isQualifier() const;
+
+ bool isMSTypeSpec() const;
+
+ bool isWebAssemblyFuncrefSpec() const;
+
+ bool isCallingConv() const;
+
+ std::optional<NullabilityKind> getImmediateNullability() const;
+
+ /// Strip off the top-level nullability annotation on the given
+ /// type, if it's there.
+ ///
+ /// \param T The type to strip. If the type is exactly an
+ /// AttributedType specifying nullability (without looking through
+ /// type sugar), the nullability is returned and this type changed
+ /// to the underlying modified type.
+ ///
+ /// \returns the top-level nullability, if present.
+ static std::optional<NullabilityKind> stripOuterNullability(QualType &T);
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
+ QualType modified, QualType equivalent,
+ const Attr *attr) {
+ ID.AddInteger(attrKind);
+ ID.AddPointer(modified.getAsOpaquePtr());
+ ID.AddPointer(equivalent.getAsOpaquePtr());
+ ID.AddPointer(attr);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Attributed;
+ }
+};
+
+class BTFTagAttributedType : public Type, public llvm::FoldingSetNode {
+private:
+ friend class ASTContext; // ASTContext creates these
+
+ QualType WrappedType;
+ const BTFTypeTagAttr *BTFAttr;
+
+ BTFTagAttributedType(QualType Canon, QualType Wrapped,
+ const BTFTypeTagAttr *BTFAttr)
+ : Type(BTFTagAttributed, Canon, Wrapped->getDependence()),
+ WrappedType(Wrapped), BTFAttr(BTFAttr) {}
+
+public:
+ QualType getWrappedType() const { return WrappedType; }
+ const BTFTypeTagAttr *getAttr() const { return BTFAttr; }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return getWrappedType(); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, WrappedType, BTFAttr);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped,
+ const BTFTypeTagAttr *BTFAttr) {
+ ID.AddPointer(Wrapped.getAsOpaquePtr());
+ ID.AddPointer(BTFAttr);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == BTFTagAttributed;
+ }
+};
+
+class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
+public:
+ struct Attributes {
+ // Data gathered from HLSL resource attributes
+ llvm::dxil::ResourceClass ResourceClass;
+
+ LLVM_PREFERRED_TYPE(bool)
+ uint8_t IsROV : 1;
+
+ LLVM_PREFERRED_TYPE(bool)
+ uint8_t RawBuffer : 1;
+
+ Attributes(llvm::dxil::ResourceClass ResourceClass, bool IsROV = false,
+ bool RawBuffer = false)
+ : ResourceClass(ResourceClass), IsROV(IsROV), RawBuffer(RawBuffer) {}
+
+ Attributes() : Attributes(llvm::dxil::ResourceClass::UAV, false, false) {}
+
+ friend bool operator==(const Attributes &LHS, const Attributes &RHS) {
+ return std::tie(LHS.ResourceClass, LHS.IsROV, LHS.RawBuffer) ==
+ std::tie(RHS.ResourceClass, RHS.IsROV, RHS.RawBuffer);
+ }
+ friend bool operator!=(const Attributes &LHS, const Attributes &RHS) {
+ return !(LHS == RHS);
+ }
+ };
+
+private:
+ friend class ASTContext; // ASTContext creates these
+
+ QualType WrappedType;
+ QualType ContainedType;
+ const Attributes Attrs;
+
+ HLSLAttributedResourceType(QualType Wrapped, QualType Contained,
+ const Attributes &Attrs)
+ : Type(HLSLAttributedResource, QualType(),
+ Contained.isNull() ? TypeDependence::None
+ : Contained->getDependence()),
+ WrappedType(Wrapped), ContainedType(Contained), Attrs(Attrs) {}
+
+public:
+ QualType getWrappedType() const { return WrappedType; }
+ QualType getContainedType() const { return ContainedType; }
+ bool hasContainedType() const { return !ContainedType.isNull(); }
+ const Attributes &getAttrs() const { return Attrs; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, WrappedType, ContainedType, Attrs);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Wrapped,
+ QualType Contained, const Attributes &Attrs) {
+ ID.AddPointer(Wrapped.getAsOpaquePtr());
+ ID.AddPointer(Contained.getAsOpaquePtr());
+ ID.AddInteger(static_cast<uint32_t>(Attrs.ResourceClass));
+ ID.AddBoolean(Attrs.IsROV);
+ ID.AddBoolean(Attrs.RawBuffer);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == HLSLAttributedResource;
+ }
+
+ // Returns handle type from HLSL resource, if the type is a resource
+ static const HLSLAttributedResourceType *
+ findHandleTypeOnResource(const Type *RT);
+};
+
+/// Instances of this class represent operands to a SPIR-V type instruction.
+class SpirvOperand {
+public:
+ enum SpirvOperandKind : unsigned char {
+ Invalid, ///< Uninitialized.
+ ConstantId, ///< Integral value to represent as a SPIR-V OpConstant
+ ///< instruction ID.
+ Literal, ///< Integral value to represent as an immediate literal.
+ TypeId, ///< Type to represent as a SPIR-V type ID.
+
+ Max,
+ };
+
+private:
+ SpirvOperandKind Kind = Invalid;
+
+ QualType ResultType;
+ llvm::APInt Value; // Signedness of constants is represented by ResultType.
+
+public:
+ SpirvOperand() : Kind(Invalid), ResultType(), Value() {}
+
+ SpirvOperand(SpirvOperandKind Kind, QualType ResultType, llvm::APInt Value)
+ : Kind(Kind), ResultType(ResultType), Value(std::move(Value)) {}
+
+ SpirvOperand(const SpirvOperand &Other) { *this = Other; }
+ ~SpirvOperand() {}
+
+ SpirvOperand &operator=(const SpirvOperand &Other) = default;
+
+ bool operator==(const SpirvOperand &Other) const {
+ return Kind == Other.Kind && ResultType == Other.ResultType &&
+ Value == Other.Value;
+ }
+
+ bool operator!=(const SpirvOperand &Other) const { return !(*this == Other); }
+
+ SpirvOperandKind getKind() const { return Kind; }
+
+ bool isValid() const { return Kind != Invalid && Kind < Max; }
+ bool isConstant() const { return Kind == ConstantId; }
+ bool isLiteral() const { return Kind == Literal; }
+ bool isType() const { return Kind == TypeId; }
+
+ llvm::APInt getValue() const {
+ assert((isConstant() || isLiteral()) &&
+ "This is not an operand with a value!");
+ return Value;
+ }
+
+ QualType getResultType() const {
+ assert((isConstant() || isType()) &&
+ "This is not an operand with a result type!");
+ return ResultType;
+ }
+
+ static SpirvOperand createConstant(QualType ResultType, llvm::APInt Val) {
+ return SpirvOperand(ConstantId, ResultType, std::move(Val));
+ }
+
+ static SpirvOperand createLiteral(llvm::APInt Val) {
+ return SpirvOperand(Literal, QualType(), std::move(Val));
+ }
+
+ static SpirvOperand createType(QualType T) {
+ return SpirvOperand(TypeId, T, llvm::APSInt());
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(Kind);
+ ID.AddPointer(ResultType.getAsOpaquePtr());
+ Value.Profile(ID);
+ }
+};
+
+/// Represents an arbitrary, user-specified SPIR-V type instruction.
+class HLSLInlineSpirvType final
+ : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<HLSLInlineSpirvType, SpirvOperand> {
+ friend class ASTContext; // ASTContext creates these
+ friend TrailingObjects;
+
+private:
+ uint32_t Opcode;
+ uint32_t Size;
+ uint32_t Alignment;
+ size_t NumOperands;
+
+ HLSLInlineSpirvType(uint32_t Opcode, uint32_t Size, uint32_t Alignment,
+ ArrayRef<SpirvOperand> Operands)
+ : Type(HLSLInlineSpirv, QualType(), TypeDependence::None), Opcode(Opcode),
+ Size(Size), Alignment(Alignment), NumOperands(Operands.size()) {
+ for (size_t I = 0; I < NumOperands; I++) {
+ // Since Operands are stored as a trailing object, they have not been
+ // initialized yet. Call the constructor manually.
+ auto *Operand = new (&getTrailingObjects()[I]) SpirvOperand();
+ *Operand = Operands[I];
+ }
+ }
+
+public:
+ uint32_t getOpcode() const { return Opcode; }
+ uint32_t getSize() const { return Size; }
+ uint32_t getAlignment() const { return Alignment; }
+ ArrayRef<SpirvOperand> getOperands() const {
+ return getTrailingObjects(NumOperands);
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Opcode, Size, Alignment, getOperands());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, uint32_t Opcode,
+ uint32_t Size, uint32_t Alignment,
+ ArrayRef<SpirvOperand> Operands) {
+ ID.AddInteger(Opcode);
+ ID.AddInteger(Size);
+ ID.AddInteger(Alignment);
+ for (auto &Operand : Operands)
+ Operand.Profile(ID);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == HLSLInlineSpirv;
+ }
+};
+
+class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these
+
+ // The associated TemplateTypeParmDecl for the non-canonical type.
+ TemplateTypeParmDecl *TTPDecl;
+
+ TemplateTypeParmType(unsigned D, unsigned I, bool PP,
+ TemplateTypeParmDecl *TTPDecl, QualType Canon)
+ : Type(TemplateTypeParm, Canon,
+ TypeDependence::DependentInstantiation |
+ (PP ? TypeDependence::UnexpandedPack : TypeDependence::None)),
+ TTPDecl(TTPDecl) {
+ assert(!TTPDecl == Canon.isNull());
+ TemplateTypeParmTypeBits.Depth = D;
+ TemplateTypeParmTypeBits.Index = I;
+ TemplateTypeParmTypeBits.ParameterPack = PP;
+ }
+
+public:
+ unsigned getDepth() const { return TemplateTypeParmTypeBits.Depth; }
+ unsigned getIndex() const { return TemplateTypeParmTypeBits.Index; }
+ bool isParameterPack() const {
+ return TemplateTypeParmTypeBits.ParameterPack;
+ }
+
+ TemplateTypeParmDecl *getDecl() const { return TTPDecl; }
+
+ IdentifierInfo *getIdentifier() const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth,
+ unsigned Index, bool ParameterPack,
+ TemplateTypeParmDecl *TTPDecl) {
+ ID.AddInteger(Depth);
+ ID.AddInteger(Index);
+ ID.AddBoolean(ParameterPack);
+ ID.AddPointer(TTPDecl);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateTypeParm;
+ }
+};
+
+/// Represents the result of substituting a type for a template
+/// type parameter.
+///
+/// Within an instantiated template, all template type parameters have
+/// been replaced with these. They are used solely to record that a
+/// type was originally written as a template type parameter;
+/// therefore they are never canonical.
+class SubstTemplateTypeParmType final
+ : public Type,
+ public llvm::FoldingSetNode,
+ private llvm::TrailingObjects<SubstTemplateTypeParmType, QualType> {
+ friend class ASTContext;
+ friend class llvm::TrailingObjects<SubstTemplateTypeParmType, QualType>;
+
+ Decl *AssociatedDecl;
+
+ SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
+ unsigned Index, UnsignedOrNone PackIndex,
+ bool Final);
+
+public:
+ /// Gets the type that was substituted for the template
+ /// parameter.
+ QualType getReplacementType() const {
+ return SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType
+ ? *getTrailingObjects()
+ : getCanonicalTypeInternal();
+ }
+
+ /// A template-like entity which owns the whole pattern being substituted.
+ /// This will usually own a set of template parameters, or in some
+ /// cases might even be a template parameter itself.
+ Decl *getAssociatedDecl() const { return AssociatedDecl; }
+
+ /// Gets the template parameter declaration that was substituted for.
+ const TemplateTypeParmDecl *getReplacedParameter() const;
+
+ /// Returns the index of the replaced parameter in the associated declaration.
+ /// This should match the result of `getReplacedParameter()->getIndex()`.
+ unsigned getIndex() const { return SubstTemplateTypeParmTypeBits.Index; }
+
+ // This substitution is Final, which means the substitution is fully
+ // sugared: it doesn't need to be resugared later.
+ unsigned getFinal() const { return SubstTemplateTypeParmTypeBits.Final; }
+
+ UnsignedOrNone getPackIndex() const {
+ return UnsignedOrNone::fromInternalRepresentation(
+ SubstTemplateTypeParmTypeBits.PackIndex);
+ }
+
+ bool isSugared() const { return true; }
+ QualType desugar() const { return getReplacementType(); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
+ getPackIndex(), getFinal());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
+ const Decl *AssociatedDecl, unsigned Index,
+ UnsignedOrNone PackIndex, bool Final);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == SubstTemplateTypeParm;
+ }
+};
+
+/// Represents the result of substituting a set of types as a template argument
+/// that needs to be expanded later.
+///
+/// These types are always dependent and produced depending on the situations:
+/// - SubstTemplateTypeParmPack is an expansion that had to be delayed,
+/// - SubstBuiltinTemplatePackType is an expansion from a builtin.
+class SubstPackType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ /// A pointer to the set of template arguments that this
+ /// parameter pack is instantiated with.
+ const TemplateArgument *Arguments;
+
+protected:
+ SubstPackType(TypeClass Derived, QualType Canon,
+ const TemplateArgument &ArgPack);
+
+public:
+ unsigned getNumArgs() const { return SubstPackTypeBits.NumArgs; }
+
+ TemplateArgument getArgumentPack() const;
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const TemplateArgument &ArgPack);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == SubstTemplateTypeParmPack ||
+ T->getTypeClass() == SubstBuiltinTemplatePack;
+ }
+};
+
+/// Represents the result of substituting a builtin template as a pack.
+class SubstBuiltinTemplatePackType : public SubstPackType {
+ friend class ASTContext;
+
+ SubstBuiltinTemplatePackType(QualType Canon, const TemplateArgument &ArgPack);
+
+public:
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ /// Mark that we reuse the Profile. We do not introduce new fields.
+ using SubstPackType::Profile;
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == SubstBuiltinTemplatePack;
+ }
+};
+
+/// Represents the result of substituting a set of types for a template
+/// type parameter pack.
+///
+/// When a pack expansion in the source code contains multiple parameter packs
+/// and those parameter packs correspond to different levels of template
+/// parameter lists, this type node is used to represent a template type
+/// parameter pack from an outer level, which has already had its argument pack
+/// substituted but that still lives within a pack expansion that itself
+/// could not be instantiated. When actually performing a substitution into
+/// that pack expansion (e.g., when all template parameters have corresponding
+/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType
+/// at the current pack substitution index.
+class SubstTemplateTypeParmPackType : public SubstPackType {
+ friend class ASTContext;
+
+ /// A pointer to the set of template arguments that this
+ /// parameter pack is instantiated with.
+ const TemplateArgument *Arguments;
+
+ llvm::PointerIntPair<Decl *, 1, bool> AssociatedDeclAndFinal;
+
+ SubstTemplateTypeParmPackType(QualType Canon, Decl *AssociatedDecl,
+ unsigned Index, bool Final,
+ const TemplateArgument &ArgPack);
+
+public:
+ IdentifierInfo *getIdentifier() const;
+
+ /// A template-like entity which owns the whole pattern being substituted.
+ /// This will usually own a set of template parameters, or in some
+ /// cases might even be a template parameter itself.
+ Decl *getAssociatedDecl() const;
+
+ /// Gets the template parameter declaration that was substituted for.
+ const TemplateTypeParmDecl *getReplacedParameter() const;
+
+ /// Returns the index of the replaced parameter in the associated declaration.
+ /// This should match the result of `getReplacedParameter()->getIndex()`.
+ unsigned getIndex() const {
+ return SubstPackTypeBits.SubstTemplTypeParmPackIndex;
+ }
+
+ // This substitution will be Final, which means the substitution will be fully
+ // sugared: it doesn't need to be resugared later.
+ bool getFinal() const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID, const Decl *AssociatedDecl,
+ unsigned Index, bool Final,
+ const TemplateArgument &ArgPack);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == SubstTemplateTypeParmPack;
+ }
+};
+
+/// Common base class for placeholders for types that get replaced by
+/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
+/// class template types, and constrained type names.
+///
+/// These types are usually a placeholder for a deduced type. However, before
+/// the initializer is attached, or (usually) if the initializer is
+/// type-dependent, there is no deduced type and the type is canonical. In
+/// the latter case, it is also a dependent type.
+class DeducedType : public Type {
+ QualType DeducedAsType;
+
+protected:
+ DeducedType(TypeClass TC, QualType DeducedAsType,
+ TypeDependence ExtraDependence, QualType Canon)
+ : Type(TC, Canon,
+ ExtraDependence | (DeducedAsType.isNull()
+ ? TypeDependence::None
+ : DeducedAsType->getDependence() &
+ ~TypeDependence::VariablyModified)),
+ DeducedAsType(DeducedAsType) {}
+
+public:
+ bool isSugared() const { return !DeducedAsType.isNull(); }
+ QualType desugar() const {
+ return isSugared() ? DeducedAsType : QualType(this, 0);
+ }
+
+ /// Get the type deduced for this placeholder type, or null if it
+ /// has not been deduced.
+ QualType getDeducedType() const { return DeducedAsType; }
+ bool isDeduced() const {
+ return !DeducedAsType.isNull() || isDependentType();
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Auto ||
+ T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
+/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
+/// by a type-constraint.
+class AutoType : public DeducedType {
+ friend class ASTContext; // ASTContext creates these
+
+ TemplateDecl *TypeConstraintConcept;
+
+ AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD,
+ ArrayRef<TemplateArgument> TypeConstraintArgs);
+
+public:
+ ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
+ return {reinterpret_cast<const TemplateArgument *>(this + 1),
+ AutoTypeBits.NumArgs};
+ }
+
+ TemplateDecl *getTypeConstraintConcept() const {
+ return TypeConstraintConcept;
+ }
+
+ bool isConstrained() const {
+ return TypeConstraintConcept != nullptr;
+ }
+
+ bool isDecltypeAuto() const {
+ return getKeyword() == AutoTypeKeyword::DecltypeAuto;
+ }
+
+ bool isGNUAutoType() const {
+ return getKeyword() == AutoTypeKeyword::GNUAutoType;
+ }
+
+ AutoTypeKeyword getKeyword() const {
+ return (AutoTypeKeyword)AutoTypeBits.Keyword;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, TemplateDecl *CD,
+ ArrayRef<TemplateArgument> Arguments);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Auto;
+ }
+};
+
+/// Represents a C++17 deduced template specialization type.
+class DeducedTemplateSpecializationType : public KeywordWrapper<DeducedType>,
+ public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these
+
+ /// The name of the template whose arguments will be deduced.
+ TemplateName Template;
+
+ DeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
+ TemplateName Template,
+ QualType DeducedAsType,
+ bool IsDeducedAsDependent, QualType Canon)
+ : KeywordWrapper(Keyword, DeducedTemplateSpecialization, DeducedAsType,
+ toTypeDependence(Template.getDependence()) |
+ (IsDeducedAsDependent
+ ? TypeDependence::DependentInstantiation
+ : TypeDependence::None),
+ Canon),
+ Template(Template) {}
+
+public:
+ /// Retrieve the name of the template that we are deducing.
+ TemplateName getTemplateName() const { return Template; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, getKeyword(), getTemplateName(), getDeducedType(),
+ isDependentType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ TemplateName Template, QualType Deduced,
+ bool IsDependent) {
+ ID.AddInteger(llvm::to_underlying(Keyword));
+ Template.Profile(ID);
+ Deduced.Profile(ID);
+ ID.AddBoolean(IsDependent || Template.isDependent());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DeducedTemplateSpecialization;
+ }
+};
+
+/// Represents a type template specialization; the template
+/// must be a class template, a type alias template, or a template
+/// template parameter. A template which cannot be resolved to one of
+/// these, e.g. because it is written with a dependent scope
+/// specifier, is instead represented as a
+/// @c DependentTemplateSpecializationType.
+///
+/// A non-dependent template specialization type is always "sugar",
+/// typically for a \c RecordType. For example, a class template
+/// specialization type of \c vector<int> will refer to a tag type for
+/// the instantiation \c std::vector<int, std::allocator<int>>
+///
+/// Template specializations are dependent if either the template or
+/// any of the template arguments are dependent, in which case the
+/// type may also be canonical.
+///
+/// Instances of this type are allocated with a trailing array of
+/// TemplateArguments, followed by a QualType representing the
+/// non-canonical aliased type when the template is a type alias
+/// template.
+class TemplateSpecializationType : public TypeWithKeyword,
+ public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these
+
+ /// The name of the template being specialized. This is
+ /// either a TemplateName::Template (in which case it is a
+ /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a
+ /// TypeAliasTemplateDecl*), a
+ /// TemplateName::SubstTemplateTemplateParmPack, or a
+ /// TemplateName::SubstTemplateTemplateParm (in which case the
+ /// replacement must, recursively, be one of these).
+ TemplateName Template;
+
+ TemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T,
+ bool IsAlias, ArrayRef<TemplateArgument> Args,
+ QualType Underlying);
+
+public:
+ /// Determine whether any of the given template arguments are dependent.
+ ///
+ /// The converted arguments should be supplied when known; whether an
+ /// argument is dependent can depend on the conversions performed on it
+ /// (for example, a 'const int' passed as a template argument might be
+ /// dependent if the parameter is a reference but non-dependent if the
+ /// parameter is an int).
+ ///
+ /// Note that the \p Args parameter is unused: this is intentional, to remind
+ /// the caller that they need to pass in the converted arguments, not the
+ /// specified arguments.
+ static bool
+ anyDependentTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
+ ArrayRef<TemplateArgument> Converted);
+ static bool
+ anyDependentTemplateArguments(const TemplateArgumentListInfo &,
+ ArrayRef<TemplateArgument> Converted);
+ static bool anyInstantiationDependentTemplateArguments(
+ ArrayRef<TemplateArgumentLoc> Args);
+
+ /// True if this template specialization type matches a current
+ /// instantiation in the context in which it is found.
+ bool isCurrentInstantiation() const {
+ return isa<InjectedClassNameType>(getCanonicalTypeInternal());
+ }
+
+ /// Determine if this template specialization type is for a type alias
+ /// template that has been substituted.
+ ///
+ /// Nearly every template specialization type whose template is an alias
+ /// template will be substituted. However, this is not the case when
+ /// the specialization contains a pack expansion but the template alias
+ /// does not have a corresponding parameter pack, e.g.,
+ ///
+ /// \code
+ /// template<typename T, typename U, typename V> struct S;
+ /// template<typename T, typename U> using A = S<T, int, U>;
+ /// template<typename... Ts> struct X {
+ /// typedef A<Ts...> type; // not a type alias
+ /// };
+ /// \endcode
+ bool isTypeAlias() const { return TemplateSpecializationTypeBits.TypeAlias; }
+
+ /// Get the aliased type, if this is a specialization of a type alias
+ /// template.
+ QualType getAliasedType() const;
+
+ /// Retrieve the name of the template that we are specializing.
+ TemplateName getTemplateName() const { return Template; }
+
+ ArrayRef<TemplateArgument> template_arguments() const {
+ return {reinterpret_cast<const TemplateArgument *>(this + 1),
+ TemplateSpecializationTypeBits.NumArgs};
+ }
+
+ bool isSugared() const;
+
+ QualType desugar() const {
+ return isTypeAlias() ? getAliasedType() : getCanonicalTypeInternal();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
+ static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
+ ArrayRef<TemplateArgument> Args, QualType Underlying,
+ const ASTContext &Context);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == TemplateSpecialization;
+ }
+};
+
+/// Print a template argument list, including the '<' and '>'
+/// enclosing the template arguments.
+void printTemplateArgumentList(raw_ostream &OS,
+ ArrayRef<TemplateArgument> Args,
+ const PrintingPolicy &Policy,
+ const TemplateParameterList *TPL = nullptr);
+
+void printTemplateArgumentList(raw_ostream &OS,
+ ArrayRef<TemplateArgumentLoc> Args,
+ const PrintingPolicy &Policy,
+ const TemplateParameterList *TPL = nullptr);
+
+void printTemplateArgumentList(raw_ostream &OS,
+ const TemplateArgumentListInfo &Args,
+ const PrintingPolicy &Policy,
+ const TemplateParameterList *TPL = nullptr);
+
+/// Make a best-effort determination of whether the type T can be produced by
+/// substituting Args into the default argument of Param.
+bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
+ const NamedDecl *Param,
+ ArrayRef<TemplateArgument> Args,
+ unsigned Depth);
+
+/// Represents a qualified type name for which the type name is
+/// dependent.
+///
+/// DependentNameType represents a class of dependent types that involve a
+/// possibly dependent nested-name-specifier (e.g., "T::") followed by a
+/// name of a type. The DependentNameType may start with a "typename" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a
+/// dependent elaborated-type-specifier), or nothing (in contexts where we
+/// know that we must be referring to a type, e.g., in a base class specifier).
+/// Typically the nested-name-specifier is dependent, but in MSVC compatibility
+/// mode, this type is used with non-dependent names to delay name lookup until
+/// instantiation.
+class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these
+
+ /// The nested name specifier containing the qualifier.
+ NestedNameSpecifier NNS;
+
+ /// The type that this typename specifier refers to.
+ const IdentifierInfo *Name;
+
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS,
+ const IdentifierInfo *Name, QualType CanonType)
+ : TypeWithKeyword(Keyword, DependentName, CanonType,
+ TypeDependence::DependentInstantiation |
+ (NNS ? toTypeDependence(NNS.getDependence())
+ : TypeDependence::Dependent)),
+ NNS(NNS), Name(Name) {
+ assert(Name);
+ }
+
+public:
+ /// Retrieve the qualification on this type.
+ NestedNameSpecifier getQualifier() const { return NNS; }
+
+ /// Retrieve the identifier that terminates this type name.
+ /// For example, "type" in "typename T::type".
+ const IdentifierInfo *getIdentifier() const {
+ return Name;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getKeyword(), NNS, Name);
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier NNS, const IdentifierInfo *Name) {
+ ID.AddInteger(llvm::to_underlying(Keyword));
+ NNS.Profile(ID);
+ ID.AddPointer(Name);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentName;
+ }
+};
+
+/// Represents a template specialization type whose template cannot be
+/// resolved, e.g.
+/// A<T>::template B<T>
+class DependentTemplateSpecializationType : public TypeWithKeyword {
+ friend class ASTContext; // ASTContext creates these
+
+ DependentTemplateStorage Name;
+
+ DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
+ const DependentTemplateStorage &Name,
+ ArrayRef<TemplateArgument> Args,
+ QualType Canon);
+
+public:
+ const DependentTemplateStorage &getDependentTemplateName() const {
+ return Name;
+ }
+
+ ArrayRef<TemplateArgument> template_arguments() const {
+ return {reinterpret_cast<const TemplateArgument *>(this + 1),
+ DependentTemplateSpecializationTypeBits.NumArgs};
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getKeyword(), Name, template_arguments());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ ElaboratedTypeKeyword Keyword,
+ const DependentTemplateStorage &Name,
+ ArrayRef<TemplateArgument> Args);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentTemplateSpecialization;
+ }
+};
+
+/// Represents a pack expansion of types.
+///
+/// Pack expansions are part of C++11 variadic templates. A pack
+/// expansion contains a pattern, which itself contains one or more
+/// "unexpanded" parameter packs. When instantiated, a pack expansion
+/// produces a series of types, each instantiated from the pattern of
+/// the expansion, where the Ith instantiation of the pattern uses the
+/// Ith arguments bound to each of the unexpanded parameter packs. The
+/// pack expansion is considered to "expand" these unexpanded
+/// parameter packs.
+///
+/// \code
+/// template<typename ...Types> struct tuple;
+///
+/// template<typename ...Types>
+/// struct tuple_of_references {
+/// typedef tuple<Types&...> type;
+/// };
+/// \endcode
+///
+/// Here, the pack expansion \c Types&... is represented via a
+/// PackExpansionType whose pattern is Types&.
+class PackExpansionType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these
+
+ /// The pattern of the pack expansion.
+ QualType Pattern;
+
+ PackExpansionType(QualType Pattern, QualType Canon,
+ UnsignedOrNone NumExpansions)
+ : Type(PackExpansion, Canon,
+ (Pattern->getDependence() | TypeDependence::Dependent |
+ TypeDependence::Instantiation) &
+ ~TypeDependence::UnexpandedPack),
+ Pattern(Pattern) {
+ PackExpansionTypeBits.NumExpansions =
+ NumExpansions ? *NumExpansions + 1 : 0;
+ }
+
+public:
+ /// Retrieve the pattern of this pack expansion, which is the
+ /// type that will be repeatedly instantiated when instantiating the
+ /// pack expansion itself.
+ QualType getPattern() const { return Pattern; }
+
+ /// Retrieve the number of expansions that this pack expansion will
+ /// generate, if known.
+ UnsignedOrNone getNumExpansions() const {
+ if (PackExpansionTypeBits.NumExpansions)
+ return PackExpansionTypeBits.NumExpansions - 1;
+ return std::nullopt;
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPattern(), getNumExpansions());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern,
+ UnsignedOrNone NumExpansions) {
+ ID.AddPointer(Pattern.getAsOpaquePtr());
+ ID.AddInteger(NumExpansions.toInternalRepresentation());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == PackExpansion;
+ }
+};
+
+/// This class wraps the list of protocol qualifiers. For types that can
+/// take ObjC protocol qualifers, they can subclass this class.
+template <class T>
+class ObjCProtocolQualifiers {
+protected:
+ ObjCProtocolQualifiers() = default;
+
+ ObjCProtocolDecl * const *getProtocolStorage() const {
+ return const_cast<ObjCProtocolQualifiers*>(this)->getProtocolStorage();
+ }
+
+ ObjCProtocolDecl **getProtocolStorage() {
+ return static_cast<T*>(this)->getProtocolStorageImpl();
+ }
+
+ void setNumProtocols(unsigned N) {
+ static_cast<T*>(this)->setNumProtocolsImpl(N);
+ }
+
+ void initialize(ArrayRef<ObjCProtocolDecl *> protocols) {
+ setNumProtocols(protocols.size());
+ assert(getNumProtocols() == protocols.size() &&
+ "bitfield overflow in protocol count");
+ if (!protocols.empty())
+ memcpy(getProtocolStorage(), protocols.data(),
+ protocols.size() * sizeof(ObjCProtocolDecl*));
+ }
+
+public:
+ using qual_iterator = ObjCProtocolDecl * const *;
+ using qual_range = llvm::iterator_range<qual_iterator>;
+
+ qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
+ qual_iterator qual_begin() const { return getProtocolStorage(); }
+ qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); }
+
+ bool qual_empty() const { return getNumProtocols() == 0; }
+
+ /// Return the number of qualifying protocols in this type, or 0 if
+ /// there are none.
+ unsigned getNumProtocols() const {
+ return static_cast<const T*>(this)->getNumProtocolsImpl();
+ }
+
+ /// Fetch a protocol by index.
+ ObjCProtocolDecl *getProtocol(unsigned I) const {
+ assert(I < getNumProtocols() && "Out-of-range protocol access");
+ return qual_begin()[I];
+ }
+
+ /// Retrieve all of the protocol qualifiers.
+ ArrayRef<ObjCProtocolDecl *> getProtocols() const {
+ return ArrayRef<ObjCProtocolDecl *>(qual_begin(), getNumProtocols());
+ }
+};
+
+/// Represents a type parameter type in Objective C. It can take
+/// a list of protocols.
+class ObjCTypeParamType : public Type,
+ public ObjCProtocolQualifiers<ObjCTypeParamType>,
+ public llvm::FoldingSetNode {
+ friend class ASTContext;
+ friend class ObjCProtocolQualifiers<ObjCTypeParamType>;
+
+ /// The number of protocols stored on this type.
+ unsigned NumProtocols : 6;
+
+ ObjCTypeParamDecl *OTPDecl;
+
+ /// The protocols are stored after the ObjCTypeParamType node. In the
+ /// canonical type, the list of protocols are sorted alphabetically
+ /// and uniqued.
+ ObjCProtocolDecl **getProtocolStorageImpl();
+
+ /// Return the number of qualifying protocols in this interface type,
+ /// or 0 if there are none.
+ unsigned getNumProtocolsImpl() const {
+ return NumProtocols;
+ }
+
+ void setNumProtocolsImpl(unsigned N) {
+ NumProtocols = N;
+ }
+
+ ObjCTypeParamType(const ObjCTypeParamDecl *D,
+ QualType can,
+ ArrayRef<ObjCProtocolDecl *> protocols);
+
+public:
+ bool isSugared() const { return true; }
+ QualType desugar() const { return getCanonicalTypeInternal(); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCTypeParam;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const ObjCTypeParamDecl *OTPDecl,
+ QualType CanonicalType,
+ ArrayRef<ObjCProtocolDecl *> protocols);
+
+ ObjCTypeParamDecl *getDecl() const { return OTPDecl; }
+};
+
+/// Represents a class type in Objective C.
+///
+/// Every Objective C type is a combination of a base type, a set of
+/// type arguments (optional, for parameterized classes) and a list of
+/// protocols.
+///
+/// Given the following declarations:
+/// \code
+/// \@class C<T>;
+/// \@protocol P;
+/// \endcode
+///
+/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType
+/// with base C and no protocols.
+///
+/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P].
+/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no
+/// protocol list.
+/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*',
+/// and protocol list [P].
+///
+/// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose
+/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType
+/// and no protocols.
+///
+/// 'id<P>' is an ObjCObjectPointerType whose pointee is an ObjCObjectType
+/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually
+/// this should get its own sugar class to better represent the source.
+class ObjCObjectType : public Type,
+ public ObjCProtocolQualifiers<ObjCObjectType> {
+ friend class ObjCProtocolQualifiers<ObjCObjectType>;
+
+ // ObjCObjectType.NumTypeArgs - the number of type arguments stored
+ // after the ObjCObjectPointerType node.
+ // ObjCObjectType.NumProtocols - the number of protocols stored
+ // after the type arguments of ObjCObjectPointerType node.
+ //
+ // These protocols are those written directly on the type. If
+ // protocol qualifiers ever become additive, the iterators will need
+ // to get kindof complicated.
+ //
+ // In the canonical object type, these are sorted alphabetically
+ // and uniqued.
+
+ /// Either a BuiltinType or an InterfaceType or sugar for either.
+ QualType BaseType;
+
+ /// Cached superclass type.
+ mutable llvm::PointerIntPair<const ObjCObjectType *, 1, bool>
+ CachedSuperClassType;
+
+ QualType *getTypeArgStorage();
+ const QualType *getTypeArgStorage() const {
+ return const_cast<ObjCObjectType *>(this)->getTypeArgStorage();
+ }
+
+ ObjCProtocolDecl **getProtocolStorageImpl();
+ /// Return the number of qualifying protocols in this interface type,
+ /// or 0 if there are none.
+ unsigned getNumProtocolsImpl() const {
+ return ObjCObjectTypeBits.NumProtocols;
+ }
+ void setNumProtocolsImpl(unsigned N) {
+ ObjCObjectTypeBits.NumProtocols = N;
+ }
+
+protected:
+ enum Nonce_ObjCInterface { Nonce_ObjCInterface };
+
+ ObjCObjectType(QualType Canonical, QualType Base,
+ ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf);
+
+ ObjCObjectType(enum Nonce_ObjCInterface)
+ : Type(ObjCInterface, QualType(), TypeDependence::None),
+ BaseType(QualType(this_(), 0)) {
+ ObjCObjectTypeBits.NumProtocols = 0;
+ ObjCObjectTypeBits.NumTypeArgs = 0;
+ ObjCObjectTypeBits.IsKindOf = 0;
+ }
+
+ void computeSuperClassTypeSlow() const;
+
+public:
+ /// Gets the base type of this object type. This is always (possibly
+ /// sugar for) one of:
+ /// - the 'id' builtin type (as opposed to the 'id' type visible to the
+ /// user, which is a typedef for an ObjCObjectPointerType)
+ /// - the 'Class' builtin type (same caveat)
+ /// - an ObjCObjectType (currently always an ObjCInterfaceType)
+ QualType getBaseType() const { return BaseType; }
+
+ bool isObjCId() const {
+ return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId);
+ }
+
+ bool isObjCClass() const {
+ return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass);
+ }
+
+ bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); }
+ bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); }
+ bool isObjCUnqualifiedIdOrClass() const {
+ if (!qual_empty()) return false;
+ if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>())
+ return T->getKind() == BuiltinType::ObjCId ||
+ T->getKind() == BuiltinType::ObjCClass;
+ return false;
+ }
+ bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); }
+ bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); }
+
+ /// Gets the interface declaration for this object type, if the base type
+ /// really is an interface.
+ ObjCInterfaceDecl *getInterface() const;
+
+ /// Determine whether this object type is "specialized", meaning
+ /// that it has type arguments.
+ bool isSpecialized() const;
+
+ /// Determine whether this object type was written with type arguments.
+ bool isSpecializedAsWritten() const {
+ return ObjCObjectTypeBits.NumTypeArgs > 0;
+ }
+
+ /// Determine whether this object type is "unspecialized", meaning
+ /// that it has no type arguments.
+ bool isUnspecialized() const { return !isSpecialized(); }
+
+ /// Determine whether this object type is "unspecialized" as
+ /// written, meaning that it has no type arguments.
+ bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
+
+ /// Retrieve the type arguments of this object type (semantically).
+ ArrayRef<QualType> getTypeArgs() const;
+
+ /// Retrieve the type arguments of this object type as they were
+ /// written.
+ ArrayRef<QualType> getTypeArgsAsWritten() const {
+ return {getTypeArgStorage(), ObjCObjectTypeBits.NumTypeArgs};
+ }
+
+ /// Whether this is a "__kindof" type as written.
+ bool isKindOfTypeAsWritten() const { return ObjCObjectTypeBits.IsKindOf; }
+
+ /// Whether this ia a "__kindof" type (semantically).
+ bool isKindOfType() const;
+
+ /// Retrieve the type of the superclass of this object type.
+ ///
+ /// This operation substitutes any type arguments into the
+ /// superclass of the current class type, potentially producing a
+ /// specialization of the superclass type. Produces a null type if
+ /// there is no superclass.
+ QualType getSuperClassType() const {
+ if (!CachedSuperClassType.getInt())
+ computeSuperClassTypeSlow();
+
+ assert(CachedSuperClassType.getInt() && "Superclass not set?");
+ return QualType(CachedSuperClassType.getPointer(), 0);
+ }
+
+ /// Strip off the Objective-C "kindof" type and (with it) any
+ /// protocol qualifiers.
+ QualType stripObjCKindOfTypeAndQuals(const ASTContext &ctx) const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCObject ||
+ T->getTypeClass() == ObjCInterface;
+ }
+};
+
+/// A class providing a concrete implementation
+/// of ObjCObjectType, so as to not increase the footprint of
+/// ObjCInterfaceType. Code outside of ASTContext and the core type
+/// system should not reference this type.
+class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode {
+ friend class ASTContext;
+
+ // If anyone adds fields here, ObjCObjectType::getProtocolStorage()
+ // will need to be modified.
+
+ ObjCObjectTypeImpl(QualType Canonical, QualType Base,
+ ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf)
+ : ObjCObjectType(Canonical, Base, typeArgs, protocols, isKindOf) {}
+
+public:
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ QualType Base,
+ ArrayRef<QualType> typeArgs,
+ ArrayRef<ObjCProtocolDecl *> protocols,
+ bool isKindOf);
+};
+
+inline QualType *ObjCObjectType::getTypeArgStorage() {
+ return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1);
+}
+
+inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() {
+ return reinterpret_cast<ObjCProtocolDecl**>(
+ getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
+}
+
+inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() {
+ return reinterpret_cast<ObjCProtocolDecl**>(
+ static_cast<ObjCTypeParamType*>(this)+1);
+}
+
+/// Interfaces are the core concept in Objective-C for object oriented design.
+/// They basically correspond to C++ classes. There are two kinds of interface
+/// types: normal interfaces like `NSString`, and qualified interfaces, which
+/// are qualified with a protocol list like `NSString<NSCopyable, NSAmazing>`.
+///
+/// ObjCInterfaceType guarantees the following properties when considered
+/// as a subtype of its superclass, ObjCObjectType:
+/// - There are no protocol qualifiers. To reinforce this, code which
+/// tries to invoke the protocol methods via an ObjCInterfaceType will
+/// fail to compile.
+/// - It is its own base type. That is, if T is an ObjCInterfaceType*,
+/// T->getBaseType() == QualType(T, 0).
+class ObjCInterfaceType : public ObjCObjectType {
+ friend class ASTContext; // ASTContext creates these.
+ friend class ASTReader;
+ template <class T> friend class serialization::AbstractTypeReader;
+
+ ObjCInterfaceDecl *Decl;
+
+ ObjCInterfaceType(const ObjCInterfaceDecl *D)
+ : ObjCObjectType(Nonce_ObjCInterface),
+ Decl(const_cast<ObjCInterfaceDecl*>(D)) {}
+
+public:
+ /// Get the declaration of this interface.
+ ObjCInterfaceDecl *getDecl() const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCInterface;
+ }
+
+ // Nonsense to "hide" certain members of ObjCObjectType within this
+ // class. People asking for protocols on an ObjCInterfaceType are
+ // not going to get what they want: ObjCInterfaceTypes are
+ // guaranteed to have no protocols.
+ enum {
+ qual_iterator,
+ qual_begin,
+ qual_end,
+ getNumProtocols,
+ getProtocol
+ };
+};
+
+inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const {
+ QualType baseType = getBaseType();
+ while (const auto *ObjT = baseType->getAs<ObjCObjectType>()) {
+ if (const auto *T = dyn_cast<ObjCInterfaceType>(ObjT))
+ return T->getDecl();
+
+ baseType = ObjT->getBaseType();
+ }
+
+ return nullptr;
+}
+
+/// Represents a pointer to an Objective C object.
+///
+/// These are constructed from pointer declarators when the pointee type is
+/// an ObjCObjectType (or sugar for one). In addition, the 'id' and 'Class'
+/// types are typedefs for these, and the protocol-qualified types 'id<P>'
+/// and 'Class<P>' are translated into these.
+///
+/// Pointers to pointers to Objective C objects are still PointerTypes;
+/// only the first level of pointer gets it own type implementation.
+class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType PointeeType;
+
+ ObjCObjectPointerType(QualType Canonical, QualType Pointee)
+ : Type(ObjCObjectPointer, Canonical, Pointee->getDependence()),
+ PointeeType(Pointee) {}
+
+public:
+ /// Gets the type pointed to by this ObjC pointer.
+ /// The result will always be an ObjCObjectType or sugar thereof.
+ QualType getPointeeType() const { return PointeeType; }
+
+ /// Gets the type pointed to by this ObjC pointer. Always returns non-null.
+ ///
+ /// This method is equivalent to getPointeeType() except that
+ /// it discards any typedefs (or other sugar) between this
+ /// type and the "outermost" object type. So for:
+ /// \code
+ /// \@class A; \@protocol P; \@protocol Q;
+ /// typedef A<P> AP;
+ /// typedef A A1;
+ /// typedef A1<P> A1P;
+ /// typedef A1P<Q> A1PQ;
+ /// \endcode
+ /// For 'A*', getObjectType() will return 'A'.
+ /// For 'A<P>*', getObjectType() will return 'A<P>'.
+ /// For 'AP*', getObjectType() will return 'A<P>'.
+ /// For 'A1*', getObjectType() will return 'A'.
+ /// For 'A1<P>*', getObjectType() will return 'A1<P>'.
+ /// For 'A1P*', getObjectType() will return 'A1<P>'.
+ /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because
+ /// adding protocols to a protocol-qualified base discards the
+ /// old qualifiers (for now). But if it didn't, getObjectType()
+ /// would return 'A1P<Q>' (and we'd have to make iterating over
+ /// qualifiers more complicated).
+ const ObjCObjectType *getObjectType() const {
+ return PointeeType->castAs<ObjCObjectType>();
+ }
+
+ /// If this pointer points to an Objective C
+ /// \@interface type, gets the type for that interface. Any protocol
+ /// qualifiers on the interface are ignored.
+ ///
+ /// \return null if the base type for this pointer is 'id' or 'Class'
+ const ObjCInterfaceType *getInterfaceType() const;
+
+ /// If this pointer points to an Objective \@interface
+ /// type, gets the declaration for that interface.
+ ///
+ /// \return null if the base type for this pointer is 'id' or 'Class'
+ ObjCInterfaceDecl *getInterfaceDecl() const {
+ return getObjectType()->getInterface();
+ }
+
+ /// True if this is equivalent to the 'id' type, i.e. if
+ /// its object type is the primitive 'id' type with no protocols.
+ bool isObjCIdType() const {
+ return getObjectType()->isObjCUnqualifiedId();
+ }
+
+ /// True if this is equivalent to the 'Class' type,
+ /// i.e. if its object tive is the primitive 'Class' type with no protocols.
+ bool isObjCClassType() const {
+ return getObjectType()->isObjCUnqualifiedClass();
+ }
+
+ /// True if this is equivalent to the 'id' or 'Class' type,
+ bool isObjCIdOrClassType() const {
+ return getObjectType()->isObjCUnqualifiedIdOrClass();
+ }
+
+ /// True if this is equivalent to 'id<P>' for some non-empty set of
+ /// protocols.
+ bool isObjCQualifiedIdType() const {
+ return getObjectType()->isObjCQualifiedId();
+ }
+
+ /// True if this is equivalent to 'Class<P>' for some non-empty set of
+ /// protocols.
+ bool isObjCQualifiedClassType() const {
+ return getObjectType()->isObjCQualifiedClass();
+ }
+
+ /// Whether this is a "__kindof" type.
+ bool isKindOfType() const { return getObjectType()->isKindOfType(); }
+
+ /// Whether this type is specialized, meaning that it has type arguments.
+ bool isSpecialized() const { return getObjectType()->isSpecialized(); }
+
+ /// Whether this type is specialized, meaning that it has type arguments.
+ bool isSpecializedAsWritten() const {
+ return getObjectType()->isSpecializedAsWritten();
+ }
+
+ /// Whether this type is unspecialized, meaning that is has no type arguments.
+ bool isUnspecialized() const { return getObjectType()->isUnspecialized(); }
+
+ /// Determine whether this object type is "unspecialized" as
+ /// written, meaning that it has no type arguments.
+ bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); }
+
+ /// Retrieve the type arguments for this type.
+ ArrayRef<QualType> getTypeArgs() const {
+ return getObjectType()->getTypeArgs();
+ }
+
+ /// Retrieve the type arguments for this type.
+ ArrayRef<QualType> getTypeArgsAsWritten() const {
+ return getObjectType()->getTypeArgsAsWritten();
+ }
+
+ /// An iterator over the qualifiers on the object type. Provided
+ /// for convenience. This will always iterate over the full set of
+ /// protocols on a type, not just those provided directly.
+ using qual_iterator = ObjCObjectType::qual_iterator;
+ using qual_range = llvm::iterator_range<qual_iterator>;
+
+ qual_range quals() const { return qual_range(qual_begin(), qual_end()); }
+
+ qual_iterator qual_begin() const {
+ return getObjectType()->qual_begin();
+ }
+
+ qual_iterator qual_end() const {
+ return getObjectType()->qual_end();
+ }
+
+ bool qual_empty() const { return getObjectType()->qual_empty(); }
+
+ /// Return the number of qualifying protocols on the object type.
+ unsigned getNumProtocols() const {
+ return getObjectType()->getNumProtocols();
+ }
+
+ /// Retrieve a qualifying protocol by index on the object type.
+ ObjCProtocolDecl *getProtocol(unsigned I) const {
+ return getObjectType()->getProtocol(I);
+ }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ /// Retrieve the type of the superclass of this object pointer type.
+ ///
+ /// This operation substitutes any type arguments into the
+ /// superclass of the current class type, potentially producing a
+ /// pointer to a specialization of the superclass type. Produces a
+ /// null type if there is no superclass.
+ QualType getSuperClassType() const;
+
+ /// Strip off the Objective-C "kindof" type and (with it) any
+ /// protocol qualifiers.
+ const ObjCObjectPointerType *stripObjCKindOfTypeAndQuals(
+ const ASTContext &ctx) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getPointeeType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCObjectPointer;
+ }
+};
+
+class AtomicType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType ValueType;
+
+ AtomicType(QualType ValTy, QualType Canonical)
+ : Type(Atomic, Canonical, ValTy->getDependence()), ValueType(ValTy) {}
+
+public:
+ /// Gets the type contained by this atomic type, i.e.
+ /// the type returned by performing an atomic load of this atomic type.
+ QualType getValueType() const { return ValueType; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getValueType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Atomic;
+ }
+};
+
+/// PipeType - OpenCL20.
+class PipeType : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext; // ASTContext creates these.
+
+ QualType ElementType;
+ bool isRead;
+
+ PipeType(QualType elemType, QualType CanonicalPtr, bool isRead)
+ : Type(Pipe, CanonicalPtr, elemType->getDependence()),
+ ElementType(elemType), isRead(isRead) {}
+
+public:
+ QualType getElementType() const { return ElementType; }
+
+ bool isSugared() const { return false; }
+
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType(), isReadOnly());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ ID.AddBoolean(isRead);
+ }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Pipe;
+ }
+
+ bool isReadOnly() const { return isRead; }
+};
+
+/// A fixed int type of a specified bitwidth.
+class BitIntType final : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsUnsigned : 1;
+ unsigned NumBits : 24;
+
+protected:
+ BitIntType(bool isUnsigned, unsigned NumBits);
+
+public:
+ bool isUnsigned() const { return IsUnsigned; }
+ bool isSigned() const { return !IsUnsigned; }
+ unsigned getNumBits() const { return NumBits; }
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, isUnsigned(), getNumBits());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, bool IsUnsigned,
+ unsigned NumBits) {
+ ID.AddBoolean(IsUnsigned);
+ ID.AddInteger(NumBits);
+ }
+
+ static bool classof(const Type *T) { return T->getTypeClass() == BitInt; }
+};
+
+class DependentBitIntType final : public Type, public llvm::FoldingSetNode {
+ friend class ASTContext;
+ llvm::PointerIntPair<Expr*, 1, bool> ExprAndUnsigned;
+
+protected:
+ DependentBitIntType(bool IsUnsigned, Expr *NumBits);
+
+public:
+ bool isUnsigned() const;
+ bool isSigned() const { return !isUnsigned(); }
+ Expr *getNumBitsExpr() const;
+
+ bool isSugared() const { return false; }
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, isUnsigned(), getNumBitsExpr());
+ }
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ bool IsUnsigned, Expr *NumBitsExpr);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == DependentBitInt;
+ }
+};
+
+class PredefinedSugarType final : public Type {
+public:
+ friend class ASTContext;
+ using Kind = PredefinedSugarKind;
+
+private:
+ PredefinedSugarType(Kind KD, const IdentifierInfo *IdentName,
+ QualType CanonicalType)
+ : Type(PredefinedSugar, CanonicalType, TypeDependence::None),
+ Name(IdentName) {
+ PredefinedSugarTypeBits.Kind = llvm::to_underlying(KD);
+ }
+
+ static StringRef getName(Kind KD);
+
+ const IdentifierInfo *Name;
+
+public:
+ bool isSugared() const { return true; }
+
+ QualType desugar() const { return getCanonicalTypeInternal(); }
+
+ Kind getKind() const { return Kind(PredefinedSugarTypeBits.Kind); }
+
+ const IdentifierInfo *getIdentifier() const { return Name; }
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == PredefinedSugar;
+ }
+};
+
+/// A qualifier set is used to build a set of qualifiers.
+class QualifierCollector : public Qualifiers {
+public:
+ QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {}
+
+ /// Collect any qualifiers on the given type and return an
+ /// unqualified type. The qualifiers are assumed to be consistent
+ /// with those already in the type.
+ const Type *strip(QualType type) {
+ addFastQualifiers(type.getLocalFastQualifiers());
+ if (!type.hasLocalNonFastQualifiers())
+ return type.getTypePtrUnsafe();
+
+ const ExtQuals *extQuals = type.getExtQualsUnsafe();
+ addConsistentQualifiers(extQuals->getQualifiers());
+ return extQuals->getBaseType();
+ }
+
+ /// Apply the collected qualifiers to the given type.
+ QualType apply(const ASTContext &Context, QualType QT) const;
+
+ /// Apply the collected qualifiers to the given type.
+ QualType apply(const ASTContext &Context, const Type* T) const;
+};
+
+/// A container of type source information.
+///
+/// A client can read the relevant info using TypeLoc wrappers, e.g:
+/// @code
+/// TypeLoc TL = TypeSourceInfo->getTypeLoc();
+/// TL.getBeginLoc().print(OS, SrcMgr);
+/// @endcode
+class alignas(8) TypeSourceInfo {
+ // Contains a memory block after the class, used for type source information,
+ // allocated by ASTContext.
+ friend class ASTContext;
+
+ QualType Ty;
+
+ TypeSourceInfo(QualType ty, size_t DataSize); // implemented in TypeLoc.h
+
+public:
+ /// Return the type wrapped by this type source info.
+ QualType getType() const { return Ty; }
+
+ /// Return the TypeLoc wrapper for the type source info.
+ TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
+
+ /// Override the type stored in this TypeSourceInfo. Use with caution!
+ void overrideType(QualType T) { Ty = T; }
+};
+
+// Inline function definitions.
+
+inline SplitQualType SplitQualType::getSingleStepDesugaredType() const {
+ SplitQualType desugar =
+ Ty->getLocallyUnqualifiedSingleStepDesugaredType().split();
+ desugar.Quals.addConsistentQualifiers(Quals);
+ return desugar;
+}
+
+inline const Type *QualType::getTypePtr() const {
+ return getCommonPtr()->BaseType;
+}
+
+inline const Type *QualType::getTypePtrOrNull() const {
+ return (isNull() ? nullptr : getCommonPtr()->BaseType);
+}
+
+inline bool QualType::isReferenceable() const {
+ // C++ [defns.referenceable]
+ // type that is either an object type, a function type that does not have
+ // cv-qualifiers or a ref-qualifier, or a reference type.
+ const Type &Self = **this;
+ if (Self.isObjectType() || Self.isReferenceType())
+ return true;
+ if (const auto *F = Self.getAs<FunctionProtoType>())
+ return F->getMethodQuals().empty() && F->getRefQualifier() == RQ_None;
+
+ return false;
+}
+
+inline SplitQualType QualType::split() const {
+ if (!hasLocalNonFastQualifiers())
+ return SplitQualType(getTypePtrUnsafe(),
+ Qualifiers::fromFastMask(getLocalFastQualifiers()));
+
+ const ExtQuals *eq = getExtQualsUnsafe();
+ Qualifiers qs = eq->getQualifiers();
+ qs.addFastQualifiers(getLocalFastQualifiers());
+ return SplitQualType(eq->getBaseType(), qs);
+}
+
+inline Qualifiers QualType::getLocalQualifiers() const {
+ Qualifiers Quals;
+ if (hasLocalNonFastQualifiers())
+ Quals = getExtQualsUnsafe()->getQualifiers();
+ Quals.addFastQualifiers(getLocalFastQualifiers());
+ return Quals;
+}
+
+inline Qualifiers QualType::getQualifiers() const {
+ Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers();
+ quals.addFastQualifiers(getLocalFastQualifiers());
+ return quals;
+}
+
+inline unsigned QualType::getCVRQualifiers() const {
+ unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers();
+ cvr |= getLocalCVRQualifiers();
+ return cvr;
+}
+
+inline QualType QualType::getCanonicalType() const {
+ QualType canon = getCommonPtr()->CanonicalType;
+ return canon.withFastQualifiers(getLocalFastQualifiers());
+}
+
+inline bool QualType::isCanonical() const {
+ return getTypePtr()->isCanonicalUnqualified();
+}
+
+inline bool QualType::isCanonicalAsParam() const {
+ if (!isCanonical()) return false;
+ if (hasLocalQualifiers()) return false;
+
+ const Type *T = getTypePtr();
+ if (T->isVariablyModifiedType() && T->hasSizedVLAType())
+ return false;
+
+ return !isa<FunctionType>(T) &&
+ (!isa<ArrayType>(T) || isa<ArrayParameterType>(T));
+}
+
+inline bool QualType::isConstQualified() const {
+ return isLocalConstQualified() ||
+ getCommonPtr()->CanonicalType.isLocalConstQualified();
+}
+
+inline bool QualType::isRestrictQualified() const {
+ return isLocalRestrictQualified() ||
+ getCommonPtr()->CanonicalType.isLocalRestrictQualified();
+}
+
+
+inline bool QualType::isVolatileQualified() const {
+ return isLocalVolatileQualified() ||
+ getCommonPtr()->CanonicalType.isLocalVolatileQualified();
+}
+
+inline bool QualType::hasQualifiers() const {
+ return hasLocalQualifiers() ||
+ getCommonPtr()->CanonicalType.hasLocalQualifiers();
+}
+
+inline QualType QualType::getUnqualifiedType() const {
+ if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
+ return QualType(getTypePtr(), 0);
+
+ return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0);
+}
+
+inline SplitQualType QualType::getSplitUnqualifiedType() const {
+ if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers())
+ return split();
+
+ return getSplitUnqualifiedTypeImpl(*this);
+}
+
+inline void QualType::removeLocalConst() {
+ removeLocalFastQualifiers(Qualifiers::Const);
+}
+
+inline void QualType::removeLocalRestrict() {
+ removeLocalFastQualifiers(Qualifiers::Restrict);
+}
+
+inline void QualType::removeLocalVolatile() {
+ removeLocalFastQualifiers(Qualifiers::Volatile);
+}
+
+/// Check if this type has any address space qualifier.
+inline bool QualType::hasAddressSpace() const {
+ return getQualifiers().hasAddressSpace();
+}
+
+/// Return the address space of this type.
+inline LangAS QualType::getAddressSpace() const {
+ return getQualifiers().getAddressSpace();
+}
+
+/// Return the gc attribute of this type.
+inline Qualifiers::GC QualType::getObjCGCAttr() const {
+ return getQualifiers().getObjCGCAttr();
+}
+
+inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) {
+ if (const auto *PT = t.getAs<PointerType>()) {
+ if (const auto *FT = PT->getPointeeType()->getAs<FunctionType>())
+ return FT->getExtInfo();
+ } else if (const auto *FT = t.getAs<FunctionType>())
+ return FT->getExtInfo();
+
+ return FunctionType::ExtInfo();
+}
+
+inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) {
+ return getFunctionExtInfo(*t);
+}
+
+/// Determine whether this type is more
+/// qualified than the Other type. For example, "const volatile int"
+/// is more qualified than "const int", "volatile int", and
+/// "int". However, it is not more qualified than "const volatile
+/// int".
+inline bool QualType::isMoreQualifiedThan(QualType other,
+ const ASTContext &Ctx) const {
+ Qualifiers MyQuals = getQualifiers();
+ Qualifiers OtherQuals = other.getQualifiers();
+ return (MyQuals != OtherQuals && MyQuals.compatiblyIncludes(OtherQuals, Ctx));
+}
+
+/// Determine whether this type is at last
+/// as qualified as the Other type. For example, "const volatile
+/// int" is at least as qualified as "const int", "volatile int",
+/// "int", and "const volatile int".
+inline bool QualType::isAtLeastAsQualifiedAs(QualType other,
+ const ASTContext &Ctx) const {
+ Qualifiers OtherQuals = other.getQualifiers();
+
+ // Ignore __unaligned qualifier if this type is a void.
+ if (getUnqualifiedType()->isVoidType())
+ OtherQuals.removeUnaligned();
+
+ return getQualifiers().compatiblyIncludes(OtherQuals, Ctx);
+}
+
+/// If Type is a reference type (e.g., const
+/// int&), returns the type that the reference refers to ("const
+/// int"). Otherwise, returns the type itself. This routine is used
+/// throughout Sema to implement C++ 5p6:
+///
+/// If an expression initially has the type "reference to T" (8.3.2,
+/// 8.5.3), the type is adjusted to "T" prior to any further
+/// analysis, the expression designates the object or function
+/// denoted by the reference, and the expression is an lvalue.
+inline QualType QualType::getNonReferenceType() const {
+ if (const auto *RefType = (*this)->getAs<ReferenceType>())
+ return RefType->getPointeeType();
+ else
+ return *this;
+}
+
+inline bool QualType::isCForbiddenLValueType() const {
+ return ((getTypePtr()->isVoidType() && !hasQualifiers()) ||
+ getTypePtr()->isFunctionType());
+}
+
+/// Tests whether the type is categorized as a fundamental type.
+///
+/// \returns True for types specified in C++0x [basic.fundamental].
+inline bool Type::isFundamentalType() const {
+ return isVoidType() ||
+ isNullPtrType() ||
+ // FIXME: It's really annoying that we don't have an
+ // 'isArithmeticType()' which agrees with the standard definition.
+ (isArithmeticType() && !isEnumeralType());
+}
+
+/// Tests whether the type is categorized as a compound type.
+///
+/// \returns True for types specified in C++0x [basic.compound].
+inline bool Type::isCompoundType() const {
+ // C++0x [basic.compound]p1:
+ // Compound types can be constructed in the following ways:
+ // -- arrays of objects of a given type [...];
+ return isArrayType() ||
+ // -- functions, which have parameters of given types [...];
+ isFunctionType() ||
+ // -- pointers to void or objects or functions [...];
+ isPointerType() ||
+ // -- references to objects or functions of a given type. [...]
+ isReferenceType() ||
+ // -- classes containing a sequence of objects of various types, [...];
+ isRecordType() ||
+ // -- unions, which are classes capable of containing objects of different
+ // types at different times;
+ isUnionType() ||
+ // -- enumerations, which comprise a set of named constant values. [...];
+ isEnumeralType() ||
+ // -- pointers to non-static class members, [...].
+ isMemberPointerType();
+}
+
+inline bool Type::isFunctionType() const {
+ return isa<FunctionType>(CanonicalType);
+}
+
+inline bool Type::isPointerType() const {
+ return isa<PointerType>(CanonicalType);
+}
+
+inline bool Type::isPointerOrReferenceType() const {
+ return isPointerType() || isReferenceType();
+}
+
+inline bool Type::isAnyPointerType() const {
+ return isPointerType() || isObjCObjectPointerType();
+}
+
+inline bool Type::isSignableType(const ASTContext &Ctx) const {
+ return isSignablePointerType() || isSignableIntegerType(Ctx);
+}
+
+inline bool Type::isSignablePointerType() const {
+ return isPointerType() || isObjCClassType() || isObjCQualifiedClassType();
+}
+
+inline bool Type::isBlockPointerType() const {
+ return isa<BlockPointerType>(CanonicalType);
+}
+
+inline bool Type::isReferenceType() const {
+ return isa<ReferenceType>(CanonicalType);
+}
+
+inline bool Type::isLValueReferenceType() const {
+ return isa<LValueReferenceType>(CanonicalType);
+}
+
+inline bool Type::isRValueReferenceType() const {
+ return isa<RValueReferenceType>(CanonicalType);
+}
+
+inline bool Type::isObjectPointerType() const {
+ // Note: an "object pointer type" is not the same thing as a pointer to an
+ // object type; rather, it is a pointer to an object type or a pointer to cv
+ // void.
+ if (const auto *T = getAs<PointerType>())
+ return !T->getPointeeType()->isFunctionType();
+ else
+ return false;
+}
+
+inline bool Type::isCFIUncheckedCalleeFunctionType() const {
+ if (const auto *Fn = getAs<FunctionProtoType>())
+ return Fn->hasCFIUncheckedCallee();
+ return false;
+}
+
+inline bool Type::hasPointeeToToCFIUncheckedCalleeFunctionType() const {
+ QualType Pointee;
+ if (const auto *PT = getAs<PointerType>())
+ Pointee = PT->getPointeeType();
+ else if (const auto *RT = getAs<ReferenceType>())
+ Pointee = RT->getPointeeType();
+ else if (const auto *MPT = getAs<MemberPointerType>())
+ Pointee = MPT->getPointeeType();
+ else if (const auto *DT = getAs<DecayedType>())
+ Pointee = DT->getPointeeType();
+ else
+ return false;
+ return Pointee->isCFIUncheckedCalleeFunctionType();
+}
+
+inline bool Type::isFunctionPointerType() const {
+ if (const auto *T = getAs<PointerType>())
+ return T->getPointeeType()->isFunctionType();
+ else
+ return false;
+}
+
+inline bool Type::isFunctionReferenceType() const {
+ if (const auto *T = getAs<ReferenceType>())
+ return T->getPointeeType()->isFunctionType();
+ else
+ return false;
+}
+
+inline bool Type::isMemberPointerType() const {
+ return isa<MemberPointerType>(CanonicalType);
+}
+
+inline bool Type::isMemberFunctionPointerType() const {
+ if (const auto *T = getAs<MemberPointerType>())
+ return T->isMemberFunctionPointer();
+ else
+ return false;
+}
+
+inline bool Type::isMemberDataPointerType() const {
+ if (const auto *T = getAs<MemberPointerType>())
+ return T->isMemberDataPointer();
+ else
+ return false;
+}
+
+inline bool Type::isArrayType() const {
+ return isa<ArrayType>(CanonicalType);
+}
+
+inline bool Type::isConstantArrayType() const {
+ return isa<ConstantArrayType>(CanonicalType);
+}
+
+inline bool Type::isIncompleteArrayType() const {
+ return isa<IncompleteArrayType>(CanonicalType);
+}
+
+inline bool Type::isVariableArrayType() const {
+ return isa<VariableArrayType>(CanonicalType);
+}
+
+inline bool Type::isArrayParameterType() const {
+ return isa<ArrayParameterType>(CanonicalType);
+}
+
+inline bool Type::isDependentSizedArrayType() const {
+ return isa<DependentSizedArrayType>(CanonicalType);
+}
+
+inline bool Type::isBuiltinType() const {
+ return isa<BuiltinType>(CanonicalType);
+}
+
+inline bool Type::isRecordType() const {
+ return isa<RecordType>(CanonicalType);
+}
+
+inline bool Type::isEnumeralType() const {
+ return isa<EnumType>(CanonicalType);
+}
+
+inline bool Type::isAnyComplexType() const {
+ return isa<ComplexType>(CanonicalType);
+}
+
+inline bool Type::isVectorType() const {
+ return isa<VectorType>(CanonicalType);
+}
+
+inline bool Type::isExtVectorType() const {
+ return isa<ExtVectorType>(CanonicalType);
+}
+
+inline bool Type::isExtVectorBoolType() const {
+ if (!isExtVectorType())
+ return false;
+ return cast<ExtVectorType>(CanonicalType)->getElementType()->isBooleanType();
+}
+
+inline bool Type::isSubscriptableVectorType() const {
+ return isVectorType() || isSveVLSBuiltinType();
+}
+
+inline bool Type::isMatrixType() const {
+ return isa<MatrixType>(CanonicalType);
+}
+
+inline bool Type::isConstantMatrixType() const {
+ return isa<ConstantMatrixType>(CanonicalType);
+}
+
+inline bool Type::isDependentAddressSpaceType() const {
+ return isa<DependentAddressSpaceType>(CanonicalType);
+}
+
+inline bool Type::isObjCObjectPointerType() const {
+ return isa<ObjCObjectPointerType>(CanonicalType);
+}
+
+inline bool Type::isObjCObjectType() const {
+ return isa<ObjCObjectType>(CanonicalType);
+}
+
+inline bool Type::isObjCObjectOrInterfaceType() const {
+ return isa<ObjCInterfaceType>(CanonicalType) ||
+ isa<ObjCObjectType>(CanonicalType);
+}
+
+inline bool Type::isAtomicType() const {
+ return isa<AtomicType>(CanonicalType);
+}
+
+inline bool Type::isUndeducedAutoType() const {
+ return isa<AutoType>(CanonicalType);
+}
+
+inline bool Type::isObjCQualifiedIdType() const {
+ if (const auto *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCQualifiedIdType();
+ return false;
+}
+
+inline bool Type::isObjCQualifiedClassType() const {
+ if (const auto *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCQualifiedClassType();
+ return false;
+}
+
+inline bool Type::isObjCIdType() const {
+ if (const auto *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCIdType();
+ return false;
+}
+
+inline bool Type::isObjCClassType() const {
+ if (const auto *OPT = getAs<ObjCObjectPointerType>())
+ return OPT->isObjCClassType();
+ return false;
+}
+
+inline bool Type::isObjCSelType() const {
+ if (const auto *OPT = getAs<PointerType>())
+ return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel);
+ return false;
+}
+
+inline bool Type::isObjCBuiltinType() const {
+ return isObjCIdType() || isObjCClassType() || isObjCSelType();
+}
+
+inline bool Type::isDecltypeType() const {
+ return isa<DecltypeType>(this);
+}
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
+ }
+#include "clang/Basic/OpenCLImageTypes.def"
+
+inline bool Type::isSamplerT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLSampler);
+}
+
+inline bool Type::isEventT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLEvent);
+}
+
+inline bool Type::isClkEventT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLClkEvent);
+}
+
+inline bool Type::isQueueT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLQueue);
+}
+
+inline bool Type::isReserveIDT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLReserveID);
+}
+
+inline bool Type::isImageType() const {
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) is##Id##Type() ||
+ return
+#include "clang/Basic/OpenCLImageTypes.def"
+ false; // end boolean or operation
+}
+
+inline bool Type::isPipeType() const {
+ return isa<PipeType>(CanonicalType);
+}
+
+inline bool Type::isBitIntType() const {
+ return isa<BitIntType>(CanonicalType);
+}
+
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
+ }
+#include "clang/Basic/OpenCLExtensionTypes.def"
+
+inline bool Type::isOCLIntelSubgroupAVCType() const {
+#define INTEL_SUBGROUP_AVC_TYPE(ExtType, Id) \
+ isOCLIntelSubgroupAVC##Id##Type() ||
+ return
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ false; // end of boolean or operation
+}
+
+inline bool Type::isOCLExtOpaqueType() const {
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) is##Id##Type() ||
+ return
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ false; // end of boolean or operation
+}
+
+inline bool Type::isOpenCLSpecificType() const {
+ return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
+ isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType();
+}
+
+#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \
+ inline bool Type::is##Id##Type() const { \
+ return isSpecificBuiltinType(BuiltinType::Id); \
+ }
+#include "clang/Basic/HLSLIntangibleTypes.def"
+
+inline bool Type::isHLSLBuiltinIntangibleType() const {
+#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) is##Id##Type() ||
+ return
+#include "clang/Basic/HLSLIntangibleTypes.def"
+ false;
+}
+
+inline bool Type::isHLSLSpecificType() const {
+ return isHLSLBuiltinIntangibleType() || isHLSLAttributedResourceType() ||
+ isHLSLInlineSpirvType();
+}
+
+inline bool Type::isHLSLAttributedResourceType() const {
+ return isa<HLSLAttributedResourceType>(this);
+}
+
+inline bool Type::isHLSLInlineSpirvType() const {
+ return isa<HLSLInlineSpirvType>(this);
+}
+
+inline bool Type::isTemplateTypeParmType() const {
+ return isa<TemplateTypeParmType>(CanonicalType);
+}
+
+inline bool Type::isSpecificBuiltinType(unsigned K) const {
+ if (const BuiltinType *BT = getAs<BuiltinType>()) {
+ return BT->getKind() == static_cast<BuiltinType::Kind>(K);
+ }
+ return false;
+}
+
+inline bool Type::isPlaceholderType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(this))
+ return BT->isPlaceholderType();
+ return false;
+}
+
+inline const BuiltinType *Type::getAsPlaceholderType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(this))
+ if (BT->isPlaceholderType())
+ return BT;
+ return nullptr;
+}
+
+inline bool Type::isSpecificPlaceholderType(unsigned K) const {
+ assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K));
+ return isSpecificBuiltinType(K);
+}
+
+inline bool Type::isNonOverloadPlaceholderType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(this))
+ return BT->isNonOverloadPlaceholderType();
+ return false;
+}
+
+inline bool Type::isVoidType() const {
+ return isSpecificBuiltinType(BuiltinType::Void);
+}
+
+inline bool Type::isHalfType() const {
+ // FIXME: Should we allow complex __fp16? Probably not.
+ return isSpecificBuiltinType(BuiltinType::Half);
+}
+
+inline bool Type::isFloat16Type() const {
+ return isSpecificBuiltinType(BuiltinType::Float16);
+}
+
+inline bool Type::isFloat32Type() const {
+ return isSpecificBuiltinType(BuiltinType::Float);
+}
+
+inline bool Type::isDoubleType() const {
+ return isSpecificBuiltinType(BuiltinType::Double);
+}
+
+inline bool Type::isBFloat16Type() const {
+ return isSpecificBuiltinType(BuiltinType::BFloat16);
+}
+
+inline bool Type::isMFloat8Type() const {
+ return isSpecificBuiltinType(BuiltinType::MFloat8);
+}
+
+inline bool Type::isFloat128Type() const {
+ return isSpecificBuiltinType(BuiltinType::Float128);
+}
+
+inline bool Type::isIbm128Type() const {
+ return isSpecificBuiltinType(BuiltinType::Ibm128);
+}
+
+inline bool Type::isNullPtrType() const {
+ return isSpecificBuiltinType(BuiltinType::NullPtr);
+}
+
+bool IsEnumDeclComplete(EnumDecl *);
+bool IsEnumDeclScoped(EnumDecl *);
+
+inline bool Type::isIntegerType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->isInteger();
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ return IsEnumDeclComplete(ET->getOriginalDecl()) &&
+ !IsEnumDeclScoped(ET->getOriginalDecl());
+ }
+ return isBitIntType();
+}
+
+inline bool Type::isFixedPointType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::ShortAccum &&
+ BT->getKind() <= BuiltinType::SatULongFract;
+ }
+ return false;
+}
+
+inline bool Type::isFixedPointOrIntegerType() const {
+ return isFixedPointType() || isIntegerType();
+}
+
+inline bool Type::isConvertibleToFixedPointType() const {
+ return isRealFloatingType() || isFixedPointOrIntegerType();
+}
+
+inline bool Type::isSaturatedFixedPointType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return BT->getKind() >= BuiltinType::SatShortAccum &&
+ BT->getKind() <= BuiltinType::SatULongFract;
+ }
+ return false;
+}
+
+inline bool Type::isUnsaturatedFixedPointType() const {
+ return isFixedPointType() && !isSaturatedFixedPointType();
+}
+
+inline bool Type::isSignedFixedPointType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) {
+ return ((BT->getKind() >= BuiltinType::ShortAccum &&
+ BT->getKind() <= BuiltinType::LongAccum) ||
+ (BT->getKind() >= BuiltinType::ShortFract &&
+ BT->getKind() <= BuiltinType::LongFract) ||
+ (BT->getKind() >= BuiltinType::SatShortAccum &&
+ BT->getKind() <= BuiltinType::SatLongAccum) ||
+ (BT->getKind() >= BuiltinType::SatShortFract &&
+ BT->getKind() <= BuiltinType::SatLongFract));
+ }
+ return false;
+}
+
+inline bool Type::isUnsignedFixedPointType() const {
+ return isFixedPointType() && !isSignedFixedPointType();
+}
+
+inline bool Type::isScalarType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() > BuiltinType::Void &&
+ BT->getKind() <= BuiltinType::NullPtr;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ // Enums are scalar types, but only if they are defined. Incomplete enums
+ // are not treated as scalar types.
+ return IsEnumDeclComplete(ET->getOriginalDecl());
+ return isa<PointerType>(CanonicalType) ||
+ isa<BlockPointerType>(CanonicalType) ||
+ isa<MemberPointerType>(CanonicalType) ||
+ isa<ComplexType>(CanonicalType) ||
+ isa<ObjCObjectPointerType>(CanonicalType) ||
+ isBitIntType();
+}
+
+inline bool Type::isIntegralOrEnumerationType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->isInteger();
+
+ // Check for a complete enum type; incomplete enum types are not properly an
+ // enumeration type in the sense required here.
+ if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
+ return IsEnumDeclComplete(ET->getOriginalDecl());
+
+ return isBitIntType();
+}
+
+inline bool Type::isBooleanType() const {
+ if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() == BuiltinType::Bool;
+ return false;
+}
+
+inline bool Type::isUndeducedType() const {
+ auto *DT = getContainedDeducedType();
+ return DT && !DT->isDeduced();
+}
+
+/// Determines whether this is a type for which one can define
+/// an overloaded operator.
+inline bool Type::isOverloadableType() const {
+ if (!isDependentType())
+ return isRecordType() || isEnumeralType();
+ return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
+ !isMemberPointerType();
+}
+
+/// Determines whether this type is written as a typedef-name.
+inline bool Type::isTypedefNameType() const {
+ if (getAs<TypedefType>())
+ return true;
+ if (auto *TST = getAs<TemplateSpecializationType>())
+ return TST->isTypeAlias();
+ return false;
+}
+
+/// Determines whether this type can decay to a pointer type.
+inline bool Type::canDecayToPointerType() const {
+ return isFunctionType() || (isArrayType() && !isArrayParameterType());
+}
+
+inline bool Type::hasPointerRepresentation() const {
+ return (isPointerType() || isReferenceType() || isBlockPointerType() ||
+ isObjCObjectPointerType() || isNullPtrType());
+}
+
+inline bool Type::hasObjCPointerRepresentation() const {
+ return isObjCObjectPointerType();
+}
+
+inline const Type *Type::getBaseElementTypeUnsafe() const {
+ const Type *type = this;
+ while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe())
+ type = arrayType->getElementType().getTypePtr();
+ return type;
+}
+
+inline const Type *Type::getPointeeOrArrayElementType() const {
+ const Type *type = this;
+ if (type->isAnyPointerType())
+ return type->getPointeeType().getTypePtr();
+ else if (type->isArrayType())
+ return type->getBaseElementTypeUnsafe();
+ return type;
+}
+/// Insertion operator for partial diagnostics. This allows sending adress
+/// spaces into a diagnostic with <<.
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+ LangAS AS) {
+ PD.AddTaggedVal(llvm::to_underlying(AS),
+ DiagnosticsEngine::ArgumentKind::ak_addrspace);
+ return PD;
+}
+
+/// Insertion operator for partial diagnostics. This allows sending Qualifiers
+/// into a diagnostic with <<.
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+ Qualifiers Q) {
+ PD.AddTaggedVal(Q.getAsOpaqueValue(),
+ DiagnosticsEngine::ArgumentKind::ak_qual);
+ return PD;
+}
+
+/// Insertion operator for partial diagnostics. This allows sending QualType's
+/// into a diagnostic with <<.
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+ QualType T) {
+ PD.AddTaggedVal(reinterpret_cast<uint64_t>(T.getAsOpaquePtr()),
+ DiagnosticsEngine::ak_qualtype);
+ return PD;
+}
+
+// Helper class template that is used by Type::getAs to ensure that one does
+// not try to look through a qualified type to get to an array type.
+template <typename T>
+using TypeIsArrayType =
+ std::integral_constant<bool, std::is_same<T, ArrayType>::value ||
+ std::is_base_of<ArrayType, T>::value>;
+
+// Member-template getAs<specific type>'.
+template <typename T> const T *Type::getAs() const {
+ static_assert(!TypeIsArrayType<T>::value,
+ "ArrayType cannot be used with getAs!");
+
+ // If this is directly a T type, return it.
+ if (const auto *Ty = dyn_cast<T>(this))
+ return Ty;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<T>(CanonicalType))
+ return nullptr;
+
+ // If this is a typedef for the type, strip the typedef off without
+ // losing all typedef information.
+ return cast<T>(getUnqualifiedDesugaredType());
+}
+
+template <typename T> const T *Type::getAsAdjusted() const {
+ static_assert(!TypeIsArrayType<T>::value, "ArrayType cannot be used with getAsAdjusted!");
+
+ // If this is directly a T type, return it.
+ if (const auto *Ty = dyn_cast<T>(this))
+ return Ty;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<T>(CanonicalType))
+ return nullptr;
+
+ // Strip off type adjustments that do not modify the underlying nature of the
+ // type.
+ const Type *Ty = this;
+ while (Ty) {
+ if (const auto *A = dyn_cast<AttributedType>(Ty))
+ Ty = A->getModifiedType().getTypePtr();
+ else if (const auto *A = dyn_cast<BTFTagAttributedType>(Ty))
+ Ty = A->getWrappedType().getTypePtr();
+ else if (const auto *A = dyn_cast<HLSLAttributedResourceType>(Ty))
+ Ty = A->getWrappedType().getTypePtr();
+ else if (const auto *P = dyn_cast<ParenType>(Ty))
+ Ty = P->desugar().getTypePtr();
+ else if (const auto *A = dyn_cast<AdjustedType>(Ty))
+ Ty = A->desugar().getTypePtr();
+ else if (const auto *M = dyn_cast<MacroQualifiedType>(Ty))
+ Ty = M->desugar().getTypePtr();
+ else
+ break;
+ }
+
+ // Just because the canonical type is correct does not mean we can use cast<>,
+ // since we may not have stripped off all the sugar down to the base type.
+ return dyn_cast<T>(Ty);
+}
+
+inline const ArrayType *Type::getAsArrayTypeUnsafe() const {
+ // If this is directly an array type, return it.
+ if (const auto *arr = dyn_cast<ArrayType>(this))
+ return arr;
+
+ // If the canonical form of this type isn't the right kind, reject it.
+ if (!isa<ArrayType>(CanonicalType))
+ return nullptr;
+
+ // If this is a typedef for the type, strip the typedef off without
+ // losing all typedef information.
+ return cast<ArrayType>(getUnqualifiedDesugaredType());
+}
+
+template <typename T> const T *Type::castAs() const {
+ static_assert(!TypeIsArrayType<T>::value,
+ "ArrayType cannot be used with castAs!");
+
+ if (const auto *ty = dyn_cast<T>(this)) return ty;
+ assert(isa<T>(CanonicalType));
+ return cast<T>(getUnqualifiedDesugaredType());
+}
+
+inline const ArrayType *Type::castAsArrayTypeUnsafe() const {
+ assert(isa<ArrayType>(CanonicalType));
+ if (const auto *arr = dyn_cast<ArrayType>(this)) return arr;
+ return cast<ArrayType>(getUnqualifiedDesugaredType());
+}
+
+DecayedType::DecayedType(QualType OriginalType, QualType DecayedPtr,
+ QualType CanonicalPtr)
+ : AdjustedType(Decayed, OriginalType, DecayedPtr, CanonicalPtr) {
+#ifndef NDEBUG
+ QualType Adjusted = getAdjustedType();
+ (void)AttributedType::stripOuterNullability(Adjusted);
+ assert(isa<PointerType>(Adjusted));
+#endif
+}
+
+QualType DecayedType::getPointeeType() const {
+ QualType Decayed = getDecayedType();
+ (void)AttributedType::stripOuterNullability(Decayed);
+ return cast<PointerType>(Decayed)->getPointeeType();
+}
+
+// Get the decimal string representation of a fixed point type, represented
+// as a scaled integer.
+// TODO: At some point, we should change the arguments to instead just accept an
+// APFixedPoint instead of APSInt and scale.
+void FixedPointValueToString(SmallVectorImpl<char> &Str, llvm::APSInt Val,
+ unsigned Scale);
+
+inline FunctionEffectsRef FunctionEffectsRef::get(QualType QT) {
+ const Type *TypePtr = QT.getTypePtr();
+ while (true) {
+ if (QualType Pointee = TypePtr->getPointeeType(); !Pointee.isNull())
+ TypePtr = Pointee.getTypePtr();
+ else if (TypePtr->isArrayType())
+ TypePtr = TypePtr->getBaseElementTypeUnsafe();
+ else
+ break;
+ }
+ if (const auto *FPT = TypePtr->getAs<FunctionProtoType>())
+ return FPT->getFunctionEffects();
+ return {};
+}
+
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_TYPE_BASE_H
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index 52ef7ac..d52e104 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -16,9 +16,9 @@
#include "clang/AST/ASTConcept.h"
#include "clang/AST/DeclarationName.h"
-#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/NestedNameSpecifierBase.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
@@ -193,6 +193,21 @@ public:
/// Get the SourceLocation of the template keyword (if any).
SourceLocation getTemplateKeywordLoc() const;
+ /// If this type represents a qualified-id, this returns it's nested name
+ /// specifier. For example, for the qualified-id "foo::bar::baz", this returns
+ /// "foo::bar". Returns null if this type represents an unqualified-id.
+ NestedNameSpecifierLoc getPrefix() const;
+
+ /// This returns the position of the type after any elaboration, such as the
+ /// 'struct' keyword, and name qualifiers. This will the 'template' keyword if
+ /// present, or the name location otherwise.
+ SourceLocation getNonPrefixBeginLoc() const;
+
+ /// This returns the position of the type after any elaboration, such as the
+ /// 'struct' keyword. This may be the position of the name qualifiers,
+ /// 'template' keyword, or the name location otherwise.
+ SourceLocation getNonElaboratedBeginLoc() const;
+
/// Initializes this to state that every location in this
/// type is the given location.
///
@@ -679,62 +694,164 @@ public:
}
};
-/// Wrapper for source info for types used via transparent aliases.
-class UsingTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- UsingTypeLoc, UsingType> {
-public:
- QualType getUnderlyingType() const {
- return getTypePtr()->getUnderlyingType();
+struct ElaboratedNameLocInfo {
+ SourceLocation NameLoc;
+ SourceLocation ElaboratedKeywordLoc;
+
+ ElaboratedNameLocInfo() = default;
+ ElaboratedNameLocInfo(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation NameLoc)
+ : NameLoc(NameLoc), ElaboratedKeywordLoc(ElaboratedKeywordLoc),
+ QualifierData(QualifierLoc.getOpaqueData()) {}
+ ElaboratedNameLocInfo(ASTContext &Context, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, SourceLocation Loc)
+ : NameLoc(Loc),
+ ElaboratedKeywordLoc(
+ Keyword != ElaboratedTypeKeyword::None ? Loc : SourceLocation()),
+ QualifierData(getTrivialQualifierData(Context, Qualifier, Loc)) {}
+
+ NestedNameSpecifierLoc getQualifierLoc(NestedNameSpecifier Qualifier) const {
+ assert(!Qualifier == !QualifierData);
+ return NestedNameSpecifierLoc(Qualifier, QualifierData);
+ }
+
+ SourceRange getLocalSourceRange(NestedNameSpecifier Qualifier) const {
+ SourceLocation BeginLoc = ElaboratedKeywordLoc;
+ if (NestedNameSpecifierLoc QualifierLoc = getQualifierLoc(Qualifier);
+ BeginLoc.isInvalid() && Qualifier)
+ BeginLoc = QualifierLoc.getBeginLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = NameLoc;
+ return SourceRange(BeginLoc, NameLoc);
}
- UsingShadowDecl *getFoundDecl() const { return getTypePtr()->getFoundDecl(); }
-};
-/// Wrapper for source info for typedefs.
-class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TypedefTypeLoc,
- TypedefType> {
-public:
- TypedefNameDecl *getTypedefNameDecl() const {
- return getTypePtr()->getDecl();
+private:
+ void *QualifierData;
+
+ static void *getTrivialQualifierData(ASTContext &Context,
+ NestedNameSpecifier Qualifier,
+ SourceLocation Loc) {
+ if (!Qualifier)
+ return nullptr;
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, Qualifier, Loc);
+ return Builder.getWithLocInContext(Context).getOpaqueData();
}
};
-/// Wrapper for source info for injected class names of class
-/// templates.
-class InjectedClassNameTypeLoc :
- public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- InjectedClassNameTypeLoc,
- InjectedClassNameType> {
+template <class TL, class T>
+class ElaboratedNameTypeLoc
+ : public ConcreteTypeLoc<UnqualTypeLoc, TL, T, ElaboratedNameLocInfo> {
public:
- CXXRecordDecl *getDecl() const {
- return getTypePtr()->getDecl();
+ auto *getDecl() const { return this->getTypePtr()->getDecl(); }
+
+ void set(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc, SourceLocation NameLoc) {
+ assert(QualifierLoc.getNestedNameSpecifier() ==
+ this->getTypePtr()->getQualifier());
+ *this->getLocalData() =
+ ElaboratedNameLocInfo(ElaboratedKeywordLoc, QualifierLoc, NameLoc);
+ }
+
+ SourceLocation getElaboratedKeywordLoc() const {
+ return this->getLocalData()->ElaboratedKeywordLoc;
+ }
+
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ return this->getLocalData()->getQualifierLoc(
+ this->getTypePtr()->getQualifier());
+ }
+
+ SourceLocation getNameLoc() const { return this->getLocalData()->NameLoc; }
+
+ SourceRange getLocalSourceRange() const {
+ return this->getLocalData()->getLocalSourceRange(
+ this->getTypePtr()->getQualifier());
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ const auto *Ptr = this->getTypePtr();
+ *this->getLocalData() = ElaboratedNameLocInfo(Context, Ptr->getKeyword(),
+ Ptr->getQualifier(), Loc);
}
};
+/// Wrapper for source info for typedefs.
+class TypedefTypeLoc
+ : public ElaboratedNameTypeLoc<TypedefTypeLoc, TypedefType> {};
+
/// Wrapper for source info for unresolved typename using decls.
-class UnresolvedUsingTypeLoc :
- public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- UnresolvedUsingTypeLoc,
- UnresolvedUsingType> {
-public:
- UnresolvedUsingTypenameDecl *getDecl() const {
- return getTypePtr()->getDecl();
- }
+class UnresolvedUsingTypeLoc
+ : public ElaboratedNameTypeLoc<UnresolvedUsingTypeLoc,
+ UnresolvedUsingType> {};
+
+/// Wrapper for source info for types used via transparent aliases.
+class UsingTypeLoc : public ElaboratedNameTypeLoc<UsingTypeLoc, UsingType> {};
+
+struct TagTypeLocInfo {
+ SourceLocation NameLoc;
+ SourceLocation ElaboratedKWLoc;
+ void *QualifierData;
};
-/// Wrapper for source info for tag types. Note that this only
-/// records source info for the name itself; a type written 'struct foo'
-/// should be represented as an ElaboratedTypeLoc. We currently
-/// only do that when C++ is enabled because of the expense of
-/// creating an ElaboratedType node for so many type references in C.
-class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- TagTypeLoc,
- TagType> {
+class TagTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, TagTypeLoc, TagType,
+ TagTypeLocInfo> {
public:
- TagDecl *getDecl() const { return getTypePtr()->getDecl(); }
+ TagDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); }
/// True if the tag was defined in this type specifier.
bool isDefinition() const;
+
+ SourceLocation getElaboratedKeywordLoc() const {
+ return getLocalData()->ElaboratedKWLoc;
+ }
+
+ void setElaboratedKeywordLoc(SourceLocation Loc) {
+ getLocalData()->ElaboratedKWLoc = Loc;
+ }
+
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ NestedNameSpecifier Qualifier = getTypePtr()->getQualifier();
+ void *QualifierData = getLocalData()->QualifierData;
+ assert(!Qualifier == !QualifierData);
+ return NestedNameSpecifierLoc(Qualifier, QualifierData);
+ }
+
+ void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
+ assert(QualifierLoc.getNestedNameSpecifier() ==
+ getTypePtr()->getQualifier());
+ getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
+ }
+
+ SourceLocation getNameLoc() const { return getLocalData()->NameLoc; }
+
+ void setNameLoc(SourceLocation Loc) { getLocalData()->NameLoc = Loc; }
+
+ SourceRange getLocalSourceRange() const {
+ SourceLocation BeginLoc = getElaboratedKeywordLoc();
+ if (NestedNameSpecifierLoc Qualifier = getQualifierLoc();
+ BeginLoc.isInvalid() && Qualifier)
+ BeginLoc = Qualifier.getBeginLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = getNameLoc();
+ return SourceRange(BeginLoc, getNameLoc());
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setElaboratedKeywordLoc(getTypePtr()->getKeyword() !=
+ ElaboratedTypeKeyword::None
+ ? Loc
+ : SourceLocation());
+ if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, Qualifier, Loc);
+ setQualifierLoc(Builder.getWithLocInContext(Context));
+ } else {
+ getLocalData()->QualifierData = nullptr;
+ }
+ setNameLoc(Loc);
+ }
};
/// Wrapper for source info for record types.
@@ -742,7 +859,9 @@ class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
RecordTypeLoc,
RecordType> {
public:
- RecordDecl *getDecl() const { return getTypePtr()->getDecl(); }
+ RecordDecl *getOriginalDecl() const {
+ return getTypePtr()->getOriginalDecl();
+ }
};
/// Wrapper for source info for enum types.
@@ -750,7 +869,18 @@ class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc,
EnumTypeLoc,
EnumType> {
public:
- EnumDecl *getDecl() const { return getTypePtr()->getDecl(); }
+ EnumDecl *getOriginalDecl() const { return getTypePtr()->getOriginalDecl(); }
+};
+
+/// Wrapper for source info for injected class names of class
+/// templates.
+class InjectedClassNameTypeLoc
+ : public InheritingConcreteTypeLoc<TagTypeLoc, InjectedClassNameTypeLoc,
+ InjectedClassNameType> {
+public:
+ CXXRecordDecl *getOriginalDecl() const {
+ return getTypePtr()->getOriginalDecl();
+ }
};
/// Wrapper for template type parameters.
@@ -859,12 +989,22 @@ class SubstTemplateTypeParmTypeLoc :
SubstTemplateTypeParmType> {
};
- /// Wrapper for substituted template type parameters.
-class SubstTemplateTypeParmPackTypeLoc :
- public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
- SubstTemplateTypeParmPackTypeLoc,
- SubstTemplateTypeParmPackType> {
-};
+/// Abstract type representing delayed type pack expansions.
+class SubstPackTypeLoc
+ : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, SubstPackTypeLoc,
+ SubstPackType> {};
+
+/// Wrapper for substituted template type parameters.
+class SubstTemplateTypeParmPackTypeLoc
+ : public InheritingConcreteTypeLoc<SubstPackTypeLoc,
+ SubstTemplateTypeParmPackTypeLoc,
+ SubstTemplateTypeParmPackType> {};
+
+/// Wrapper for substituted template type parameters.
+class SubstBuiltinTemplatePackTypeLoc
+ : public InheritingConcreteTypeLoc<SubstPackTypeLoc,
+ SubstBuiltinTemplatePackTypeLoc,
+ SubstBuiltinTemplatePackType> {};
struct AttributedLocInfo {
const Attr *TypeAttr;
@@ -1405,7 +1545,7 @@ public:
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setSigilLoc(Loc);
- if (auto *Qualifier = getTypePtr()->getQualifier()) {
+ if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) {
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, Qualifier, Loc);
setQualifierLoc(Builder.getWithLocInContext(Context));
@@ -1701,9 +1841,11 @@ struct TemplateNameLocInfo {
};
struct TemplateSpecializationLocInfo : TemplateNameLocInfo {
+ SourceRange SR;
+ SourceLocation ElaboratedKWLoc;
SourceLocation TemplateKWLoc;
SourceLocation LAngleLoc;
- SourceLocation RAngleLoc;
+ void *QualifierData;
};
class TemplateSpecializationTypeLoc :
@@ -1712,54 +1854,52 @@ class TemplateSpecializationTypeLoc :
TemplateSpecializationType,
TemplateSpecializationLocInfo> {
public:
- SourceLocation getTemplateKeywordLoc() const {
- return getLocalData()->TemplateKWLoc;
- }
+ void set(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKeywordLoc, SourceLocation NameLoc,
+ SourceLocation LAngleLoc, SourceLocation RAngleLoc);
- void setTemplateKeywordLoc(SourceLocation Loc) {
- getLocalData()->TemplateKWLoc = Loc;
- }
+ void set(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKeywordLoc, SourceLocation NameLoc,
+ const TemplateArgumentListInfo &TAL);
- SourceLocation getLAngleLoc() const {
- return getLocalData()->LAngleLoc;
+ SourceLocation getElaboratedKeywordLoc() const {
+ return getLocalData()->ElaboratedKWLoc;
}
- void setLAngleLoc(SourceLocation Loc) {
- getLocalData()->LAngleLoc = Loc;
- }
+ NestedNameSpecifierLoc getQualifierLoc() const {
+ if (!getLocalData()->QualifierData)
+ return NestedNameSpecifierLoc();
- SourceLocation getRAngleLoc() const {
- return getLocalData()->RAngleLoc;
+ NestedNameSpecifier Qualifier =
+ getTypePtr()->getTemplateName().getQualifier();
+ assert(Qualifier && "missing qualification");
+ return NestedNameSpecifierLoc(Qualifier, getLocalData()->QualifierData);
}
- void setRAngleLoc(SourceLocation Loc) {
- getLocalData()->RAngleLoc = Loc;
+ SourceLocation getTemplateKeywordLoc() const {
+ return getLocalData()->TemplateKWLoc;
}
+ SourceLocation getTemplateNameLoc() const { return getLocalData()->NameLoc; }
+
+ SourceLocation getLAngleLoc() const { return getLocalData()->LAngleLoc; }
+
unsigned getNumArgs() const {
return getTypePtr()->template_arguments().size();
}
- void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
- getArgInfos()[i] = AI;
- }
-
- TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
- return getArgInfos()[i];
+ MutableArrayRef<TemplateArgumentLocInfo> getArgLocInfos() {
+ return {getArgInfos(), getNumArgs()};
}
TemplateArgumentLoc getArgLoc(unsigned i) const {
return TemplateArgumentLoc(getTypePtr()->template_arguments()[i],
- getArgLocInfo(i));
- }
-
- SourceLocation getTemplateNameLoc() const {
- return getLocalData()->NameLoc;
+ getArgInfos()[i]);
}
- void setTemplateNameLoc(SourceLocation Loc) {
- getLocalData()->NameLoc = Loc;
- }
+ SourceLocation getRAngleLoc() const { return getLocalData()->SR.getEnd(); }
/// - Copy the location information from the given info.
void copy(TemplateSpecializationTypeLoc Loc) {
@@ -1773,21 +1913,9 @@ public:
memcpy(Data, Loc.Data, size);
}
- SourceRange getLocalSourceRange() const {
- if (getTemplateKeywordLoc().isValid())
- return SourceRange(getTemplateKeywordLoc(), getRAngleLoc());
- else
- return SourceRange(getTemplateNameLoc(), getRAngleLoc());
- }
+ SourceRange getLocalSourceRange() const { return getLocalData()->SR; }
- void initializeLocal(ASTContext &Context, SourceLocation Loc) {
- setTemplateKeywordLoc(SourceLocation());
- setTemplateNameLoc(Loc);
- setLAngleLoc(Loc);
- setRAngleLoc(Loc);
- initializeArgLocs(Context, getTypePtr()->template_arguments(),
- getArgInfos(), Loc);
- }
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
static void initializeArgLocs(ASTContext &Context,
ArrayRef<TemplateArgument> Args,
@@ -2346,99 +2474,73 @@ public:
void initializeLocal(ASTContext &Context, SourceLocation Loc);
};
-class DeducedTemplateSpecializationTypeLoc
- : public InheritingConcreteTypeLoc<DeducedTypeLoc,
- DeducedTemplateSpecializationTypeLoc,
- DeducedTemplateSpecializationType> {
-public:
- SourceLocation getTemplateNameLoc() const {
- return getNameLoc();
- }
-
- void setTemplateNameLoc(SourceLocation Loc) {
- setNameLoc(Loc);
- }
-};
-
-struct ElaboratedLocInfo {
+struct DeducedTemplateSpecializationLocInfo : TypeSpecLocInfo {
SourceLocation ElaboratedKWLoc;
-
/// Data associated with the nested-name-specifier location.
void *QualifierData;
};
-class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
- ElaboratedTypeLoc,
- ElaboratedType,
- ElaboratedLocInfo> {
+class DeducedTemplateSpecializationTypeLoc
+ : public ConcreteTypeLoc<DeducedTypeLoc,
+ DeducedTemplateSpecializationTypeLoc,
+ DeducedTemplateSpecializationType,
+ DeducedTemplateSpecializationLocInfo> {
public:
SourceLocation getElaboratedKeywordLoc() const {
- return !isEmpty() ? getLocalData()->ElaboratedKWLoc : SourceLocation();
+ return getLocalData()->ElaboratedKWLoc;
}
void setElaboratedKeywordLoc(SourceLocation Loc) {
- if (isEmpty()) {
- assert(Loc.isInvalid());
- return;
- }
getLocalData()->ElaboratedKWLoc = Loc;
}
+ SourceLocation getTemplateNameLoc() const { return getNameLoc(); }
+
+ void setTemplateNameLoc(SourceLocation Loc) { setNameLoc(Loc); }
+
NestedNameSpecifierLoc getQualifierLoc() const {
- return !isEmpty() ? NestedNameSpecifierLoc(getTypePtr()->getQualifier(),
- getLocalData()->QualifierData)
- : NestedNameSpecifierLoc();
+ void *Data = getLocalData()->QualifierData;
+ if (!Data)
+ return NestedNameSpecifierLoc();
+ NestedNameSpecifier Qualifier =
+ getTypePtr()->getTemplateName().getQualifier();
+ assert(Qualifier && "missing qualification");
+ return NestedNameSpecifierLoc(Qualifier, Data);
}
void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) {
- assert(QualifierLoc.getNestedNameSpecifier() ==
- getTypePtr()->getQualifier() &&
- "Inconsistent nested-name-specifier pointer");
- if (isEmpty()) {
- assert(!QualifierLoc.hasQualifier());
+ if (!QualifierLoc) {
+ // Even if we have a nested-name-specifier in the dependent
+ // template specialization type, we won't record the nested-name-specifier
+ // location information when this type-source location information is
+ // part of a nested-name-specifier.
+ getLocalData()->QualifierData = nullptr;
return;
}
+
+ assert(QualifierLoc.getNestedNameSpecifier() ==
+ getTypePtr()->getTemplateName().getQualifier() &&
+ "Inconsistent nested-name-specifier pointer");
getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
}
SourceRange getLocalSourceRange() const {
- if (getElaboratedKeywordLoc().isValid())
- if (getQualifierLoc())
- return SourceRange(getElaboratedKeywordLoc(),
- getQualifierLoc().getEndLoc());
- else
- return SourceRange(getElaboratedKeywordLoc());
- else
- return getQualifierLoc().getSourceRange();
+ SourceLocation BeginLoc = getElaboratedKeywordLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = getQualifierLoc().getBeginLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = getNameLoc();
+ return {BeginLoc, getNameLoc()};
}
void initializeLocal(ASTContext &Context, SourceLocation Loc);
+};
- TypeLoc getNamedTypeLoc() const { return getInnerTypeLoc(); }
-
- QualType getInnerType() const { return getTypePtr()->getNamedType(); }
-
- bool isEmpty() const {
- return getTypePtr()->getKeyword() == ElaboratedTypeKeyword::None &&
- !getTypePtr()->getQualifier();
- }
-
- unsigned getLocalDataAlignment() const {
- // FIXME: We want to return 1 here in the empty case, but
- // there are bugs in how alignment is handled in TypeLocs
- // that prevent this from working.
- return ConcreteTypeLoc::getLocalDataAlignment();
- }
-
- unsigned getLocalDataSize() const {
- return !isEmpty() ? ConcreteTypeLoc::getLocalDataSize() : 0;
- }
+struct ElaboratedLocInfo {
+ SourceLocation ElaboratedKWLoc;
- void copy(ElaboratedTypeLoc Loc) {
- unsigned size = getFullDataSize();
- assert(size == Loc.getFullDataSize());
- memcpy(Data, Loc.Data, size);
- }
+ /// Data associated with the nested-name-specifier location.
+ void *QualifierData;
};
// This is exactly the structure of an ElaboratedTypeLoc whose inner
@@ -2749,8 +2851,6 @@ inline T TypeLoc::getAsAdjusted() const {
Cur = ATL.getWrappedLoc();
else if (auto ATL = Cur.getAs<HLSLAttributedResourceTypeLoc>())
Cur = ATL.getWrappedLoc();
- else if (auto ETL = Cur.getAs<ElaboratedTypeLoc>())
- Cur = ETL.getNamedTypeLoc();
else if (auto ATL = Cur.getAs<AdjustedTypeLoc>())
Cur = ATL.getOriginalLoc();
else if (auto MQL = Cur.getAs<MacroQualifiedTypeLoc>())
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 3373e96..185a968 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -379,38 +379,59 @@ let Class = AtomicType in {
}
let Class = UnresolvedUsingType in {
- def : Property<"declaration", DeclRef> {
- let Read = [{ node->getDecl() }];
+ def : Property<"IsCanonical", Bool> {
+ let Read = [{ node->isCanonicalUnqualified() }];
}
-
+ def : Property<"Keyword", ElaboratedTypeKeyword> {
+ let Conditional = [{ !IsCanonical }];
+ let Read = [{ node->getKeyword() }];
+ }
+ def : Property<"Qualifier", NestedNameSpecifier> {
+ let Conditional = [{ !IsCanonical }];
+ let Read = [{ node->getQualifier() }];
+ }
+ def : Property<"D", DeclRef> { let Read = [{ node->getDecl() }]; }
def : Creator<[{
- return ctx.getUnresolvedUsingType(cast<UnresolvedUsingTypenameDecl>(declaration));
+ auto *UD = cast<UnresolvedUsingTypenameDecl>(D);
+ return IsCanonical ? ctx.getCanonicalUnresolvedUsingType(UD) : ctx.getUnresolvedUsingType(*Keyword, *Qualifier, UD);
}]>;
}
let Class = UsingType in {
- def : Property<"foundDeclaration", UsingShadowDeclRef> {
- let Read = [{ node->getFoundDecl() }];
+ def : Property<"Keyword", ElaboratedTypeKeyword> {
+ let Read = [{ node->getKeyword() }];
}
- def : Property<"underlyingType", QualType> {
- let Read = [{ node->getUnderlyingType() }];
+ def : Property<"Qualifier", NestedNameSpecifier> {
+ let Read = [{ node->getQualifier() }];
+ }
+ def : Property<"D", UsingShadowDeclRef> { let Read = [{ node->getDecl() }]; }
+ def : Property<"UnderlyingType", QualType> {
+ let Read = [{ node->desugar() }];
}
-
def : Creator<[{
- return ctx.getUsingType(foundDeclaration, underlyingType);
+ return ctx.getUsingType(Keyword, Qualifier, D, UnderlyingType);
}]>;
}
let Class = TypedefType in {
+ def : Property<"Keyword", ElaboratedTypeKeyword> {
+ let Read = [{ node->getKeyword() }];
+ }
+ def : Property<"Qualifier", NestedNameSpecifier> {
+ let Read = [{ node->getQualifier() }];
+ }
def : Property<"declaration", DeclRef> {
let Read = [{ node->getDecl() }];
}
- def : Property<"underlyingType", QualType> {
+ def : Property<"UnderlyingType", QualType> {
let Read = [{ node->desugar() }];
}
+ def : Property<"TypeMatchesDecl", Bool> {
+ let Read = [{ node->typeMatchesDecl() }];
+ }
def : Creator<[{
- return ctx.getTypedefType(cast<TypedefNameDecl>(declaration), underlyingType);
+ return ctx.getTypedefType(Keyword, Qualifier, cast<TypedefNameDecl>(declaration), UnderlyingType, TypeMatchesDecl);
}]>;
}
@@ -520,6 +541,9 @@ let Class = AutoType in {
}
let Class = DeducedTemplateSpecializationType in {
+ def : Property<"keyword", ElaboratedTypeKeyword> {
+ let Read = [{ node->getKeyword() }];
+ }
def : Property<"templateName", Optional<TemplateName>> {
let Read = [{ makeOptionalFromNullable(node->getTemplateName()) }];
}
@@ -533,97 +557,42 @@ let Class = DeducedTemplateSpecializationType in {
}
def : Creator<[{
- return ctx.getDeducedTemplateSpecializationType(
+ return ctx.getDeducedTemplateSpecializationType(keyword,
makeNullableFromOptional(templateName),
deducedType, dependent);
}]>;
}
let Class = TagType in {
- def : Property<"dependent", Bool> {
- let Read = [{ node->isDependentType() }];
+ def : Property<"IsCanonical", Bool> {
+ let Read = [{ node->isCanonicalUnqualified() }];
}
- def : Property<"declaration", DeclRef> {
- // We don't know which declaration was originally referenced here, and we
- // cannot reference a declaration that follows the use (because that can
- // introduce deserialization cycles), so conservatively generate a
- // reference to the first declaration.
- // FIXME: If this is a reference to a class template specialization, that
- // can still introduce a deserialization cycle.
- let Read = [{ node->getDecl()->getCanonicalDecl() }];
+ def : Property<"Keyword", ElaboratedTypeKeyword> {
+ let Conditional = [{ !IsCanonical }];
+ let Read = [{ node->getKeyword() }];
}
+ def : Property<"Qualifier", NestedNameSpecifier> {
+ let Conditional = [{ !IsCanonical }];
+ let Read = [{ node->getQualifier() }];
+ }
+ def : Property<"TD", TagDeclRef> { let Read = [{ node->getOriginalDecl() }]; }
}
let Class = EnumType in {
+ def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; }
def : Creator<[{
- QualType result = ctx.getEnumType(cast<EnumDecl>(declaration));
- if (dependent)
- const_cast<Type *>(result.getTypePtr())
- ->addDependence(TypeDependence::DependentInstantiation);
- return result;
+ return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag);
}]>;
}
-
let Class = RecordType in {
+ def : Property<"OwnsTag", Bool> { let Read = [{ node->isTagOwned() }]; }
def : Creator<[{
- auto record = cast<RecordDecl>(declaration);
- QualType result = ctx.getRecordType(record);
- if (dependent)
- const_cast<Type *>(result.getTypePtr())
- ->addDependence(TypeDependence::DependentInstantiation);
- return result;
- }]>;
-}
-
-let Class = ElaboratedType in {
- def : Property<"keyword", ElaboratedTypeKeyword> {
- let Read = [{ node->getKeyword() }];
- }
- def : Property<"qualifier", NestedNameSpecifier> {
- let Read = [{ node->getQualifier() }];
- }
- def : Property<"namedType", QualType> {
- let Read = [{ node->getNamedType() }];
- }
- def : Property<"ownedTag", Optional<TagDeclRef>> {
- let Read = [{ makeOptionalFromPointer(
- const_cast<const TagDecl *>(node->getOwnedTagDecl())) }];
- }
-
- def : Creator<[{
- return ctx.getElaboratedType(keyword, qualifier, namedType,
- makePointerFromOptional(ownedTag));
+ return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, OwnsTag);
}]>;
}
-
let Class = InjectedClassNameType in {
- def : Property<"declaration", DeclRef> {
- // FIXME: drilling down to the canonical declaration is what the
- // existing serialization code was doing, but it's not clear why.
- let Read = [{ node->getDecl()->getCanonicalDecl() }];
- }
- def : Property<"injectedSpecializationType", QualType> {
- let Read = [{ node->getInjectedSpecializationType() }];
- }
-
def : Creator<[{
- // FIXME: ASTContext::getInjectedClassNameType is not currently suitable
- // for AST reading, too much interdependencies.
- const Type *T = nullptr;
- auto typeDecl = cast<CXXRecordDecl>(declaration);
- for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl()) {
- if (const Type *existing = DI->getTypeForDecl()) {
- T = existing;
- break;
- }
- }
- if (!T) {
- T = new (ctx, TypeAlignment)
- InjectedClassNameType(typeDecl, injectedSpecializationType);
- for (auto *DI = typeDecl; DI; DI = DI->getPreviousDecl())
- DI->setTypeForDecl(T);
- }
- return QualType(T, 0);
+ return IsCanonical ? ctx.getCanonicalTagType(TD) : ctx.getTagType(*Keyword, *Qualifier, TD, /*OwnsTag=*/false);
}]>;
}
@@ -741,6 +710,9 @@ let Class = DependentAddressSpaceType in {
}
let Class = TemplateSpecializationType in {
+ def : Property<"keyword", ElaboratedTypeKeyword> {
+ let Read = [{ node->getKeyword() }];
+ }
def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }];
}
@@ -753,7 +725,7 @@ let Class = TemplateSpecializationType in {
}
def : Creator<[{
- return ctx.getTemplateSpecializationType(templateName, args, {}, UnderlyingType);
+ return ctx.getTemplateSpecializationType(keyword, templateName, args, {}, UnderlyingType);
}]>;
}
@@ -848,6 +820,12 @@ let Class = PackExpansionType in {
}]>;
}
+let Class = SubstPackType in {
+ def : Property<"replacementPack", TemplateArgument> {
+ let Read = [{ node->getArgumentPack() }];
+ }
+}
+
let Class = SubstTemplateTypeParmPackType in {
def : Property<"associatedDecl", DeclRef> {
let Read = [{ node->getAssociatedDecl() }];
@@ -855,12 +833,7 @@ let Class = SubstTemplateTypeParmPackType in {
def : Property<"Index", UInt32> {
let Read = [{ node->getIndex() }];
}
- def : Property<"Final", Bool> {
- let Read = [{ node->getFinal() }];
- }
- def : Property<"replacementPack", TemplateArgument> {
- let Read = [{ node->getArgumentPack() }];
- }
+ def : Property<"Final", Bool> { let Read = [{ node->getFinal() }]; }
def : Creator<[{
return ctx.getSubstTemplateTypeParmPackType(
@@ -868,6 +841,12 @@ let Class = SubstTemplateTypeParmPackType in {
}]>;
}
+let Class = SubstBuiltinTemplatePackType in {
+ def : Creator<[{
+ return ctx.getSubstBuiltinTemplatePack(replacementPack);
+ }]>;
+}
+
let Class = BuiltinType in {
def : Property<"kind", BuiltinTypeKind> {
let Read = [{ node->getKind() }];
diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
index 73cbcf1..2d36e8c 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -135,10 +135,15 @@ public:
llvm::StringMap<llvm::TimeRecord> &Records;
};
+ MatchFinderOptions() {}
+
/// Enables per-check timers.
///
/// It prints a report after match.
std::optional<Profiling> CheckProfiling;
+
+ /// Avoids matching declarations in system headers.
+ bool IgnoreSystemHeaders{false};
};
MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 08c898f..f1d88a9 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -222,6 +222,19 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
extern const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl>
typeAliasDecl;
+/// \brief Matches shadow declarations introduced into a scope by a
+/// (resolved) using declaration.
+///
+/// Given
+/// \code
+/// namespace n { int f; }
+/// namespace declToImport { using n::f; }
+/// \endcode
+/// usingShadowDecl()
+/// matches \code f \endcode
+extern const internal::VariadicDynCastAllOfMatcher<Decl, UsingShadowDecl>
+ usingShadowDecl;
+
/// Matches type alias template declarations.
///
/// typeAliasTemplateDecl() matches
@@ -3740,7 +3753,7 @@ extern const internal::VariadicOperatorMatcherFunc<1, 1> unless;
/// Matcher<MemberExpr>, Matcher<QualType>, Matcher<RecordType>,
/// Matcher<TagType>, Matcher<TemplateSpecializationType>,
/// Matcher<TemplateTypeParmType>, Matcher<TypedefType>,
-/// Matcher<UnresolvedUsingType>
+/// Matcher<UnresolvedUsingType>, Matcher<UsingType>
inline internal::PolymorphicMatcher<
internal::HasDeclarationMatcher,
void(internal::HasDeclarationSupportedTypes), internal::Matcher<Decl>>
@@ -4375,7 +4388,13 @@ AST_POLYMORPHIC_MATCHER_P(throughUsingDecl,
AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr,
UsingType),
internal::Matcher<UsingShadowDecl>, Inner) {
- const NamedDecl *FoundDecl = Node.getFoundDecl();
+ const NamedDecl *FoundDecl;
+ if constexpr (std::is_same_v<NodeType, UsingType>) {
+ FoundDecl = Node.getDecl();
+ } else {
+ static_assert(std::is_same_v<NodeType, DeclRefExpr>);
+ FoundDecl = Node.getFoundDecl();
+ }
if (const UsingShadowDecl *UsingDecl = dyn_cast<UsingShadowDecl>(FoundDecl))
return Inner.matches(*UsingDecl, Finder, Builder);
return false;
@@ -5642,8 +5661,8 @@ AST_POLYMORPHIC_MATCHER_P(hasInitStatement,
return Init != nullptr && InnerMatcher.matches(*Init, Finder, Builder);
}
-/// Matches the condition expression of an if statement, for loop,
-/// switch statement or conditional operator.
+/// Matches the condition expression of an if statement, for loop, while loop,
+/// do-while loop, switch statement or conditional operator.
///
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
/// \code
@@ -5720,16 +5739,29 @@ AST_POLYMORPHIC_MATCHER_P(equalsBoundNode,
return Builder->removeBindings(Predicate);
}
-/// Matches the condition variable statement in an if statement.
+/// Matches a declaration if it declares the same entity as the node previously
+/// bound to \p ID.
+AST_MATCHER_P(Decl, declaresSameEntityAsBoundNode, std::string, ID) {
+ return Builder->removeBindings([&](const internal::BoundNodesMap &Nodes) {
+ return !clang::declaresSameEntity(&Node, Nodes.getNodeAs<Decl>(ID));
+ });
+}
+
+/// Matches the condition variable statement in an if statement, for loop,
+/// while loop or switch statement.
///
/// Given
/// \code
/// if (A* a = GetAPointer()) {}
+/// for (; A* a = GetAPointer(); ) {}
/// \endcode
/// hasConditionVariableStatement(...)
-/// matches 'A* a = GetAPointer()'.
-AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
- internal::Matcher<DeclStmt>, InnerMatcher) {
+/// matches both 'A* a = GetAPointer()'.
+AST_POLYMORPHIC_MATCHER_P(hasConditionVariableStatement,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
+ WhileStmt,
+ SwitchStmt),
+ internal::Matcher<DeclStmt>, InnerMatcher) {
const DeclStmt* const DeclarationStatement =
Node.getConditionVariableDeclStmt();
return DeclarationStatement != nullptr &&
@@ -7004,37 +7036,6 @@ AST_POLYMORPHIC_MATCHER_P2(
InnerMatcher.matches(Args[Index], Finder, Builder);
}
-/// Matches C or C++ elaborated `TypeLoc`s.
-///
-/// Given
-/// \code
-/// struct s {};
-/// struct s ss;
-/// \endcode
-/// elaboratedTypeLoc()
-/// matches the `TypeLoc` of the variable declaration of `ss`.
-extern const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>
- elaboratedTypeLoc;
-
-/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching
-/// `InnerMatcher`.
-///
-/// Given
-/// \code
-/// template <typename T>
-/// class C {};
-/// class C<int> c;
-///
-/// class D {};
-/// class D d;
-/// \endcode
-/// elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc()));
-/// matches the `TypeLoc` of the variable declaration of `c`, but not `d`.
-AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, internal::Matcher<TypeLoc>,
- InnerMatcher) {
- return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder);
-}
-
/// Matches type \c bool.
///
/// Given
@@ -7301,7 +7302,7 @@ extern const AstTypeMatcher<DecltypeType> decltypeType;
AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
AST_POLYMORPHIC_SUPPORTED_TYPES(AutoType));
-/// Matches \c DecltypeType or \c UsingType nodes to find the underlying type.
+/// Matches \c QualType nodes to find the underlying type.
///
/// Given
/// \code
@@ -7311,10 +7312,13 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
/// decltypeType(hasUnderlyingType(isInteger()))
/// matches the type of "a"
///
-/// Usable as: Matcher<DecltypeType>, Matcher<UsingType>
-AST_TYPE_TRAVERSE_MATCHER(hasUnderlyingType, getUnderlyingType,
- AST_POLYMORPHIC_SUPPORTED_TYPES(DecltypeType,
- UsingType));
+/// Usable as: Matcher<QualType>
+AST_MATCHER_P(Type, hasUnderlyingType, internal::Matcher<QualType>, Inner) {
+ QualType QT = Node.getLocallyUnqualifiedSingleStepDesugaredType();
+ if (QT == QualType(&Node, 0))
+ return false;
+ return Inner.matches(QT, Finder, Builder);
+}
/// Matches \c FunctionType nodes.
///
@@ -7593,27 +7597,7 @@ extern const AstTypeMatcher<RecordType> recordType;
/// and \c c.
extern const AstTypeMatcher<TagType> tagType;
-/// Matches types specified with an elaborated type keyword or with a
-/// qualified name.
-///
-/// Given
-/// \code
-/// namespace N {
-/// namespace M {
-/// class D {};
-/// }
-/// }
-/// class C {};
-///
-/// class C c;
-/// N::M::D d;
-/// \endcode
-///
-/// \c elaboratedType() matches the type of the variable declarations of both
-/// \c c and \c d.
-extern const AstTypeMatcher<ElaboratedType> elaboratedType;
-
-/// Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
+/// Matches Types whose qualifier, a NestedNameSpecifier,
/// matches \c InnerMatcher if the qualifier exists.
///
/// Given
@@ -7628,34 +7612,14 @@ extern const AstTypeMatcher<ElaboratedType> elaboratedType;
///
/// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
/// matches the type of the variable declaration of \c d.
-AST_MATCHER_P(ElaboratedType, hasQualifier,
- internal::Matcher<NestedNameSpecifier>, InnerMatcher) {
- if (const NestedNameSpecifier *Qualifier = Node.getQualifier())
- return InnerMatcher.matches(*Qualifier, Finder, Builder);
+AST_MATCHER_P(Type, hasQualifier, internal::Matcher<NestedNameSpecifier>,
+ InnerMatcher) {
+ if (NestedNameSpecifier Qualifier = Node.getPrefix())
+ return InnerMatcher.matches(Qualifier, Finder, Builder);
return false;
}
-/// Matches ElaboratedTypes whose named type matches \c InnerMatcher.
-///
-/// Given
-/// \code
-/// namespace N {
-/// namespace M {
-/// class D {};
-/// }
-/// }
-/// N::M::D d;
-/// \endcode
-///
-/// \c elaboratedType(namesType(recordType(
-/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
-/// declaration of \c d.
-AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
- InnerMatcher) {
- return InnerMatcher.matches(Node.getNamedType(), Finder, Builder);
-}
-
/// Matches types specified through a using declaration.
///
/// Given
@@ -7824,7 +7788,7 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(
/// matches "A::"
AST_MATCHER_P(NestedNameSpecifier, specifiesType,
internal::Matcher<QualType>, InnerMatcher) {
- if (!Node.getAsType())
+ if (Node.getKind() != NestedNameSpecifier::Kind::Type)
return false;
return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder);
}
@@ -7842,8 +7806,12 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType,
/// matches "A::"
AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
internal::Matcher<TypeLoc>, InnerMatcher) {
- return Node && Node.getNestedNameSpecifier()->getAsType() &&
- InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
+ if (!Node)
+ return false;
+ TypeLoc TL = Node.getAsTypeLoc();
+ if (!TL)
+ return false;
+ return InnerMatcher.matches(TL, Finder, Builder);
}
/// Matches on the prefix of a \c NestedNameSpecifier.
@@ -7858,10 +7826,21 @@ AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
internal::Matcher<NestedNameSpecifier>, InnerMatcher,
0) {
- const NestedNameSpecifier *NextNode = Node.getPrefix();
+ NestedNameSpecifier NextNode = std::nullopt;
+ switch (Node.getKind()) {
+ case NestedNameSpecifier::Kind::Namespace:
+ NextNode = Node.getAsNamespaceAndPrefix().Prefix;
+ break;
+ case NestedNameSpecifier::Kind::Type:
+ NextNode = Node.getAsType()->getPrefix();
+ break;
+ default:
+ break;
+ }
+
if (!NextNode)
return false;
- return InnerMatcher.matches(*NextNode, Finder, Builder);
+ return InnerMatcher.matches(NextNode, Finder, Builder);
}
/// Matches on the prefix of a \c NestedNameSpecifierLoc.
@@ -7876,7 +7855,12 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
internal::Matcher<NestedNameSpecifierLoc>, InnerMatcher,
1) {
- NestedNameSpecifierLoc NextNode = Node.getPrefix();
+ NestedNameSpecifierLoc NextNode;
+ if (TypeLoc TL = Node.getAsTypeLoc())
+ NextNode = TL.getPrefix();
+ else
+ NextNode = Node.getAsNamespaceAndPrefix().Prefix;
+
if (!NextNode)
return false;
return InnerMatcher.matches(NextNode, Finder, Builder);
@@ -7894,9 +7878,13 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
/// matches "ns::"
AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
internal::Matcher<NamespaceDecl>, InnerMatcher) {
- if (auto *NS = dyn_cast_if_present<NamespaceDecl>(Node.getAsNamespace()))
- return InnerMatcher.matches(*NS, Finder, Builder);
- return false;
+ if (Node.getKind() != NestedNameSpecifier::Kind::Namespace)
+ return false;
+ const auto *Namespace =
+ dyn_cast<NamespaceDecl>(Node.getAsNamespaceAndPrefix().Namespace);
+ if (!Namespace)
+ return false;
+ return InnerMatcher.matches(*Namespace, Finder, Builder);
}
/// Matches attributes.
@@ -8835,7 +8823,7 @@ AST_MATCHER(OMPDefaultClause, isFirstPrivateKind) {
/// #pragma omp for
/// \endcode
///
-/// `ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches
+/// ``ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches
/// ``omp parallel`` and ``omp parallel for``.
///
/// If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 5df2294..1ab6f11 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1017,10 +1017,7 @@ private:
// First, for any types that have a declaration, extract the declaration and
// match on it.
if (const auto *S = dyn_cast<TagType>(&Node)) {
- return matchesDecl(S->getDecl(), Finder, Builder);
- }
- if (const auto *S = dyn_cast<InjectedClassNameType>(&Node)) {
- return matchesDecl(S->getDecl(), Finder, Builder);
+ return matchesDecl(S->getOriginalDecl(), Finder, Builder);
}
if (const auto *S = dyn_cast<TemplateTypeParmType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
@@ -1031,6 +1028,9 @@ private:
if (const auto *S = dyn_cast<UnresolvedUsingType>(&Node)) {
return matchesDecl(S->getDecl(), Finder, Builder);
}
+ if (const auto *S = dyn_cast<UsingType>(&Node)) {
+ return matchesDecl(S->getDecl(), Finder, Builder);
+ }
if (const auto *S = dyn_cast<ObjCObjectType>(&Node)) {
return matchesDecl(S->getInterface(), Finder, Builder);
}
@@ -1066,12 +1066,6 @@ private:
Builder);
}
- // FIXME: We desugar elaborated types. This makes the assumption that users
- // do never want to match on whether a type is elaborated - there are
- // arguments for both sides; for now, continue desugaring.
- if (const auto *S = dyn_cast<ElaboratedType>(&Node)) {
- return matchesSpecialized(S->desugar(), Finder, Builder);
- }
// Similarly types found via using declarations.
// These are *usually* meaningless sugar, and this matches the historical
// behavior prior to the introduction of UsingType.
@@ -1211,8 +1205,8 @@ using AdaptativeDefaultToTypes =
/// All types that are supported by HasDeclarationMatcher above.
using HasDeclarationSupportedTypes =
TypeList<CallExpr, CXXConstructExpr, CXXNewExpr, DeclRefExpr, EnumType,
- ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
- MemberExpr, QualType, RecordType, TagType,
+ InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr,
+ QualType, RecordType, TagType, UsingType,
TemplateSpecializationType, TemplateTypeParmType, TypedefType,
UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;
@@ -1789,7 +1783,7 @@ public:
private:
static DynTypedNode extract(const NestedNameSpecifierLoc &Loc) {
- return DynTypedNode::create(*Loc.getNestedNameSpecifier());
+ return DynTypedNode::create(Loc.getNestedNameSpecifier());
}
};
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
index 1c00558..7e1bfc9 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety.h
@@ -19,14 +19,35 @@
#define LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableSet.h"
#include "llvm/ADT/StringMap.h"
#include <memory>
namespace clang::lifetimes {
+/// Enum to track the confidence level of a potential error.
+enum class Confidence {
+ None,
+ Maybe, // Reported as a potential error (-Wlifetime-safety-strict)
+ Definite // Reported as a definite error (-Wlifetime-safety-permissive)
+};
+
+class LifetimeSafetyReporter {
+public:
+ LifetimeSafetyReporter() = default;
+ virtual ~LifetimeSafetyReporter() = default;
+
+ virtual void reportUseAfterFree(const Expr *IssueExpr, const Expr *UseExpr,
+ SourceLocation FreeLoc,
+ Confidence Confidence) {}
+};
+
/// The main entry point for the analysis.
-void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC);
+void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC,
+ LifetimeSafetyReporter *Reporter);
namespace internal {
// Forward declarations of internal types.
@@ -53,6 +74,7 @@ template <typename Tag> struct ID {
IDBuilder.AddInteger(Value);
}
};
+
template <typename Tag>
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ID<Tag> ID) {
return OS << ID.Value;
@@ -78,7 +100,8 @@ using ProgramPoint = const Fact *;
/// encapsulates the various dataflow analyses.
class LifetimeSafetyAnalysis {
public:
- LifetimeSafetyAnalysis(AnalysisDeclContext &AC);
+ LifetimeSafetyAnalysis(AnalysisDeclContext &AC,
+ LifetimeSafetyReporter *Reporter);
~LifetimeSafetyAnalysis();
void run();
@@ -87,7 +110,7 @@ public:
LoanSet getLoansAtPoint(OriginID OID, ProgramPoint PP) const;
/// Returns the set of loans that have expired at a specific program point.
- LoanSet getExpiredLoansAtPoint(ProgramPoint PP) const;
+ std::vector<LoanID> getExpiredLoansAtPoint(ProgramPoint PP) const;
/// Finds the OriginID for a given declaration.
/// Returns a null optional if not found.
@@ -110,6 +133,7 @@ public:
private:
AnalysisDeclContext &AC;
+ LifetimeSafetyReporter *Reporter;
std::unique_ptr<LifetimeFactory> Factory;
std::unique_ptr<FactManager> FactMgr;
std::unique_ptr<LoanPropagationAnalysis> LoanPropagation;
@@ -118,4 +142,25 @@ private:
} // namespace internal
} // namespace clang::lifetimes
+namespace llvm {
+template <typename Tag>
+struct DenseMapInfo<clang::lifetimes::internal::ID<Tag>> {
+ using ID = clang::lifetimes::internal::ID<Tag>;
+
+ static inline ID getEmptyKey() {
+ return {DenseMapInfo<uint32_t>::getEmptyKey()};
+ }
+
+ static inline ID getTombstoneKey() {
+ return {DenseMapInfo<uint32_t>::getTombstoneKey()};
+ }
+
+ static unsigned getHashValue(const ID &Val) {
+ return DenseMapInfo<uint32_t>::getHashValue(Val.Value);
+ }
+
+ static bool isEqual(const ID &LHS, const ID &RHS) { return LHS == RHS; }
+};
+} // namespace llvm
+
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_LIFETIMESAFETY_H
diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
index 8c7ee86..a404b06 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
@@ -112,8 +112,14 @@ public:
// fields that are only used in these.
// Note: The operand of the `noexcept` operator is an unevaluated operand, but
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
- bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) override { return true; }
- bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) override { return true; }
+ bool TraverseDecltypeTypeLoc(DecltypeTypeLoc,
+ bool TraverseQualifier) override {
+ return true;
+ }
+ bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc,
+ bool TraverseQualifier) override {
+ return true;
+ }
bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) override {
if (TIE->isPotentiallyEvaluated())
return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(TIE);
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index 5be4a11..11042e8 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -42,6 +42,18 @@ struct ContextSensitiveOptions {
unsigned Depth = 2;
};
+/// A simple representation of essential elements of the logical context used in
+/// environments. Designed for import/export for applications requiring
+/// serialization support.
+struct SimpleLogicalContext {
+ // Global invariant that applies for all definitions in the context.
+ const Formula *Invariant;
+ // Flow-condition tokens in the context.
+ llvm::DenseMap<Atom, const Formula *> TokenDefs;
+ // Dependencies between flow-condition definitions.
+ llvm::DenseMap<Atom, llvm::DenseSet<Atom>> TokenDeps;
+};
+
/// Owns objects that encompass the state of a program and stores context that
/// is used during dataflow analysis.
class DataflowAnalysisContext {
@@ -140,6 +152,15 @@ public:
/// Adds `Constraint` to the flow condition identified by `Token`.
void addFlowConditionConstraint(Atom Token, const Formula &Constraint);
+ /// Adds `Deps` to the dependencies of the flow condition identified by
+ /// `Token`. Intended for use in deserializing contexts. The formula alone
+ /// doesn't have enough information to indicate its deps.
+ void addFlowConditionDeps(Atom Token, const llvm::DenseSet<Atom> &Deps) {
+ // Avoid creating an entry for `Token` with an empty set.
+ if (!Deps.empty())
+ FlowConditionDeps[Token].insert(Deps.begin(), Deps.end());
+ }
+
/// Creates a new flow condition with the same constraints as the flow
/// condition identified by `Token` and returns its token.
Atom forkFlowCondition(Atom Token);
@@ -207,6 +228,14 @@ public:
return {};
}
+ /// Export the logical-context portions of `AC`, limited to the given target
+ /// flow-condition tokens.
+ SimpleLogicalContext
+ exportLogicalContext(llvm::DenseSet<dataflow::Atom> TargetTokens) const;
+
+ /// Initializes this context's "logical" components with `LC`.
+ void initLogicalContext(SimpleLogicalContext LC);
+
private:
friend class Environment;
@@ -228,6 +257,11 @@ private:
DataflowAnalysisContext(Solver &S, std::unique_ptr<Solver> &&OwnedSolver,
Options Opts);
+ /// Computes the transitive closure of dependencies of (flow-condition)
+ /// `Tokens`. That is, the set of flow-condition tokens reachable from
+ /// `Tokens` in the dependency graph.
+ llvm::DenseSet<Atom> collectDependencies(llvm::DenseSet<Atom> Tokens) const;
+
// Extends the set of modeled field declarations.
void addModeledFields(const FieldSet &Fields);
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index 097ff2b..0767144 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -157,10 +157,18 @@ public:
};
/// Creates an environment that uses `DACtx` to store objects that encompass
- /// the state of a program.
+ /// the state of a program. `FlowConditionToken` sets the flow condition
+ /// associated with the environment. Generally, new environments should be
+ /// initialized with a fresh token, by using one of the other
+ /// constructors. This constructor is for specialized use, including
+ /// deserialization and delegation from other constructors.
+ Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken)
+ : DACtx(&DACtx), FlowConditionToken(FlowConditionToken) {}
+
+ /// Creates an environment that uses `DACtx` to store objects that encompass
+ /// the state of a program. Populates a fresh atom as flow condition token.
explicit Environment(DataflowAnalysisContext &DACtx)
- : DACtx(&DACtx),
- FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
+ : Environment(DACtx, DACtx.arena().makeFlowConditionToken()) {}
/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `S` as the statement to analyze.
diff --git a/clang/include/clang/Analysis/FlowSensitive/Formula.h b/clang/include/clang/Analysis/FlowSensitive/Formula.h
index 0e63524..3959bc9 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Formula.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Formula.h
@@ -85,21 +85,17 @@ public:
}
using AtomNames = llvm::DenseMap<Atom, std::string>;
- // Produce a stable human-readable representation of this formula.
- // For example: (V3 | !(V1 & V2))
- // If AtomNames is provided, these override the default V0, V1... names.
+ /// Produces a stable human-readable representation of this formula.
+ /// For example: (V3 | !(V1 & V2))
+ /// If AtomNames is provided, these override the default V0, V1... names.
void print(llvm::raw_ostream &OS, const AtomNames * = nullptr) const;
- // Allocate Formulas using Arena rather than calling this function directly.
+ /// Allocates Formulas using Arena rather than calling this function directly.
static const Formula &create(llvm::BumpPtrAllocator &Alloc, Kind K,
ArrayRef<const Formula *> Operands,
unsigned Value = 0);
-private:
- Formula() = default;
- Formula(const Formula &) = delete;
- Formula &operator=(const Formula &) = delete;
-
+ /// Count of operands (sub-formulas) associated with Formulas of kind `K`.
static unsigned numOperands(Kind K) {
switch (K) {
case AtomRef:
@@ -116,6 +112,11 @@ private:
llvm_unreachable("Unhandled Formula::Kind enum");
}
+private:
+ Formula() = default;
+ Formula(const Formula &) = delete;
+ Formula &operator=(const Formula &) = delete;
+
Kind FormulaKind;
// Some kinds of formula have scalar values, e.g. AtomRef's atom number.
unsigned Value;
diff --git a/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h b/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h
new file mode 100644
index 0000000..119f93e
--- /dev/null
+++ b/clang/include/clang/Analysis/FlowSensitive/FormulaSerialization.h
@@ -0,0 +1,40 @@
+//=== FormulaSerialization.h - Formula De/Serialization support -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_SERIALIZATION_H
+#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_SERIALIZATION_H
+
+#include "clang/Analysis/FlowSensitive/Arena.h"
+#include "clang/Analysis/FlowSensitive/Formula.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <string>
+
+namespace clang::dataflow {
+
+/// Prints `F` to `OS` in a compact format, optimized for easy parsing
+/// (deserialization) rather than human use.
+void serializeFormula(const Formula &F, llvm::raw_ostream &OS);
+
+/// Parses `Str` to build a serialized Formula.
+/// @returns error on parse failure or if parsing does not fully consume `Str`.
+/// @param A used to construct the formula components.
+/// @param AtomMap maps serialized Atom identifiers (unsigned ints) to Atoms.
+/// This map is provided by the caller to enable consistency across
+/// multiple formulas in a single file.
+llvm::Expected<const Formula *>
+parseFormula(llvm::StringRef Str, Arena &A,
+ llvm::DenseMap<unsigned, Atom> &AtomMap);
+
+} // namespace clang::dataflow
+#endif
diff --git a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
index 8fcc6a4..534b9a0 100644
--- a/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
+++ b/clang/include/clang/Analysis/FlowSensitive/StorageLocation.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Debug.h"
#include <cassert>
@@ -152,6 +153,11 @@ public:
return {SyntheticFields.begin(), SyntheticFields.end()};
}
+ /// Add a synthetic field, if none by that name is already present.
+ void addSyntheticField(llvm::StringRef Name, StorageLocation &Loc) {
+ SyntheticFields.insert({Name, &Loc});
+ }
+
/// Changes the child storage location for a field `D` of reference type.
/// All other fields cannot change their storage location and always retain
/// the storage location passed to the `RecordStorageLocation` constructor.
@@ -164,6 +170,11 @@ public:
Children[&D] = Loc;
}
+ /// Add a child storage location for a field `D`, if not already present.
+ void addChild(const ValueDecl &D, StorageLocation *Loc) {
+ Children.insert({&D, Loc});
+ }
+
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
return {Children.begin(), Children.end()};
}
diff --git a/clang/include/clang/Basic/ABIVersions.def b/clang/include/clang/Basic/ABIVersions.def
new file mode 100644
index 0000000..f6524bc
--- /dev/null
+++ b/clang/include/clang/Basic/ABIVersions.def
@@ -0,0 +1,135 @@
+//===--- ABIVersions.def - Clang ABI Versions Database ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates Clang ABI versions.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file ABIVersions.def
+///
+/// In this file, each of the Clang ABI Versions is enumerated
+/// ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR, or ABI_VER_LATEST macro.
+///
+/// ABI_VER_MAJOR is used when the minor version is 0 or can be omitted.
+///
+/// The first argument of ABI_VER_MAJOR_MINOR and ABI_VER_MAJOR is the major
+/// version.
+///
+/// The second argument of ABI_VER_MAJOR_MINOR is the minor version.
+///
+/// The first argument of ABI_VER_LATEST is an identifier `Latest`.
+
+#if defined(ABI_VER_MAJOR_MINOR) != defined(ABI_VER_MAJOR) || \
+ defined(ABI_VER_MAJOR) != defined(ABI_VER_LATEST)
+# error ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR and ABI_VER_LATEST should be defined simultaneously
+#endif
+
+#ifndef ABI_VER_MAJOR_MINOR
+# define ABI_VER_MAJOR_MINOR(Major, Minor)
+#endif
+
+#ifndef ABI_VER_MAJOR
+# define ABI_VER_MAJOR(Major)
+#endif
+
+#ifndef ABI_VER_LATEST
+# define ABI_VER_LATEST(Latest)
+#endif
+
+/// Attempt to be ABI-compatible with code generated by Clang 3.8.x
+/// (SVN r257626). This causes <1 x long long> to be passed in an integer
+/// register instead of an SSE register on x64_64.
+ABI_VER_MAJOR_MINOR(3, 8)
+
+/// Attempt to be ABI-compatible with code generated by Clang 4.0.x
+/// (SVN r291814). This causes move operations to be ignored when determining
+/// whether a class type can be passed or returned directly.
+ABI_VER_MAJOR(4)
+
+/// Attempt to be ABI-compatible with code generated by Clang 6.0.x
+/// (SVN r321711). This causes determination of whether a type is
+/// standard-layout to ignore collisions between empty base classes and between
+/// base classes and member subobjects, which affects whether we reuse base
+/// class tail padding in some ABIs.
+ABI_VER_MAJOR(6)
+
+/// Attempt to be ABI-compatible with code generated by Clang 7.0.x
+/// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be compatible
+/// with __alignof (i.e., return the preferred alignment) rather than returning
+/// the required alignment.
+ABI_VER_MAJOR(7)
+
+/// Attempt to be ABI-compatible with code generated by Clang 9.0.x
+/// (SVN r351319). This causes vectors of __int128 to be passed in memory
+/// instead of passing in multiple scalar registers on x86_64 on Linux and
+/// NetBSD.
+ABI_VER_MAJOR(9)
+
+/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
+/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit vector
+/// member on the stack instead of using registers, to not properly mangle
+/// substitutions for template names in some cases, and to mangle declaration
+/// template arguments without a cast to the parameter type even when that can
+/// lead to mangling collisions.
+ABI_VER_MAJOR(11)
+
+/// Attempt to be ABI-compatible with code generated by Clang 12.0.x
+/// (git 8e464dd76bef). This causes clang to mangle lambdas within global-scope
+/// inline variables incorrectly.
+ABI_VER_MAJOR(12)
+
+/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
+/// This causes clang to:
+/// - mangle dependent nested names incorrectly.
+/// - make trivial only those defaulted copy constructors with a
+/// parameter-type-list equivalent to the parameter-type-list of an implicit
+/// declaration.
+ABI_VER_MAJOR(14)
+
+/// Attempt to be ABI-compatible with code generated by Clang 15.0.x.
+/// This causes clang to:
+/// - Reverse the implementation for CWG692, CWG1395 and CWG1432.
+/// - pack non-POD members of packed structs.
+/// - consider classes with defaulted special member functions non-pod.
+ABI_VER_MAJOR(15)
+
+/// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
+/// This causes clang to revert some fixes to its implementation of the Itanium
+/// name mangling scheme, with the consequence that overloaded function
+/// templates are mangled the same if they differ only by:
+/// - constraints
+/// - whether a non-type template parameter has a deduced type
+/// - the parameter list of a template template parameter
+ABI_VER_MAJOR(17)
+
+/// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
+/// This causes clang to revert some fixes to the mangling of lambdas in the
+/// initializers of members of local classes.
+ABI_VER_MAJOR(18)
+
+/// Attempt to be ABI-compatible with code generated by Clang 19.0.x.
+/// This causes clang to:
+/// - Incorrectly mangle the 'base type' substitutions of the CXX construction
+/// vtable because it hasn't added 'type' as a substitution.
+/// - Skip mangling enclosing class templates of member-like friend function
+/// templates.
+/// - Ignore empty struct arguments in C++ mode for ARM, instead of passing
+/// them as if they had a size of 1 byte.
+ABI_VER_MAJOR(19)
+
+/// Attempt to be ABI-compatible with code generated by Clang 20.0.x.
+/// This causes clang to:
+/// - Incorrectly return C++ records in AVX registers on x86_64.
+ABI_VER_MAJOR(20)
+
+/// Conform to the underlying platform's C and C++ ABIs as closely as we can.
+ABI_VER_LATEST(Latest)
+
+#undef ABI_VER_MAJOR_MINOR
+#undef ABI_VER_MAJOR
+#undef ABI_VER_LATEST
diff --git a/clang/include/clang/Basic/AllDiagnosticKinds.inc b/clang/include/clang/Basic/AllDiagnosticKinds.inc
index a946b4a..2d08bb0 100644
--- a/clang/include/clang/Basic/AllDiagnosticKinds.inc
+++ b/clang/include/clang/Basic/AllDiagnosticKinds.inc
@@ -30,4 +30,5 @@
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
+#include "clang/Basic/DiagnosticTrapKinds.inc"
// clang-format on
diff --git a/clang/include/clang/Basic/AllDiagnostics.h b/clang/include/clang/Basic/AllDiagnostics.h
index e64634c..78e5428 100644
--- a/clang/include/clang/Basic/AllDiagnostics.h
+++ b/clang/include/clang/Basic/AllDiagnostics.h
@@ -23,20 +23,21 @@
#include "clang/Basic/DiagnosticInstallAPI.h"
#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticParse.h"
+#include "clang/Basic/DiagnosticRefactoring.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/DiagnosticSerialization.h"
-#include "clang/Basic/DiagnosticRefactoring.h"
+#include "clang/Basic/DiagnosticTrap.h"
namespace clang {
-template <size_t SizeOfStr, typename FieldType>
-class StringSizerHelper {
+template <size_t SizeOfStr, typename FieldType> class StringSizerHelper {
static_assert(SizeOfStr <= FieldType(~0U), "Field too small!");
+
public:
enum { Size = SizeOfStr };
};
} // end namespace clang
-#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \
- fieldTy>::Size
+#define STR_SIZE(str, fieldTy) \
+ clang::StringSizerHelper<sizeof(str) - 1, fieldTy>::Size
#endif
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 30efb9f..29364c5 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1632,6 +1632,13 @@ def DeviceKernel : DeclOrTypeAttr {
}];
}
+def SYCLExternal : InheritableAttr {
+ let Spellings = [CXX11<"clang", "sycl_external">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let LangOpts = [SYCLHost, SYCLDevice];
+ let Documentation = [SYCLExternalDocs];
+}
+
def SYCLKernelEntryPoint : InheritableAttr {
let Spellings = [CXX11<"clang", "sycl_kernel_entry_point">];
let Args = [
@@ -3922,6 +3929,14 @@ def CFICanonicalJumpTable : InheritableAttr {
let SimpleHandler = 1;
}
+def CFISalt : TypeAttr {
+ let Spellings = [Clang<"cfi_salt">];
+ let Args = [StringArgument<"Salt">];
+ let Subjects = SubjectList<[FunctionLike], ErrorDiag>;
+ let Documentation = [CFISaltDocs];
+ let LangOpts = [COnly];
+}
+
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
// Not all of these attributes will be given a [[]] spelling. The attributes
// which require access to function parameter names cannot use the [[]] spelling
@@ -4932,6 +4947,7 @@ def HLSLResourceBinding: InheritableAttr {
return SpaceNumber;
}
void setImplicitBindingOrderID(uint32_t Value) {
+ assert(!hasImplicitBindingOrderID() && "attribute already has implicit binding order id");
ImplicitBindingOrderID = Value;
}
bool hasImplicitBindingOrderID() const {
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 2b095ab..2504841 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -476,6 +476,47 @@ The SYCL kernel in the previous code sample meets these expectations.
}];
}
+def SYCLExternalDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "sycl_external";
+ let Content = [{
+The ``sycl_external`` attribute indicates that a function defined in another
+translation unit may be called by a device function defined in the current
+translation unit or, if defined in the current translation unit, the function
+may be called by device functions defined in other translation units.
+The attribute is intended for use in the implementation of the ``SYCL_EXTERNAL``
+macro as specified in section 5.10.1, "SYCL functions and member functions
+linkage", of the SYCL 2020 specification.
+
+The attribute only appertains to functions and only those that meet the
+following requirements:
+
+* Has external linkage
+* Is not explicitly defined as deleted (the function may be an explicitly
+ defaulted function that is defined as deleted)
+
+The attribute shall be present on the first declaration of a function and
+may optionally be present on subsequent declarations.
+
+When compiling for a SYCL device target that does not support the generic
+address space, the function shall not specify a raw pointer or reference type
+as the return type or as a parameter type.
+See section 5.10, "SYCL offline linking", of the SYCL 2020 specification.
+The following examples demonstrate the use of this attribute:
+
+.. code-block:: c++
+
+ [[clang::sycl_external]] void Foo(); // Ok.
+
+ [[clang::sycl_external]] void Bar() { /* ... */ } // Ok.
+
+ [[clang::sycl_external]] extern void Baz(); // Ok.
+
+ [[clang::sycl_external]] static void Quux() { /* ... */ } // error: Quux() has internal linkage.
+
+ }];
+}
+
def SYCLKernelEntryPointDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@@ -932,6 +973,21 @@ An example of how to use ``alloc_size``
assert(__builtin_object_size(a, 0) == 100);
}
+When ``-Walloc-size`` is enabled, this attribute allows the compiler to
+diagnose cases when the allocated memory is insufficient for the size of the
+type the returned pointer is cast to.
+
+.. code-block:: c
+
+ void *my_malloc(int a) __attribute__((alloc_size(1)));
+ void consumer_func(int *);
+
+ int main() {
+ int *ptr = my_malloc(sizeof(int)); // no warning
+ int *w = my_malloc(1); // warning: allocation of insufficient size '1' for type 'int' with size '4'
+ consumer_func(my_malloc(1)); // warning: allocation of insufficient size '1' for type 'int' with size '4'
+ }
+
.. Note:: This attribute works differently in clang than it does in GCC.
Specifically, clang will only trace ``const`` pointers (as above); we give up
on pointers that are not marked as ``const``. In the vast majority of cases,
@@ -3646,6 +3702,99 @@ make the function's CFI jump table canonical. See :ref:`the CFI documentation
}];
}
+def CFISaltDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "cfi_salt";
+ let Label = "langext-cfi_salt";
+ let Content = [{
+The ``cfi_salt`` attribute specifies a string literal that is used as a salt
+for Control-Flow Integrity (CFI) checks to distinguish between functions with
+the same type signature. This attribute can be applied to function declarations,
+function definitions, and function pointer typedefs.
+
+The attribute prevents function pointers from being replaced with pointers to
+functions that have a compatible type, which can be a CFI bypass vector.
+
+**Syntax:**
+
+* GNU-style: ``__attribute__((cfi_salt("<salt_string>")))``
+* C++11-style: ``[[clang::cfi_salt("<salt_string>")]]``
+
+**Usage:**
+
+The attribute takes a single string literal argument that serves as the salt.
+Functions or function types with different salt values will have different CFI
+hashes, even if they have identical type signatures.
+
+**Motivation:**
+
+In large codebases like the Linux kernel, there are often hundreds of functions
+with identical type signatures that are called indirectly:
+
+.. code-block::
+
+ 1662 functions with void (*)(void)
+ 1179 functions with int (*)(void)
+ ...
+
+By salting the CFI hashes, you can make CFI more robust by ensuring that
+functions intended for different purposes have distinct CFI identities.
+
+**Type Compatibility:**
+
+* Functions with different salt values are considered to have incompatible types
+* Function pointers with different salt values cannot be assigned to each other
+* All declarations of the same function must use the same salt value
+
+**Example:**
+
+.. code-block:: c
+
+ // Header file - define convenience macros
+ #define __cfi_salt(s) __attribute__((cfi_salt(s)))
+
+ // Typedef for regular function pointers
+ typedef int (*fptr_t)(void);
+
+ // Typedef for salted function pointers
+ typedef int (*fptr_salted_t)(void) __cfi_salt("pepper");
+
+ struct widget_ops {
+ fptr_t init; // Regular CFI
+ fptr_salted_t exec; // Salted CFI
+ fptr_t cleanup; // Regular CFI
+ };
+
+ // Function implementations
+ static int widget_init(void) { return 0; }
+ static int widget_exec(void) __cfi_salt("pepper") { return 1; }
+ static int widget_cleanup(void) { return 0; }
+
+ static struct widget_ops ops = {
+ .init = widget_init, // OK - compatible types
+ .exec = widget_exec, // OK - both use "pepper" salt
+ .cleanup = widget_cleanup // OK - compatible types
+ };
+
+ // Using C++11 attribute syntax
+ void secure_callback(void) [[clang::cfi_salt("secure")]];
+
+ // This would cause a compilation error:
+ // fptr_t bad_ptr = widget_exec; // Error: incompatible types
+
+**Notes:**
+
+* The salt string can contain non-NULL ASCII characters, including spaces and
+ quotes
+* This attribute only applies to function types; using it on non-function
+ types will generate a warning
+* All declarations and definitions of the same function must use identical
+ salt values
+* The attribute affects type compatibility during compilation and CFI hash
+ generation during code generation
+ }];
+}
+
def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> {
let Content = [{
Clang supports additional attributes to enable checking type safety properties
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td b/clang/include/clang/Basic/BuiltinTemplates.td
index 5b9672b..504405a 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -62,3 +62,7 @@ def __builtin_common_type : CPlusPlusBuiltinTemplate<
// typename ...Operands>
def __hlsl_spirv_type : HLSLBuiltinTemplate<
[Uint32T, Uint32T, Uint32T, Class<"Operands", /*is_variadic=*/1>]>;
+
+// template <class ...Args>
+def __builtin_dedup_pack
+ : CPlusPlusBuiltinTemplate<[Class<"Args", /*is_variadic=*/1>]>;
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index c81714e..af0e824 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1232,6 +1232,30 @@ def ConvertVector : Builtin {
let Prototype = "void(...)";
}
+def MaskedLoad : Builtin {
+ let Spellings = ["__builtin_masked_load"];
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def MaskedStore : Builtin {
+ let Spellings = ["__builtin_masked_store"];
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def MaskedExpandLoad : Builtin {
+ let Spellings = ["__builtin_masked_expand_load"];
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def MaskedCompressStore : Builtin {
+ let Spellings = ["__builtin_masked_compress_store"];
+ let Attributes = [NoThrow, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
def AllocaUninitialized : Builtin {
let Spellings = ["__builtin_alloca_uninitialized"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow];
@@ -1264,7 +1288,7 @@ def NondetermenisticValue : Builtin {
def ElementwiseAbs : Builtin {
let Spellings = ["__builtin_elementwise_abs"];
- let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
@@ -1300,13 +1324,13 @@ def ElementwiseBitreverse : Builtin {
def ElementwiseMax : Builtin {
let Spellings = ["__builtin_elementwise_max"];
- let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
def ElementwiseMin : Builtin {
let Spellings = ["__builtin_elementwise_min"];
- let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
@@ -1498,7 +1522,7 @@ def ElementwiseCopysign : Builtin {
def ElementwiseFma : Builtin {
let Spellings = ["__builtin_elementwise_fma"];
- let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}
@@ -1514,6 +1538,30 @@ def ElementwiseSubSat : Builtin {
let Prototype = "void(...)";
}
+def ElementwiseFshl : Builtin {
+ let Spellings = ["__builtin_elementwise_fshl"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ElementwiseFshr : Builtin {
+ let Spellings = ["__builtin_elementwise_fshr"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking];
+ let Prototype = "void(...)";
+}
+
+def ElementwiseCtlz : Builtin {
+ let Spellings = ["__builtin_elementwise_ctlz"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
+ let Prototype = "void(...)";
+}
+
+def ElementwiseCttz : Builtin {
+ let Spellings = ["__builtin_elementwise_cttz"];
+ let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
+ let Prototype = "void(...)";
+}
+
def ReduceMax : Builtin {
let Spellings = ["__builtin_reduce_max"];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def
index b16d4a2..6f5d1e0 100644
--- a/clang/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def
@@ -183,6 +183,9 @@ TARGET_BUILTIN(__builtin_amdgcn_struct_ptr_buffer_load_lds, "vQbv*3IUiiiiIiIi",
TARGET_BUILTIN(__builtin_amdgcn_ballot_w32, "ZUib", "nc", "wavefrontsize32")
BUILTIN(__builtin_amdgcn_ballot_w64, "WUib", "nc")
+TARGET_BUILTIN(__builtin_amdgcn_inverse_ballot_w32, "bZUi", "nc", "wavefrontsize32")
+TARGET_BUILTIN(__builtin_amdgcn_inverse_ballot_w64, "bWUi", "nc", "wavefrontsize64")
+
// Deprecated intrinsics in favor of __builtin_amdgn_ballot_{w32|w64}
BUILTIN(__builtin_amdgcn_uicmp, "WUiUiUiIi", "nc")
BUILTIN(__builtin_amdgcn_uicmpl, "WUiWUiWUiIi", "nc")
@@ -503,6 +506,9 @@ TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal, "vIi", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_var, "vv*i", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_wait, "vIs", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_barrier_signal_isfirst, "bIi", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_init, "vv*i", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_join, "vv*", "n", "gfx12-insts")
+TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "vIs", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_get_named_barrier_state, "Uiv*", "n", "gfx12-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_prefetch_data, "vvC*Ui", "nc", "gfx12-insts")
diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def
index e7d6741..22926b6 100644
--- a/clang/include/clang/Basic/BuiltinsPPC.def
+++ b/clang/include/clang/Basic/BuiltinsPPC.def
@@ -580,6 +580,8 @@ TARGET_BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "",
"isa-v207-instructions")
// P9 Binary-coded decimal (BCD) builtins.
+TARGET_BUILTIN(__builtin_ppc_bcdcopysign, "V16UcV16UcV16Uc", "", "power9-vector")
+TARGET_BUILTIN(__builtin_ppc_bcdsetsign, "V16UcV16UcUc", "t", "power9-vector")
TARGET_BUILTIN(__builtin_ppc_national2packed, "V16UcV16UcUc", "t", "power9-vector")
TARGET_BUILTIN(__builtin_ppc_packed2national, "V16UcV16Uc", "", "power9-vector")
TARGET_BUILTIN(__builtin_ppc_packed2zoned, "V16UcV16UcUc", "t", "power9-vector")
@@ -1098,6 +1100,10 @@ UNALIASED_CUSTOM_BUILTIN(mma_dmmr, "vW1024*W1024*", false,
"mma,isa-future-instructions")
UNALIASED_CUSTOM_BUILTIN(mma_dmxor, "vW1024*W1024*", true,
"mma,isa-future-instructions")
+UNALIASED_CUSTOM_BUILTIN(mma_disassemble_dmr, "vv*W1024*", false,
+ "mma,isa-future-instructions")
+UNALIASED_CUSTOM_BUILTIN(mma_build_dmr, "vW1024*VVVVVVVV", false,
+ "mma,isa-future-instructions")
// MMA builtins with positive/negative multiply/accumulate.
UNALIASED_CUSTOM_MMA_BUILTIN(mma_xvf16ger2, "vW512*VV",
diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td
index a4acc72..acd8f70 100644
--- a/clang/include/clang/Basic/BuiltinsX86.td
+++ b/clang/include/clang/Basic/BuiltinsX86.td
@@ -93,13 +93,11 @@ let Attributes = [Const, NoThrow, RequiredVectorWidth<128>] in {
}
let Features = "sse2" in {
- def pmulhw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def pavgb128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
def pavgw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def packsswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">;
def packssdw128 : X86Builtin<"_Vector<8, short>(_Vector<4, int>, _Vector<4, int>)">;
def packuswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">;
- def pmulhuw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def vec_ext_v2di : X86Builtin<"long long int(_Vector<2, long long int>, _Constant int)">;
def vec_ext_v4si : X86Builtin<"int(_Vector<4, int>, _Constant int)">;
def vec_ext_v4sf : X86Builtin<"float(_Vector<4, float>, _Constant int)">;
@@ -107,6 +105,11 @@ let Attributes = [Const, NoThrow, RequiredVectorWidth<128>] in {
def vec_set_v8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, short, _Constant int)">;
}
+ let Features = "sse2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def pmulhw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
+ def pmulhuw128 : X86Builtin<"_Vector<8, unsigned short>(_Vector<8, unsigned short>, _Vector<8, unsigned short>)">;
+ }
+
let Features = "sse3" in {
foreach Op = ["addsub", "hadd", "hsub"] in {
def Op#ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>)">;
@@ -265,7 +268,6 @@ let Header = "emmintrin.h", Attributes = [NoThrow, RequireDeclaration] in {
}
let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def pmuludq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">;
def psraw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def psrad128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
def psrlw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
@@ -274,17 +276,25 @@ let Features = "sse2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] i
def psllw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def pslld128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
def psllq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
+ def pmaddwd128 : X86Builtin<"_Vector<4, int>(_Vector<8, short>, _Vector<8, short>)">;
+ def pslldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
+ def psrldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
+}
+
+let Features = "sse2",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def pmuludq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">;
+
def psllwi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">;
def pslldi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">;
def psllqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">;
+
def psrlwi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">;
def psrldi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">;
def psrlqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">;
+
def psrawi128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, int)">;
def psradi128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int)">;
- def pmaddwd128 : X86Builtin<"_Vector<4, int>(_Vector<8, short>, _Vector<8, short>)">;
- def pslldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
- def psrldqi128_byteshift : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
}
let Features = "sse3", Attributes = [NoThrow] in {
@@ -309,7 +319,6 @@ let Features = "sse4.1", Attributes = [NoThrow, Const, RequiredVectorWidth<128>]
def blendvpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">;
def blendvps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">;
def packusdw128 : X86Builtin<"_Vector<8, short>(_Vector<4, int>, _Vector<4, int>)">;
- def pmuldq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">;
def roundps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Constant int)">;
def roundss : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Constant int)">;
def roundsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Constant int)">;
@@ -326,6 +335,10 @@ let Features = "sse4.1", Attributes = [NoThrow, Const, RequiredVectorWidth<128>]
def vec_set_v4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int, _Constant int)">;
}
+let Features = "sse4.1", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def pmuldq128 : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>, _Vector<4, int>)">;
+}
+
let Features = "sse4.2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def pcmpistrm128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>, _Constant char)">;
def pcmpistri128 : X86Builtin<"int(_Vector<16, char>, _Vector<16, char>, _Constant char)">;
@@ -526,28 +539,22 @@ let Features = "avx", Attributes = [NoThrow] in {
let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def lddqu256 : X86Builtin<"_Vector<32, char>(char const *)">;
-}
-let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def maskloadpd : X86Builtin<"_Vector<2, double>(_Vector<2, double const *>, _Vector<2, long long int>)">;
- def maskloadps : X86Builtin<"_Vector<4, float>(_Vector<4, float const *>, _Vector<4, int>)">;
-}
-
-let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def maskloadpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double const *>, _Vector<4, long long int>)">;
def maskloadps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float const *>, _Vector<8, int>)">;
+
+ def maskstorepd256 : X86Builtin<"void(_Vector<4, double *>, _Vector<4, long long int>, _Vector<4, double>)">;
+ def maskstoreps256 : X86Builtin<"void(_Vector<8, float *>, _Vector<8, int>, _Vector<8, float>)">;
}
let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
+ def maskloadpd : X86Builtin<"_Vector<2, double>(_Vector<2, double const *>, _Vector<2, long long int>)">;
+ def maskloadps : X86Builtin<"_Vector<4, float>(_Vector<4, float const *>, _Vector<4, int>)">;
+
def maskstorepd : X86Builtin<"void(_Vector<2, double *>, _Vector<2, long long int>, _Vector<2, double>)">;
def maskstoreps : X86Builtin<"void(_Vector<4, float *>, _Vector<4, int>, _Vector<4, float>)">;
}
-let Features = "avx", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def maskstorepd256 : X86Builtin<"void(_Vector<4, double *>, _Vector<4, long long int>, _Vector<4, double>)">;
- def maskstoreps256 : X86Builtin<"void(_Vector<8, float *>, _Vector<8, int>, _Vector<8, float>)">;
-}
-
let Features = "avx", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def vec_ext_v32qi : X86Builtin<"char(_Vector<32, char>, _Constant int)">;
def vec_ext_v16hi : X86Builtin<"short(_Vector<16, short>, _Constant int)">;
@@ -577,11 +584,7 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
def pmaddubsw256 : X86Builtin<"_Vector<16, short>(_Vector<32, char>, _Vector<32, char>)">;
def pmaddwd256 : X86Builtin<"_Vector<8, int>(_Vector<16, short>, _Vector<16, short>)">;
def pmovmskb256 : X86Builtin<"int(_Vector<32, char>)">;
- def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
def pmulhrsw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
- def pmulhuw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
- def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
- def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
def psadbw256 : X86Builtin<"_Vector<4, long long int>(_Vector<32, char>, _Vector<32, char>)">;
def pshufb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">;
def pshufd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
@@ -590,23 +593,15 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
def psignb256 : X86Builtin<"_Vector<32, char>(_Vector<32, char>, _Vector<32, char>)">;
def psignw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
def psignd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
- def psllwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
def psllw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">;
def pslldqi256_byteshift : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
- def pslldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
def pslld256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">;
- def psllqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">;
def psllq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">;
- def psrawi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
def psraw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">;
- def psradi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
def psrad256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">;
def psrldqi256_byteshift : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
- def psrlwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
def psrlw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<8, short>)">;
- def psrldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
def psrld256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<4, int>)">;
- def psrlqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">;
def psrlq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">;
def pblendd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant int)">;
def pblendd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Constant int)">;
@@ -619,128 +614,73 @@ let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
def insert128i256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>, _Constant int)">;
}
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def maskloadd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int const *>, _Vector<8, int>)">;
- def maskloadq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int const *>, _Vector<4, long long int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def maskloadd : X86Builtin<"_Vector<4, int>(_Vector<4, int const *>, _Vector<4, int>)">;
- def maskloadq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int const *>, _Vector<2, long long int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def maskstored256 : X86Builtin<"void(_Vector<8, int *>, _Vector<8, int>, _Vector<8, int>)">;
- def maskstoreq256 : X86Builtin<"void(_Vector<4, long long int *>, _Vector<4, long long int>, _Vector<4, long long int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def maskstored : X86Builtin<"void(_Vector<4, int *>, _Vector<4, int>, _Vector<4, int>)">;
- def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
-}
+let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
+ def pmuldq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
+ def pmuludq256 : X86Builtin<"_Vector<4, long long int>(_Vector<8, int>, _Vector<8, int>)">;
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
-}
+ def psllwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
+ def pslldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
+ def psllqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">;
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
-}
+ def psrlwi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
+ def psrldi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
+ def psrlqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">;
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
-}
+ def psrawi256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, int)">;
+ def psradi256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int)">;
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
-}
+ def pmulhuw256 : X86Builtin<"_Vector<16, unsigned short>(_Vector<16, unsigned short>, _Vector<16, unsigned short>)">;
+ def pmulhw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>)">;
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+ def psllv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
def psrav8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
def psrlv8si : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+ def psllv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
def psrlv4di : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
}
-let Features = "avx2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx2", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def psllv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
+ def psrav4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
+ def psrlv4si : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
+ def psllv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
def psrlv2di : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
}
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
-}
-
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def gatherd_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, int>, _Vector<4, double>, _Constant char)">;
-}
+ def maskloadd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int const *>, _Vector<8, int>)">;
+ def maskloadq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int const *>, _Vector<4, long long int>)">;
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherq_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<2, long long int>, _Vector<2, double>, _Constant char)">;
-}
+ def maskstored256 : X86Builtin<"void(_Vector<8, int *>, _Vector<8, int>, _Vector<8, int>)">;
+ def maskstoreq256 : X86Builtin<"void(_Vector<4, long long int *>, _Vector<4, long long int>, _Vector<4, long long int>)">;
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
+ def gatherd_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, int>, _Vector<4, double>, _Constant char)">;
def gatherq_pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, double const *, _Vector<4, long long int>, _Vector<4, double>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherd_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, int>, _Vector<4, float>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def gatherd_ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, float const *, _Vector<8, int>, _Vector<8, float>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherq_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<2, long long int>, _Vector<4, float>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def gatherq_ps256 : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, long long int>, _Vector<4, float>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherd_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<4, int>, _Vector<2, long long int>, _Constant char)">;
-}
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def gatherd_q256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, long long int const *, _Vector<4, int>, _Vector<4, long long int>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherq_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">;
-}
-
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
def gatherq_q256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, long long int const *, _Vector<4, long long int>, _Vector<4, long long int>, _Constant char)">;
+ def gatherd_d256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int const *, _Vector<8, int>, _Vector<8, int>, _Constant char)">;
+ def gatherq_d256 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, long long int>, _Vector<4, int>, _Constant char)">;
}
let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherd_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, int>, _Vector<4, int>, _Constant char)">;
-}
+ def maskloadd : X86Builtin<"_Vector<4, int>(_Vector<4, int const *>, _Vector<4, int>)">;
+ def maskloadq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int const *>, _Vector<2, long long int>)">;
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def gatherd_d256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, int const *, _Vector<8, int>, _Vector<8, int>, _Constant char)">;
-}
+ def maskstored : X86Builtin<"void(_Vector<4, int *>, _Vector<4, int>, _Vector<4, int>)">;
+ def maskstoreq : X86Builtin<"void(_Vector<2, long long int *>, _Vector<2, long long int>, _Vector<2, long long int>)">;
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<128>] in {
- def gatherq_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<2, long long int>, _Vector<4, int>, _Constant char)">;
-}
+ def gatherd_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<4, int>, _Vector<2, double>, _Constant char)">;
+ def gatherq_pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, double const *, _Vector<2, long long int>, _Vector<2, double>, _Constant char)">;
+ def gatherd_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<4, int>, _Vector<4, float>, _Constant char)">;
+ def gatherq_ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, float const *, _Vector<2, long long int>, _Vector<4, float>, _Constant char)">;
-let Features = "avx2", Attributes = [NoThrow, RequiredVectorWidth<256>] in {
- def gatherq_d256 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, long long int>, _Vector<4, int>, _Constant char)">;
+ def gatherd_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<4, int>, _Vector<2, long long int>, _Constant char)">;
+ def gatherq_q : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, long long int const *, _Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">;
+ def gatherd_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<4, int>, _Vector<4, int>, _Constant char)">;
+ def gatherq_d : X86Builtin<"_Vector<4, int>(_Vector<4, int>, int const *, _Vector<2, long long int>, _Vector<4, int>, _Constant char)">;
}
let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
@@ -751,14 +691,6 @@ let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] i
def vcvtps2ph256 : X86Builtin<"_Vector<8, short>(_Vector<8, float>, _Constant int)">;
}
-let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vcvtph2ps : X86Builtin<"_Vector<4, float>(_Vector<8, short>)">;
-}
-
-let Features = "f16c", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vcvtph2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, short>)">;
-}
-
let Features = "rdrnd", Attributes = [NoThrow] in {
def rdrand16_step : X86Builtin<"unsigned int(unsigned short *)">;
def rdrand32_step : X86Builtin<"unsigned int(unsigned int *)">;
@@ -878,11 +810,6 @@ let Features = "sha", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in
def sha256msg2 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}
-let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vfmaddps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">;
- def vfmaddpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">;
-}
-
let Features = "fma", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def vfmaddss3 : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>)">;
def vfmaddsd3 : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, double>)">;
@@ -899,8 +826,6 @@ let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<128
}
let Features = "fma|fma4", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vfmaddps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, float>)">;
- def vfmaddpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, double>)">;
def vfmaddsubps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, float>)">;
def vfmaddsubpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, double>)">;
}
@@ -953,14 +878,6 @@ let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in
def vphsubwd : X86Builtin<"_Vector<4, int>(_Vector<8, short>)">;
def vphsubdq : X86Builtin<"_Vector<2, long long int>(_Vector<4, int>)">;
def vpperm : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>, _Vector<16, char>)">;
- def vprotb : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
- def vprotw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
- def vprotd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
- def vprotq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
- def vprotbi : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Constant char)">;
- def vprotwi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant char)">;
- def vprotdi : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant char)">;
- def vprotqi : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant char)">;
def vpshlb : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
def vpshlw : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def vpshld : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
@@ -978,28 +895,23 @@ let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in
def vpcomd : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant char)">;
def vpcomq : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Constant char)">;
def vpermil2pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Vector<2, long long int>, _Constant char)">;
-}
-
-let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpermil2pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, long long int>, _Constant char)">;
-}
-
-let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def vpermil2ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, int>, _Constant char)">;
-}
-
-let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpermil2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, int>, _Constant char)">;
-}
-
-let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def vfrczss : X86Builtin<"_Vector<4, float>(_Vector<4, float>)">;
def vfrczsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">;
def vfrczps : X86Builtin<"_Vector<4, float>(_Vector<4, float>)">;
def vfrczpd : X86Builtin<"_Vector<2, double>(_Vector<2, double>)">;
}
+let Features = "xop", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def vprotbi : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Constant char)">;
+ def vprotwi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Constant char)">;
+ def vprotdi : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant char)">;
+ def vprotqi : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant char)">;
+}
+
let Features = "xop", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+ def vpermil2pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>, _Vector<4, long long int>, _Constant char)">;
+ def vpermil2ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, _Vector<8, int>, _Constant char)">;
def vfrczps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>)">;
def vfrczpd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>)">;
}
@@ -1090,6 +1002,9 @@ let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWi
def cvtpd2ps512_mask : X86Builtin<"_Vector<8, float>(_Vector<8, double>, _Vector<8, float>, unsigned char, _Constant int)">;
def vcvtps2ph512_mask : X86Builtin<"_Vector<16, short>(_Vector<16, float>, _Constant int, _Vector<16, short>, unsigned short)">;
def vcvtph2ps512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, short>, _Vector<16, float>, unsigned short, _Constant int)">;
+}
+
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def pmuldq512 : X86Builtin<"_Vector<8, long long int>(_Vector<16, int>, _Vector<16, int>)">;
def pmuludq512 : X86Builtin<"_Vector<8, long long int>(_Vector<16, int>, _Vector<16, int>)">;
}
@@ -1411,8 +1326,6 @@ let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVector
let Features = "avx512cd,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def vpconflictdi_512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>)">;
def vpconflictsi_512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>)">;
- def vplzcntd_512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>)">;
- def vplzcntq_512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>)">;
}
let Features = "avx512vl,avx512bitalg", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
@@ -1429,7 +1342,10 @@ let Features = "avx512bitalg,evex512", Attributes = [NoThrow, Const, RequiredVec
let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def pmulhrsw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">;
- def pmulhuw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">;
+}
+
+let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def pmulhuw512 : X86Builtin<"_Vector<32, unsigned short>(_Vector<32, unsigned short>, _Vector<32, unsigned short>)">;
def pmulhw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">;
}
@@ -1888,78 +1804,6 @@ let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVect
}
let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshldvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshldvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshldvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshldvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Vector<2, long long int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshldvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>, _Vector<4, long long int>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshldvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>, _Vector<8, long long int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshldvw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>, _Vector<8, short>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshldvw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>, _Vector<16, short>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshldvw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>, _Vector<32, short>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshrdvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshrdvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshrdvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshrdvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>, _Vector<2, long long int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshrdvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>, _Vector<4, long long int>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshrdvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>, _Vector<8, long long int>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vpshrdvw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>, _Vector<8, short>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vpshrdvw256 : X86Builtin<"_Vector<16, short>(_Vector<16, short>, _Vector<16, short>, _Vector<16, short>)">;
-}
-
-let Features = "avx512vbmi2,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def vpshrdvw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>, _Vector<32, short>)">;
-}
-
-let Features = "avx512vl,avx512vbmi2", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def vpshrdd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>, _Constant int)">;
}
@@ -2148,93 +1992,32 @@ let Features = "avx512dq,evex512", Attributes = [NoThrow, Const, RequiredVectorW
def reduceps512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, float>, _Constant int, _Vector<16, float>, unsigned short, _Constant int)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def prold512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
- def prolq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prold128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prold256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prolq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prolq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
-}
-
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def prolvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
- def prolvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">;
def prord512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
+ def prolq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
def prorq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prolvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prolvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prolvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prolvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
+ def prold128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">;
def prord128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prord256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+ def prolq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
def prorq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Constant int)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
+ def prold256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
+ def prord256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Constant int)">;
+ def prolq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
def prorq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Constant int)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def prorvd512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
- def prorvq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prorvd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prorvd256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>, _Vector<8, int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def prorvq128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, _Vector<2, long long int>)">;
-}
-
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def prorvq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<4, long long int>)">;
-}
-
let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def pshufhw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">;
def pshuflw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Constant int)">;
def psllv32hi : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<32, short>)">;
def psllw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
- def psllwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
}
let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
@@ -2245,7 +2028,9 @@ let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVector
def psllv8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def psllwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
def pslldi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">;
def psllqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">;
}
@@ -2262,7 +2047,9 @@ let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVector
def psrlv8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def psrlwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
def psrldi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">;
def psrlqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">;
}
@@ -2288,10 +2075,10 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256
}
let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
- def psraw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
- def psrawi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
- def psrlw512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
- def psrlwi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
+ def psraw512
+ : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
+ def psrlw512
+ : X86Builtin<"_Vector<32, short>(_Vector<32, short>, _Vector<8, short>)">;
def pslldqi512_byteshift : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
def psrldqi512_byteshift : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
}
@@ -2574,22 +2361,6 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256
def rcp14ps256_mask : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>, unsigned char)">;
}
-let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vplzcntd_128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>)">;
-}
-
-let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vplzcntd_256 : X86Builtin<"_Vector<8, int>(_Vector<8, int>)">;
-}
-
-let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vplzcntq_128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>)">;
-}
-
-let Features = "avx512cd,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vplzcntq_256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>)">;
-}
-
let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
def vcvtsd2si32 : X86Builtin<"int(_Vector<2, double>, _Constant int)">;
def vcvtsd2usi32 : X86Builtin<"unsigned int(_Vector<2, double>, _Constant int)">;
@@ -2623,7 +2394,9 @@ let Features = "avx512f", Attributes = [NoThrow, Const, RequiredVectorWidth<128>
def scalefss_round_mask : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Vector<4, float>, unsigned char, _Constant int)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
+ def psrawi512 : X86Builtin<"_Vector<32, short>(_Vector<32, short>, int)">;
def psradi512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, int)">;
def psraqi512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, int)">;
}
@@ -2636,11 +2409,13 @@ let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256
def psraq256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, _Vector<2, long long int>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def psraqi128 : X86Builtin<"_Vector<2, long long int>(_Vector<2, long long int>, int)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl",
+ Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def psraqi256 : X86Builtin<"_Vector<4, long long int>(_Vector<4, long long int>, int)">;
}
@@ -4140,14 +3915,6 @@ let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVecto
def vcvtps2phx512_mask : X86Builtin<"_Vector<16, _Float16>(_Vector<16, float>, _Vector<16, _Float16>, unsigned short, _Constant int)">;
}
-let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vfmaddph : X86Builtin<"_Vector<8, _Float16>(_Vector<8, _Float16>, _Vector<8, _Float16>, _Vector<8, _Float16>)">;
-}
-
-let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vfmaddph256 : X86Builtin<"_Vector<16, _Float16>(_Vector<16, _Float16>, _Vector<16, _Float16>, _Vector<16, _Float16>)">;
-}
-
let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def vfmaddph512_mask : X86Builtin<"_Vector<32, _Float16>(_Vector<32, _Float16>, _Vector<32, _Float16>, _Vector<32, _Float16>, unsigned int, _Constant int)">;
def vfmaddph512_mask3 : X86Builtin<"_Vector<32, _Float16>(_Vector<32, _Float16>, _Vector<32, _Float16>, _Vector<32, _Float16>, unsigned int, _Constant int)">;
@@ -4246,99 +4013,99 @@ let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVecto
def vfcmulcph512_mask : X86Builtin<"_Vector<16, float>(_Vector<16, float>, _Vector<16, float>, _Vector<16, float>, unsigned short, _Constant int)">;
}
-let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectb_128 : X86Builtin<"_Vector<16, char>(unsigned short, _Vector<16, char>, _Vector<16, char>)">;
}
-let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectb_256 : X86Builtin<"_Vector<32, char>(unsigned int, _Vector<32, char>, _Vector<32, char>)">;
}
-let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectb_512 : X86Builtin<"_Vector<64, char>(unsigned long long int, _Vector<64, char>, _Vector<64, char>)">;
}
-let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectw_128 : X86Builtin<"_Vector<8, short>(unsigned char, _Vector<8, short>, _Vector<8, short>)">;
}
-let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512bw,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectw_256 : X86Builtin<"_Vector<16, short>(unsigned short, _Vector<16, short>, _Vector<16, short>)">;
}
-let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512bw,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectw_512 : X86Builtin<"_Vector<32, short>(unsigned int, _Vector<32, short>, _Vector<32, short>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectd_128 : X86Builtin<"_Vector<4, int>(unsigned char, _Vector<4, int>, _Vector<4, int>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectd_256 : X86Builtin<"_Vector<8, int>(unsigned char, _Vector<8, int>, _Vector<8, int>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectd_512 : X86Builtin<"_Vector<16, int>(unsigned short, _Vector<16, int>, _Vector<16, int>)">;
}
-let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectph_128 : X86Builtin<"_Vector<8, _Float16>(unsigned char, _Vector<8, _Float16>, _Vector<8, _Float16>)">;
}
-let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512fp16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectph_256 : X86Builtin<"_Vector<16, _Float16>(unsigned short, _Vector<16, _Float16>, _Vector<16, _Float16>)">;
}
-let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512fp16,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectph_512 : X86Builtin<"_Vector<32, _Float16>(unsigned int, _Vector<32, _Float16>, _Vector<32, _Float16>)">;
}
-let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectpbf_128 : X86Builtin<"_Vector<8, __bf16>(unsigned char, _Vector<8, __bf16>, _Vector<8, __bf16>)">;
}
-let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512bf16,avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectpbf_256 : X86Builtin<"_Vector<16, __bf16>(unsigned short, _Vector<16, __bf16>, _Vector<16, __bf16>)">;
}
-let Features = "avx512bf16,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512bf16,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectpbf_512 : X86Builtin<"_Vector<32, __bf16>(unsigned int, _Vector<32, __bf16>, _Vector<32, __bf16>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectq_128 : X86Builtin<"_Vector<2, long long int>(unsigned char, _Vector<2, long long int>, _Vector<2, long long int>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectq_256 : X86Builtin<"_Vector<4, long long int>(unsigned char, _Vector<4, long long int>, _Vector<4, long long int>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectq_512 : X86Builtin<"_Vector<8, long long int>(unsigned char, _Vector<8, long long int>, _Vector<8, long long int>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectps_128 : X86Builtin<"_Vector<4, float>(unsigned char, _Vector<4, float>, _Vector<4, float>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectps_256 : X86Builtin<"_Vector<8, float>(unsigned char, _Vector<8, float>, _Vector<8, float>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectps_512 : X86Builtin<"_Vector<16, float>(unsigned short, _Vector<16, float>, _Vector<16, float>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<128>] in {
def selectpd_128 : X86Builtin<"_Vector<2, double>(unsigned char, _Vector<2, double>, _Vector<2, double>)">;
}
-let Features = "avx512vl", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
+let Features = "avx512vl", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<256>] in {
def selectpd_256 : X86Builtin<"_Vector<4, double>(unsigned char, _Vector<4, double>, _Vector<4, double>)">;
}
-let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
+let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
def selectpd_512 : X86Builtin<"_Vector<8, double>(unsigned char, _Vector<8, double>, _Vector<8, double>)">;
}
@@ -5373,13 +5140,4 @@ let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth<
let Features = "avx10.2-512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
def vsqrtbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>)">;
- def vfmaddbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>, _Vector<32, __bf16>, _Vector<32, __bf16>)">;
-}
-
-let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth<256>] in {
- def vfmaddbf16256 : X86Builtin<"_Vector<16, __bf16>(_Vector<16, __bf16>, _Vector<16, __bf16>, _Vector<16, __bf16>)">;
-}
-
-let Features = "avx10.2-256", Attributes = [NoThrow, Const, RequiredVectorWidth<128>] in {
- def vfmaddbf16128 : X86Builtin<"_Vector<8, __bf16>(_Vector<8, __bf16>, _Vector<8, __bf16>, _Vector<8, __bf16>)">;
}
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 0cf661a..8173600 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -33,6 +33,7 @@ clang_diag_gen(Parse)
clang_diag_gen(Refactoring)
clang_diag_gen(Sema)
clang_diag_gen(Serialization)
+clang_diag_gen(Trap)
clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups
SOURCE Diagnostic.td
TARGET ClangDiagnosticGroups)
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 423b696..fda0da9 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -58,7 +58,7 @@ ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None, Benig
ENUM_CODEGENOPT(ExceptionHandling, ExceptionHandlingKind, 3, ExceptionHandlingKind::None, NotCompatible)
-CODEGENOPT(ClearASTBeforeBackend , 1, 0, Benign) ///< Free the AST before running backend code generation. Only works with -disable-free.
+CODEGENOPT(ClearASTBeforeBackend , 1, 0, Benign) ///< Free the AST before running backend code generation.
CODEGENOPT(DisableFree , 1, 0, Benign) ///< Don't free memory.
CODEGENOPT(DiscardValueNames , 1, 0, Benign) ///< Discard Value Names from the IR (LLVMContext flag)
CODEGENOPT(DisableLLVMPasses , 1, 0, Benign) ///< Don't run any LLVM IR passes to get
@@ -307,7 +307,7 @@ CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0, Benign) ///< Emit PCs for atomic
CODEGENOPT(SanitizeBinaryMetadataUAR, 1, 0, Benign) ///< Emit PCs for start of functions
///< that are subject for use-after-return checking.
CODEGENOPT(SanitizeStats , 1, 0, Benign) ///< Collect statistics for sanitizers.
-CODEGENOPT(SanitizeDebugTrapReasons, 1, 1 , Benign) ///< Enable UBSan trapping messages
+ENUM_CODEGENOPT(SanitizeDebugTrapReasons, SanitizeDebugTrapReasonKind, 2, SanitizeDebugTrapReasonKind::Detailed, Benign) ///< Control how "trap reasons" are emitted in debug info
CODEGENOPT(SimplifyLibCalls , 1, 1, Benign) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0, Benign) ///< -soft-float.
CODEGENOPT(SpeculativeLoadHardening, 1, 0, Benign) ///< Enable speculative load hardening.
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index cdeedd5..5d5cf25 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -198,6 +198,16 @@ public:
Forced,
};
+ enum SanitizeDebugTrapReasonKind {
+ None, ///< Trap Messages are omitted. This offers the smallest debug info
+ ///< size but at the cost of making traps hard to debug.
+ Basic, ///< Trap Message is fixed per SanitizerKind. Produces smaller debug
+ ///< info than `Detailed` but is not as helpful for debugging.
+ Detailed, ///< Trap Message includes more context (e.g. the expression being
+ ///< overflowed). This is more helpful for debugging but produces
+ ///< larger debug info than `Basic`.
+ };
+
/// The code model to use (-mcmodel).
std::string CodeModel;
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index cee5bed..af26a04 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
@@ -1259,10 +1260,13 @@ class DiagnosticBuilder : public StreamingDiagnostic {
DiagnosticBuilder() = default;
+protected:
DiagnosticBuilder(DiagnosticsEngine *DiagObj, SourceLocation DiagLoc,
unsigned DiagID);
-protected:
+ DiagnosticsEngine *getDiagnosticsEngine() const { return DiagObj; }
+ unsigned getDiagID() const { return DiagID; }
+
/// Clear out the current diagnostic.
void Clear() const {
DiagObj = nullptr;
diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td
index 65b19f3..53b1db2 100644
--- a/clang/include/clang/Basic/Diagnostic.td
+++ b/clang/include/clang/Basic/Diagnostic.td
@@ -30,6 +30,7 @@ def CLASS_REMARK : DiagClass;
def CLASS_WARNING : DiagClass;
def CLASS_EXTENSION : DiagClass;
def CLASS_ERROR : DiagClass;
+def CLASS_TRAP : DiagClass;
// Responses to a diagnostic in a SFINAE context.
class SFINAEResponse;
@@ -144,7 +145,8 @@ class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Ignored>;
class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, SEV_Warning>;
// Notes can provide supplementary information on errors, warnings, and remarks.
class Note<string str> : Diagnostic<str, CLASS_NOTE, SEV_Fatal/*ignored*/>;
-
+// Trap messages attached to traps in debug info.
+class Trap<string str> : Diagnostic<str, CLASS_TRAP, SEV_Fatal/*ignored*/>;
class DefaultIgnore { Severity DefaultSeverity = SEV_Ignored; }
class DefaultWarn { Severity DefaultSeverity = SEV_Warning; }
@@ -235,3 +237,4 @@ include "DiagnosticParseKinds.td"
include "DiagnosticRefactoringKinds.td"
include "DiagnosticSemaKinds.td"
include "DiagnosticSerializationKinds.td"
+include "DiagnosticTrapKinds.td"
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 46d04b0..a63bd80 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -400,6 +400,9 @@ def note_constexpr_non_const_vectorelements : Note<
"cannot determine number of elements for sizeless vectors in a constant expression">;
def note_constexpr_assumption_failed : Note<
"assumption evaluated to false">;
+def note_constexpr_countzeroes_zero : Note<
+ "evaluation of %select{__builtin_elementwise_ctlz|__builtin_elementwise_cttz}0 "
+ "with a zero value is undefined">;
def err_experimental_clang_interp_failed : Error<
"the experimental clang interpreter failed to evaluate an expression">;
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 0f17f4a..b8c7c6e 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -581,6 +581,13 @@ def err_drv_reduced_module_output_overrided : Warning<
"please consider use '-fmodule-output=' to specify the output file for reduced BMI explicitly">,
InGroup<DiagGroup<"reduced-bmi-output-overrided">>;
+def remark_found_cxx20_module_usage : Remark<
+ "found C++20 module usage in file '%0'">,
+ InGroup<ModulesDriver>;
+def remark_performing_driver_managed_module_build : Remark<
+ "performing driver managed module build">,
+ InGroup<ModulesDriver>;
+
def warn_drv_delayed_template_parsing_after_cxx20 : Warning<
"-fdelayed-template-parsing is deprecated after C++20">,
InGroup<DiagGroup<"delayed-template-parsing-in-cxx20">>;
@@ -878,4 +885,9 @@ def warn_drv_openacc_without_cir
: Warning<"OpenACC directives will result in no runtime behavior; use "
"-fclangir to enable runtime effect">,
InGroup<SourceUsesOpenACC>;
+
+def warn_drv_gcc_install_dir_libstdcxx : Warning<
+ "future releases of the clang compiler will prefer GCC installations "
+ "containing libstdc++ include directories; '%0' would be chosen over '%1'">,
+ InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>;
}
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 8a8db27..b7e27d8 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -287,6 +287,10 @@ def err_function_needs_feature : Error<
"always_inline function %1 requires target feature '%2', but would "
"be inlined into function %0 that is compiled without support for '%2'">;
+def err_flatten_function_needs_feature : Error<
+ "flatten function %0 calls %1 which requires target feature '%2', but the "
+ "caller is compiled without support for '%2'">;
+
let CategoryName = "Codegen ABI Check" in {
def err_function_always_inline_attribute_mismatch : Error<
"always_inline function %1 and its caller %0 have mismatching %2 attributes">;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index ccb18aa..0c994e0 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -533,7 +533,14 @@ def Dangling : DiagGroup<"dangling", [DanglingAssignment,
DanglingGsl,
ReturnStackAddress]>;
-def LifetimeSafety : DiagGroup<"experimental-lifetime-safety">;
+def LifetimeSafetyPermissive : DiagGroup<"experimental-lifetime-safety-permissive">;
+def LifetimeSafetyStrict : DiagGroup<"experimental-lifetime-safety-strict">;
+def LifetimeSafety : DiagGroup<"experimental-lifetime-safety",
+ [LifetimeSafetyPermissive, LifetimeSafetyStrict]> {
+ code Documentation = [{
+ Experimental warnings to detect use-after-free and related temporal safety bugs based on lifetime safety analysis.
+ }];
+}
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
def DllexportExplicitInstantiationDecl : DiagGroup<"dllexport-explicit-instantiation-decl">;
@@ -628,6 +635,7 @@ def ModuleConflict : DiagGroup<"module-conflict">;
def ModuleFileExtension : DiagGroup<"module-file-extension">;
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
def ModuleMap : DiagGroup<"module-map">;
+def ModulesDriver : DiagGroup<"modules-driver">;
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
def NewlineEOF : DiagGroup<"newline-eof">;
def Nullability : DiagGroup<"nullability">;
@@ -644,6 +652,7 @@ def NonNull : DiagGroup<"nonnull">;
def NonPODVarargs : DiagGroup<"non-pod-varargs">;
def ClassVarargs : DiagGroup<"class-varargs", [NonPODVarargs]>;
def : DiagGroup<"nonportable-cfstrings">;
+def NonPortableSYCL : DiagGroup<"nonportable-sycl">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def GNUNullPointerArithmetic : DiagGroup<"gnu-null-pointer-arithmetic">;
def NullPointerArithmetic
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h
index b21a3b6..06446cf 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -23,76 +23,80 @@
#include <vector>
namespace clang {
- class DiagnosticsEngine;
- class DiagnosticBuilder;
- class LangOptions;
- class SourceLocation;
-
- // Import the diagnostic enums themselves.
- namespace diag {
- enum class Group;
-
- // Size of each of the diagnostic categories.
- enum {
- DIAG_SIZE_COMMON = 300,
- DIAG_SIZE_DRIVER = 400,
- DIAG_SIZE_FRONTEND = 200,
- DIAG_SIZE_SERIALIZATION = 120,
- DIAG_SIZE_LEX = 500,
- DIAG_SIZE_PARSE = 800,
- DIAG_SIZE_AST = 300,
- DIAG_SIZE_COMMENT = 100,
- DIAG_SIZE_CROSSTU = 100,
- DIAG_SIZE_SEMA = 5000,
- DIAG_SIZE_ANALYSIS = 100,
- DIAG_SIZE_REFACTORING = 1000,
- DIAG_SIZE_INSTALLAPI = 100,
- };
- // Start position for diagnostics.
- enum {
- DIAG_START_COMMON = 0,
- DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
- DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
- DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
- DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
- DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
- DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
- DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
- DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
- DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
- DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
- DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
- DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
- DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
- };
-
- class CustomDiagInfo;
-
- /// All of the diagnostics that can be emitted by the frontend.
- typedef unsigned kind;
-
- /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
- /// to either Ignore (nothing), Remark (emit a remark), Warning
- /// (emit a warning) or Error (emit as an error). It allows clients to
- /// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
- enum class Severity : uint8_t {
- // NOTE: 0 means "uncomputed".
- Ignored = 1, ///< Do not present this diagnostic, ignore it.
- Remark = 2, ///< Present this diagnostic as a remark.
- Warning = 3, ///< Present this diagnostic as a warning.
- Error = 4, ///< Present this diagnostic as an error.
- Fatal = 5 ///< Present this diagnostic as a fatal error.
- };
-
- /// Flavors of diagnostics we can emit. Used to filter for a particular
- /// kind of diagnostic (for instance, for -W/-R flags).
- enum class Flavor {
- WarningOrError, ///< A diagnostic that indicates a problem or potential
- ///< problem. Can be made fatal by -Werror.
- Remark ///< A diagnostic that indicates normal progress through
- ///< compilation.
- };
- } // end namespace diag
+class DiagnosticsEngine;
+class DiagnosticBuilder;
+class LangOptions;
+class SourceLocation;
+
+// Import the diagnostic enums themselves.
+namespace diag {
+enum class Group;
+
+// Size of each of the diagnostic categories.
+enum {
+ DIAG_SIZE_COMMON = 300,
+ DIAG_SIZE_DRIVER = 400,
+ DIAG_SIZE_FRONTEND = 200,
+ DIAG_SIZE_SERIALIZATION = 120,
+ DIAG_SIZE_LEX = 500,
+ DIAG_SIZE_PARSE = 800,
+ DIAG_SIZE_AST = 300,
+ DIAG_SIZE_COMMENT = 100,
+ DIAG_SIZE_CROSSTU = 100,
+ DIAG_SIZE_SEMA = 5000,
+ DIAG_SIZE_ANALYSIS = 100,
+ DIAG_SIZE_REFACTORING = 1000,
+ DIAG_SIZE_INSTALLAPI = 100,
+ DIAG_SIZE_TRAP = 100,
+};
+// Start position for diagnostics.
+// clang-format off
+enum {
+ DIAG_START_COMMON = 0,
+ DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
+ DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
+ DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
+ DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
+ DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
+ DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
+ DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
+ DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
+ DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
+ DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
+ DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
+ DIAG_START_TRAP = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI),
+ DIAG_UPPER_LIMIT = DIAG_START_TRAP + static_cast<int>(DIAG_SIZE_TRAP)
+};
+// clang-format on
+
+class CustomDiagInfo;
+
+/// All of the diagnostics that can be emitted by the frontend.
+typedef unsigned kind;
+
+/// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs
+/// to either Ignore (nothing), Remark (emit a remark), Warning
+/// (emit a warning) or Error (emit as an error). It allows clients to
+/// map ERRORs to Error or Fatal (stop emitting diagnostics after this one).
+enum class Severity : uint8_t {
+ // NOTE: 0 means "uncomputed".
+ Ignored = 1, ///< Do not present this diagnostic, ignore it.
+ Remark = 2, ///< Present this diagnostic as a remark.
+ Warning = 3, ///< Present this diagnostic as a warning.
+ Error = 4, ///< Present this diagnostic as an error.
+ Fatal = 5 ///< Present this diagnostic as a fatal error.
+};
+
+/// Flavors of diagnostics we can emit. Used to filter for a particular
+/// kind of diagnostic (for instance, for -W/-R flags).
+enum class Flavor {
+ WarningOrError, ///< A diagnostic that indicates a problem or potential
+ ///< problem. Can be made fatal by -Werror.
+ Remark ///< A diagnostic that indicates normal progress through
+ ///< compilation.
+};
+} // end namespace diag
} // end namespace clang
// This has to be included *after* the DIAG_START_ enums above are defined.
@@ -173,7 +177,8 @@ public:
/// Used for handling and querying diagnostic IDs.
///
-/// Can be used and shared by multiple Diagnostics for multiple translation units.
+/// Can be used and shared by multiple Diagnostics for multiple translation
+/// units.
class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
public:
/// The level of the diagnostic, after it has been through mapping.
@@ -186,7 +191,8 @@ public:
CLASS_REMARK = 0x02,
CLASS_WARNING = 0x03,
CLASS_EXTENSION = 0x04,
- CLASS_ERROR = 0x05
+ CLASS_ERROR = 0x05,
+ CLASS_TRAP = 0x06
};
static bool IsCustomDiag(diag::kind Diag) {
@@ -360,6 +366,10 @@ public:
///
bool isExtensionDiag(unsigned DiagID, bool &EnabledByDefault) const;
+ bool isTrapDiag(unsigned DiagID) const {
+ return getDiagClass(DiagID) == CLASS_TRAP;
+ }
+
/// Given a group ID, returns the flag that toggles the group.
/// For example, for Group::DeprecatedDeclarations, returns
/// "deprecated-declarations".
@@ -498,6 +508,6 @@ private:
friend class DiagnosticsEngine;
};
-} // end namespace clang
+} // end namespace clang
#endif
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index c7fe6e1d..c03c403 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -912,6 +912,11 @@ def err_mmap_nested_submodule_id : Error<
"qualified module name can only be used to define modules at the top level">;
def err_mmap_expected_feature : Error<"expected a feature name">;
def err_mmap_expected_attribute : Error<"expected an attribute name">;
+def warn_mmap_link_redeclaration : Warning<"redeclaration of link library '%0'">,
+ InGroup<DiagGroup<"module-link-redeclaration">>, DefaultError;
+def note_mmap_prev_link_declaration : Note<"previously declared here">;
+def err_mmap_submodule_link_decl
+ : Error<"link declaration is not allowed in submodules">;
def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">,
InGroup<IgnoredAttributes>;
def warn_mmap_mismatched_private_submodule : Warning<
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 0042afc..ff506fb 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -830,6 +830,9 @@ def err_ms_property_expected_comma_or_rparen : Error<
"expected ',' or ')' at end of property accessor list">;
def err_ms_property_initializer : Error<
"property declaration cannot have a default member initializer">;
+def ext_invalid_attribute_argument
+ : Extension<"'%0' is not allowed in an attribute argument list">,
+ InGroup<DiagGroup<"attribute-preprocessor-tokens">>;
def err_assume_attr_expects_cond_expr : Error<
"use of this expression in an %0 attribute requires parentheses">;
@@ -1503,8 +1506,8 @@ def err_omp_unexpected_directive : Error<
"unexpected OpenMP directive %select{|'#pragma omp %1'}0">;
def err_omp_expected_punc : Error<
"expected ',' or ')' in '%0' %select{clause|directive}1">;
-def warn_clause_expected_string : Warning<
- "expected string literal in 'clause %0' - ignoring">, InGroup<IgnoredPragmas>;
+def warn_clause_expected_string: Warning<
+ "expected string %select{|literal }1in 'clause %0' - ignoring">, InGroup<IgnoredPragmas>;
def err_omp_unexpected_clause : Error<
"unexpected OpenMP clause '%0' in directive '#pragma omp %1'">;
def err_omp_unexpected_clause_extension_only : Error<
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f903b7f..c934fed 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1772,7 +1772,8 @@ def note_unsatisfied_trait
"%Replaceable{replaceable}|"
"%TriviallyCopyable{trivially copyable}|"
"%Empty{empty}|"
- "%StandardLayout{standard-layout}"
+ "%StandardLayout{standard-layout}|"
+ "%Final{final}"
"}1">;
def note_unsatisfied_trait_reason
@@ -1815,7 +1816,9 @@ def note_unsatisfied_trait_reason
"%sub{select_special_member_kind}1}|"
"%FunctionType{is a function type}|"
"%CVVoidType{is a cv void type}|"
- "%IncompleteArrayType{is an incomplete array type}"
+ "%IncompleteArrayType{is an incomplete array type}|"
+ "%NotClassOrUnion{is not a class or union type}|"
+ "%NotMarkedFinal{is not marked 'final'}"
"}0">;
def warn_consteval_if_always_true : Warning<
@@ -3684,6 +3687,10 @@ def warn_alloca_align_alignof : Warning<
"second argument to __builtin_alloca_with_align is supposed to be in bits">,
InGroup<DiagGroup<"alloca-with-align-alignof">>;
+def warn_alloc_size : Warning<
+ "allocation of insufficient size '%0' for type %1 with size '%2'">,
+ InGroup<DiagGroup<"alloc-size">>;
+
def err_alignment_too_small : Error<
"requested alignment must be %0 or greater">;
def err_alignment_too_big : Error<
@@ -4404,6 +4411,11 @@ def warn_impcast_different_enum_types : Warning<
def warn_impcast_int_to_enum : Warning<
"implicit conversion from %0 to enumeration type %1 is invalid in C++">,
InGroup<ImplicitIntToEnumCast>, DefaultIgnore;
+
+def note_no_implicit_conversion_for_scoped_enum
+ : Note<"no implicit conversion for scoped enum; consider casting to "
+ "underlying type">;
+
def warn_impcast_bool_to_null_pointer : Warning<
"initialization of pointer of type %0 to null from a constant boolean "
"expression">, InGroup<BoolConversion>;
@@ -6074,6 +6086,13 @@ def warn_cxx23_pack_indexing : Warning<
def err_pack_outside_template : Error<
"pack declaration outside of template">;
+def err_builtin_pack_outside_template
+ : Error<"%0 cannot be used outside of template">;
+
+def err_unsupported_builtin_template_pack_expansion
+ : Error<"expansions of %0 are not supported here. Only expansions in "
+ "template arguments and class bases are supported">;
+
def err_fold_expression_packs_both_sides : Error<
"binary fold expression has unexpanded parameter packs in both operands">;
def err_fold_expression_empty : Error<
@@ -10423,9 +10442,10 @@ def warn_format_conversion_argument_type_mismatch : Warning<
def warn_format_conversion_argument_type_mismatch_pedantic : Extension<
warn_format_conversion_argument_type_mismatch.Summary>,
InGroup<FormatPedantic>;
-def warn_format_conversion_argument_type_mismatch_signedness : Warning<
- warn_format_conversion_argument_type_mismatch.Summary>,
- InGroup<FormatSignedness>, DefaultIgnore;
+def warn_format_conversion_argument_type_mismatch_signedness: Warning<
+ "format specifies type %0 but the argument has %select{type|underlying "
+ "type}2 %1, which differs in signedness" >
+ , InGroup<FormatSignedness>, DefaultIgnore;
def warn_format_conversion_argument_type_mismatch_confusion : Warning<
warn_format_conversion_argument_type_mismatch.Summary>,
InGroup<FormatTypeConfusion>, DefaultIgnore;
@@ -10537,8 +10557,10 @@ def warn_format_cmp_sensitivity_mismatch : Warning<
"it should be %select{unspecified|private|public|sensitive}1">, InGroup<Format>;
def warn_format_cmp_specifier_mismatch : Warning<
"format specifier '%0' is incompatible with '%1'">, InGroup<Format>;
-def warn_format_cmp_specifier_sign_mismatch : Warning<
- "signedness of format specifier '%0' is incompatible with '%1'">, InGroup<Format>;
+def warn_format_cmp_specifier_sign_mismatch
+ : Warning<"signedness of format specifier '%0' is incompatible with '%1'">,
+ InGroup<FormatSignedness>,
+ DefaultIgnore;
def warn_format_cmp_specifier_mismatch_pedantic : Extension<
warn_format_cmp_specifier_sign_mismatch.Summary>, InGroup<FormatPedantic>;
def note_format_cmp_with : Note<
@@ -10668,9 +10690,15 @@ def warn_dangling_reference_captured_by_unknown : Warning<
"object whose reference is captured will be destroyed at the end of "
"the full-expression">, InGroup<DanglingCapture>;
-def warn_experimental_lifetime_safety_dummy_warning : Warning<
- "todo: remove this warning after we have atleast one warning based on the lifetime analysis">,
- InGroup<LifetimeSafety>, DefaultIgnore;
+// Diagnostics based on the Lifetime safety analysis.
+def warn_lifetime_safety_loan_expires_permissive : Warning<
+ "object whose reference is captured does not live long enough">,
+ InGroup<LifetimeSafetyPermissive>, DefaultIgnore;
+def warn_lifetime_safety_loan_expires_strict : Warning<
+ "object whose reference is captured may not live long enough">,
+ InGroup<LifetimeSafetyStrict>, DefaultIgnore;
+def note_lifetime_safety_used_here : Note<"later used here">;
+def note_lifetime_safety_destroyed_here : Note<"destroyed here">;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
@@ -10985,10 +11013,15 @@ def err_block_on_vm : Error<
def err_sizeless_nonlocal : Error<
"non-local variable with sizeless type %0">;
+def err_vec_masked_load_store_ptr : Error<
+ "%ordinal0 argument must be a %1">;
+def err_vec_masked_load_store_size : Error<
+ "all arguments to %0 must have the same number of elements (was %1 and %2)">;
+
def err_vec_builtin_non_vector : Error<
"%select{first two|all}1 arguments to %0 must be vectors">;
def err_vec_builtin_incompatible_vector : Error<
- "%select{first two|all}1 arguments to %0 must have the same type">;
+ "%select{first two|all|last two}1 arguments to %0 must have the same type">;
def err_vsx_builtin_nonconstant_argument : Error<
"argument %0 to %1 must be a 2-bit unsigned literal (i.e. 0, 1, 2 or 3)">;
@@ -12585,7 +12618,7 @@ def warn_zero_as_null_pointer_constant : Warning<
InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
def warn_not_eliding_copy_on_return : Warning<
- "not eliding copy on return">,
+ "not eliding copy on return">,
InGroup<DiagGroup<"nrvo">>, DefaultIgnore;
def err_nullability_cs_multilevel : Error<
@@ -12850,7 +12883,7 @@ def err_builtin_invalid_arg_type: Error<
"%plural{0:|: }1"
// Second component: integer-like types
"%select{|integer|signed integer|unsigned integer|'int'|"
- "pointer to a valid matrix element}2"
+ "pointer to a valid matrix element|boolean}2"
// A space after a non-empty second component
"%plural{0:|: }2"
// An 'or' if non-empty second and third components are combined
@@ -12942,6 +12975,17 @@ def err_sycl_special_type_num_init_method : Error<
"types with 'sycl_special_class' attribute must have one and only one '__init' "
"method defined">;
+// SYCL external attribute diagnostics
+def err_sycl_external_invalid_linkage : Error<
+ "%0 can only be applied to functions with external linkage">;
+def err_sycl_external_invalid_main : Error<
+ "%0 cannot be applied to the 'main' function">;
+def err_sycl_external_invalid_deleted_function : Error<
+ "%0 cannot be applied to an explicitly deleted function">;
+def warn_sycl_external_missing_on_first_decl : Warning<
+ "%0 attribute does not appear on the first declaration">,
+ InGroup<NonPortableSYCL>;
+
// SYCL kernel entry point diagnostics
def err_sycl_entry_point_invalid : Error<
"the %0 attribute cannot be applied to a"
@@ -12956,7 +13000,7 @@ def err_sycl_kernel_name_conflict : Error<
"the %0 kernel name argument conflicts with a previous declaration">;
def warn_sycl_kernel_name_not_a_class_type : Warning<
"%0 is not a valid SYCL kernel name type; a non-union class type is required">,
- InGroup<DiagGroup<"nonportable-sycl">>, DefaultError;
+ InGroup<NonPortableSYCL>, DefaultError;
def warn_sycl_entry_point_redundant_declaration : Warning<
"redundant %0 attribute">, InGroup<RedundantAttribute>;
def err_sycl_entry_point_after_definition : Error<
@@ -13234,9 +13278,9 @@ def err_wasm_builtin_arg_must_match_table_element_type : Error <
"%ordinal0 argument must match the element type of the WebAssembly table in the %ordinal1 argument">;
def err_wasm_builtin_arg_must_be_integer_type : Error <
"%ordinal0 argument must be an integer">;
-def err_wasm_builtin_test_fp_sig_cannot_include_reference_type
- : Error<"not supported for "
- "function pointers with a reference type %select{return "
+def err_wasm_builtin_test_fp_sig_cannot_include_struct_or_union
+ : Error<"not supported with the multivalue ABI for "
+ "function pointers with a struct/union as %select{return "
"value|parameter}0">;
// OpenACC diagnostics.
@@ -13359,16 +13403,23 @@ def err_acc_reduction_num_gangs_conflict
"appear on a '%2' construct "
"with a '%3' clause%select{ with more than 1 argument|}0">;
def err_acc_reduction_type
- : Error<"OpenACC 'reduction' variable must be of scalar type, aggregate, "
- "sub-array, or a composite of scalar types;%select{| sub-array "
- "base}1 type is %0">;
-def err_acc_reduction_composite_type
- : Error<"OpenACC 'reduction' variable must be a composite of scalar types; "
- "%1 %select{is not a class or struct|is incomplete|is not an "
- "aggregate}0">;
-def err_acc_reduction_composite_member_type :Error<
- "OpenACC 'reduction' composite variable must not have non-scalar field">;
-def note_acc_reduction_composite_member_loc : Note<"invalid field is here">;
+ : Error<"invalid type %0 used in OpenACC 'reduction' variable reference; "
+ "type is %enum_select<OACCReductionTy>{%NotScalar{not a scalar "
+ "value, or array of scalars, or composite of "
+ "scalars}|%MemberNotScalar{not a scalar value}|%NotAgg{not an "
+ "aggregate}|%NotComplete{not a complete type}|%NotClassStruct{not "
+ "a class or struct}}1">;
+def note_acc_reduction_array
+ : Note<"used as element type of "
+ "%enum_select<OACCReductionArray>{%Section{sub-array"
+ "}|%Subscript{array}|%ArrayTy{array}}0 type %1">;
+def note_acc_reduction_member_of_composite
+ : Note<"used as field '%0' of composite '%1'">;
+def note_acc_reduction_type_summary
+ : Note<"OpenACC 'reduction' variable reference must be a scalar variable "
+ "or a "
+ "composite of scalars, or an array, sub-array, or element of scalar "
+ "types">;
def err_acc_loop_not_for_loop
: Error<"OpenACC '%0' construct can only be applied to a 'for' loop">;
def note_acc_construct_here : Note<"'%0' construct is here">;
@@ -13529,8 +13580,13 @@ def err_acc_invalid_modifier
def err_acc_invalid_default_type
: Error<"invalid value %0 in '%1' clause; valid values are %2">;
def err_acc_device_type_multiple_archs
- : Error<"OpenACC 'device_type' clause on a 'set' construct only permits "
+ : Error<"OpenACC 'device_type' clause on a '%0' construct only permits "
"one architecture">;
+def warn_acc_var_referenced_non_const_array
+ : Warning<"variable of array type %0 referenced in OpenACC '%1' clause "
+ "does not have constant bounds; initialization will happen after "
+ "decay to pointer">,
+ InGroup<DiagGroup<"openacc-var-non-const-array">>;
def warn_acc_var_referenced_lacks_op
: Warning<"variable of type %0 referenced in OpenACC '%1' clause does not "
"have a %enum_select<AccVarReferencedReason>{%DefCtor{default "
diff --git a/clang/include/clang/Basic/DiagnosticTrap.h b/clang/include/clang/Basic/DiagnosticTrap.h
new file mode 100644
index 0000000..da8bd25
--- /dev/null
+++ b/clang/include/clang/Basic/DiagnosticTrap.h
@@ -0,0 +1,14 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTICTRAP_H
+#define LLVM_CLANG_BASIC_DIAGNOSTICTRAP_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticTrapInterface.inc"
+
+#endif
diff --git a/clang/include/clang/Basic/DiagnosticTrapKinds.td b/clang/include/clang/Basic/DiagnosticTrapKinds.td
new file mode 100644
index 0000000..c17a88d
--- /dev/null
+++ b/clang/include/clang/Basic/DiagnosticTrapKinds.td
@@ -0,0 +1,30 @@
+//==--- DiagnosticTrapKinds.td ------------------------ -------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// Trap Diagnostics
+//
+// These are diagnostics that are emitted into `TrapReason` objects using the
+// `TrapReasonBuilder` class. These `TrapReason` objects are then encoded into
+// debug info during codegen, rather than to the traditional diagnostic
+// consumers like the terminal. Their primary purpose is to make debugging traps
+// (e.g. `-fsanitize-trap=undefined`) easier by attaching a trap category and
+// message to the trap instruction that tools like a debugger can show.
+//
+//===----------------------------------------------------------------------===//
+let Component = "Trap" in {
+let CategoryName = "Undefined Behavior Sanitizer" in {
+
+def trap_ubsan_arith_overflow : Trap<
+ "%select{unsigned|signed}0 integer "
+ "%enum_select<UBSanArithKind>{"
+ "%Add{addition}|"
+ "%Sub{subtraction}|"
+ "%Mul{multiplication}"
+ "}1 overflow in %2">;
+
+}
+}
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 72f2361..0e91b42a 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -128,6 +128,7 @@ FEATURE(attribute_overloadable, true)
FEATURE(attribute_unavailable_with_message, true)
FEATURE(attribute_unused_on_fields, true)
FEATURE(attribute_diagnose_if_objc, true)
+FEATURE(ext_vector_type_boolean, true)
FEATURE(blocks, LangOpts.Blocks)
FEATURE(c_thread_safety_attributes, true)
FEATURE(cxx_exceptions, LangOpts.CXXExceptions)
@@ -147,14 +148,17 @@ FEATURE(type_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Type))
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
-FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
-EXTENSION(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics)
+FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics &&
+ PP.getTargetInfo().getTriple().isOSDarwin())
+FEATURE(ptrauth_qualifier, LangOpts.PointerAuthIntrinsics &&
+ PP.getTargetInfo().getTriple().isOSDarwin())
FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
+FEATURE(ptrauth_signed_block_descriptors, LangOpts.PointerAuthBlockDescriptorPointers)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
@@ -163,7 +167,7 @@ FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
-FEATURE(ptrauth_objc_signable_class, true)
+FEATURE(ptrauth_objc_signable_class, LangOpts.PointerAuthIntrinsics)
FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)
EXTENSION(swiftcc,
@@ -303,6 +307,14 @@ FEATURE(is_trivially_assignable, LangOpts.CPlusPlus)
FEATURE(is_trivially_constructible, LangOpts.CPlusPlus)
FEATURE(is_trivially_copyable, LangOpts.CPlusPlus)
FEATURE(is_union, LangOpts.CPlusPlus)
+FEATURE(cfi_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::CFI))
+FEATURE(cfi_cast_strict_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFICastStrict))
+FEATURE(cfi_derived_cast_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIDerivedCast))
+FEATURE(cfi_icall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIICall))
+FEATURE(cfi_mfcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIMFCall))
+FEATURE(cfi_unrelated_cast_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIUnrelatedCast))
+FEATURE(cfi_nvcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFINVCall))
+FEATURE(cfi_vcall_sanitizer, LangOpts.Sanitize.has(SanitizerKind::CFIVCall))
FEATURE(kcfi, LangOpts.Sanitize.has(SanitizerKind::KCFI))
FEATURE(kcfi_arity, LangOpts.Sanitize.has(SanitizerKind::KCFI))
FEATURE(modules, LangOpts.Modules)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 08d98a7..e0a5351 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -136,6 +136,8 @@ LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of SEL
LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication key for SEL fields of ObjC interfaces")
LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer authentication")
+LANGOPT(PointerAuthBlockDescriptorPointers, 1, 0, NotCompatible, "enable signed block descriptors")
+
LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes")
@@ -239,6 +241,7 @@ LANGOPT(HLSL, 1, 0, NotCompatible, "HLSL")
ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, NotCompatible, "HLSL Version")
LANGOPT(HLSLStrictAvailability, 1, 0, NotCompatible,
"Strict availability diagnostic mode for HLSL built-in functions.")
+LANGOPT(HLSLSpvUseUnknownImageFormat, 1, 0, NotCompatible, "For storage images and texel buffers, sets the default format to 'Unknown' when not specified via the `vk::image_format` attribute. If this option is not used, the format is inferred from the resource's data type.")
LANGOPT(CUDAIsDevice , 1, 0, NotCompatible, "compiling for CUDA device")
LANGOPT(CUDAAllowVariadicFunctions, 1, 0, NotCompatible, "allowing variadic functions in CUDA device code")
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 0407897..a8943df 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -186,95 +186,10 @@ public:
/// Clang versions with different platform ABI conformance.
enum class ClangABI {
- /// Attempt to be ABI-compatible with code generated by Clang 3.8.x
- /// (SVN r257626). This causes <1 x long long> to be passed in an
- /// integer register instead of an SSE register on x64_64.
- Ver3_8,
-
- /// Attempt to be ABI-compatible with code generated by Clang 4.0.x
- /// (SVN r291814). This causes move operations to be ignored when
- /// determining whether a class type can be passed or returned directly.
- Ver4,
-
- /// Attempt to be ABI-compatible with code generated by Clang 6.0.x
- /// (SVN r321711). This causes determination of whether a type is
- /// standard-layout to ignore collisions between empty base classes
- /// and between base classes and member subobjects, which affects
- /// whether we reuse base class tail padding in some ABIs.
- Ver6,
-
- /// Attempt to be ABI-compatible with code generated by Clang 7.0.x
- /// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be
- /// compatible with __alignof (i.e., return the preferred alignment)
- /// rather than returning the required alignment.
- Ver7,
-
- /// Attempt to be ABI-compatible with code generated by Clang 9.0.x
- /// (SVN r351319). This causes vectors of __int128 to be passed in memory
- /// instead of passing in multiple scalar registers on x86_64 on Linux and
- /// NetBSD.
- Ver9,
-
- /// Attempt to be ABI-compatible with code generated by Clang 11.0.x
- /// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
- /// vector member on the stack instead of using registers, to not properly
- /// mangle substitutions for template names in some cases, and to mangle
- /// declaration template arguments without a cast to the parameter type
- /// even when that can lead to mangling collisions.
- Ver11,
-
- /// Attempt to be ABI-compatible with code generated by Clang 12.0.x
- /// (git 8e464dd76bef). This causes clang to mangle lambdas within
- /// global-scope inline variables incorrectly.
- Ver12,
-
- /// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
- /// This causes clang to:
- /// - mangle dependent nested names incorrectly.
- /// - make trivial only those defaulted copy constructors with a
- /// parameter-type-list equivalent to the parameter-type-list of an
- /// implicit declaration.
- Ver14,
-
- /// Attempt to be ABI-compatible with code generated by Clang 15.0.x.
- /// This causes clang to:
- /// - Reverse the implementation for DR692, DR1395 and DR1432.
- /// - pack non-POD members of packed structs.
- /// - consider classes with defaulted special member functions non-pod.
- Ver15,
-
- /// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
- /// This causes clang to revert some fixes to its implementation of the
- /// Itanium name mangling scheme, with the consequence that overloaded
- /// function templates are mangled the same if they differ only by:
- /// - constraints
- /// - whether a non-type template parameter has a deduced type
- /// - the parameter list of a template template parameter
- Ver17,
-
- /// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
- /// This causes clang to revert some fixes to the mangling of lambdas
- /// in the initializers of members of local classes.
- Ver18,
-
- /// Attempt to be ABI-compatible with code generated by Clang 19.0.x.
- /// This causes clang to:
- /// - Incorrectly mangle the 'base type' substitutions of the CXX
- /// construction vtable because it hasn't added 'type' as a substitution.
- /// - Skip mangling enclosing class templates of member-like friend
- /// function templates.
- /// - Ignore empty struct arguments in C++ mode for ARM, instead of
- /// passing them as if they had a size of 1 byte.
- Ver19,
-
- /// Attempt to be ABI-compatible with code generated by Clang 20.0.x.
- /// This causes clang to:
- /// - Incorrectly return C++ records in AVX registers on x86_64.
- Ver20,
-
- /// Conform to the underlying platform's C and C++ ABIs as closely
- /// as we can.
- Latest
+#define ABI_VER_MAJOR_MINOR(Major, Minor) Ver##Major##_##Minor,
+#define ABI_VER_MAJOR(Major) Ver##Major,
+#define ABI_VER_LATEST(Latest) Latest
+#include "clang/Basic/ABIVersions.def"
};
enum class CoreFoundationABI {
@@ -637,6 +552,10 @@ public:
llvm::dxbc::RootSignatureVersion HLSLRootSigVer =
llvm::dxbc::RootSignatureVersion::V1_1;
+ /// The HLSL root signature that will be used to overide the root signature
+ /// used for the shader entry point.
+ std::string HLSLRootSigOverride;
+
// Indicates if the wasm-opt binary must be ignored in the case of a
// WebAssembly target.
bool NoWasmOpt = false;
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index fb6dddf..2b92025 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -23,6 +23,10 @@
namespace clang {
+/// Constant discriminator to be used with block descriptor pointers. The value
+/// is ptrauth_string_discriminator("block_descriptor")
+constexpr uint16_t BlockDescriptorConstantDiscriminator = 0xC0BB;
+
/// Constant discriminator to be used with function pointers in .init_array and
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
@@ -223,6 +227,18 @@ struct PointerAuthOptions {
/// The ABI for function addresses in .init_array and .fini_array
PointerAuthSchema InitFiniPointers;
+ /// The ABI for block invocation function pointers.
+ PointerAuthSchema BlockInvocationFunctionPointers;
+
+ /// The ABI for block object copy/destroy function pointers.
+ PointerAuthSchema BlockHelperFunctionPointers;
+
+ /// The ABI for __block variable copy/destroy function pointers.
+ PointerAuthSchema BlockByrefHelperFunctionPointers;
+
+ /// The ABI for pointers to block descriptors.
+ PointerAuthSchema BlockDescriptorPointers;
+
/// The ABI for Objective-C method lists.
PointerAuthSchema ObjCMethodListFunctionPointers;
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index ce4677e..25b6862 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -233,8 +233,9 @@ protected:
bool TLSSupported;
bool VLASupported;
bool NoAsmVariants; // True if {|} are normal characters.
- bool HasLegalHalfType; // True if the backend supports operations on the half
- // LLVM IR type.
+ bool HasFastHalfType; // True if the backend has native half float support,
+ // and performing calculations in float instead does
+ // not have a performance advantage.
bool HalfArgsAndReturns; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) type.
bool HasFloat128;
bool HasFloat16;
@@ -700,8 +701,9 @@ public:
return 128;
}
- /// Determine whether _Float16 is supported on this target.
- virtual bool hasLegalHalfType() const { return HasLegalHalfType; }
+ /// Determine whether the target has fast native support for operations
+ /// on half types.
+ virtual bool hasFastHalfType() const { return HasFastHalfType; }
/// Whether half args and returns are supported.
virtual bool allowHalfArgsAndReturns() const { return HalfArgsAndReturns; }
diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h
index 1b133dd..d84f359 100644
--- a/clang/include/clang/Basic/TokenKinds.h
+++ b/clang/include/clang/Basic/TokenKinds.h
@@ -95,10 +95,20 @@ inline bool isStringLiteral(TokenKind K) {
/// Return true if this is a "literal" kind, like a numeric
/// constant, string, etc.
inline bool isLiteral(TokenKind K) {
- return K == tok::numeric_constant || K == tok::char_constant ||
- K == tok::wide_char_constant || K == tok::utf8_char_constant ||
- K == tok::utf16_char_constant || K == tok::utf32_char_constant ||
- isStringLiteral(K) || K == tok::header_name || K == tok::binary_data;
+ const bool isInLiteralRange =
+ K >= tok::numeric_constant && K <= tok::utf32_string_literal;
+
+#if !NDEBUG
+ const bool isLiteralExplicit =
+ K == tok::numeric_constant || K == tok::char_constant ||
+ K == tok::wide_char_constant || K == tok::utf8_char_constant ||
+ K == tok::utf16_char_constant || K == tok::utf32_char_constant ||
+ isStringLiteral(K) || K == tok::header_name || K == tok::binary_data;
+ assert(isInLiteralRange == isLiteralExplicit &&
+ "TokenKind literals should be contiguous");
+#endif
+
+ return isInLiteralRange;
}
/// Return true if this is any of tok::annot_* kinds.
diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td
index 971ce54..fb6862b 100644
--- a/clang/include/clang/Basic/TypeNodes.td
+++ b/clang/include/clang/Basic/TypeNodes.td
@@ -37,21 +37,12 @@ class NeverCanonical {}
/// canonical types can ignore these nodes.
class NeverCanonicalUnlessDependent {}
-/// A type node which never has component type structure. Some code may be
-/// able to operate on leaf types faster than they can on non-leaf types.
-///
-/// For example, the function type `void (int)` is not a leaf type because it
-/// is structurally composed of component types (`void` and `int`).
-///
-/// A struct type is a leaf type because its field types are not part of its
-/// type-expression.
-///
-/// Nodes like `TypedefType` which are syntactically leaves but can desugar
-/// to types that may not be leaves should not declare this.
-class LeafType {}
+/// A type node which is always a canonical type, that is, types for which
+/// `T.getCanonicalType() == T` always holds.
+class AlwaysCanonical {}
def Type : TypeNode<?, 1>;
-def BuiltinType : TypeNode<Type>, LeafType;
+def BuiltinType : TypeNode<Type>, AlwaysCanonical;
def ComplexType : TypeNode<Type>;
def PointerType : TypeNode<Type>;
def BlockPointerType : TypeNode<Type>;
@@ -88,28 +79,29 @@ def TypeOfType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def DecltypeType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def UnaryTransformType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def TagType : TypeNode<Type, 1>;
-def RecordType : TypeNode<TagType>, LeafType;
-def EnumType : TypeNode<TagType>, LeafType;
-def ElaboratedType : TypeNode<Type>, NeverCanonical;
+def RecordType : TypeNode<TagType>;
+def EnumType : TypeNode<TagType>;
+def InjectedClassNameType : TypeNode<TagType>, AlwaysDependent;
def AttributedType : TypeNode<Type>, NeverCanonical;
def BTFTagAttributedType : TypeNode<Type>, NeverCanonical;
def HLSLAttributedResourceType : TypeNode<Type>;
def HLSLInlineSpirvType : TypeNode<Type>;
-def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent, LeafType;
+def TemplateTypeParmType : TypeNode<Type>, AlwaysDependent;
def SubstTemplateTypeParmType : TypeNode<Type>, NeverCanonical;
-def SubstTemplateTypeParmPackType : TypeNode<Type>, AlwaysDependent;
+def SubstPackType : TypeNode<Type, 1>;
+def SubstTemplateTypeParmPackType : TypeNode<SubstPackType>, AlwaysDependent;
+def SubstBuiltinTemplatePackType : TypeNode<SubstPackType>, AlwaysDependent;
def TemplateSpecializationType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def DeducedType : TypeNode<Type, 1>;
def AutoType : TypeNode<DeducedType>;
def DeducedTemplateSpecializationType : TypeNode<DeducedType>;
-def InjectedClassNameType : TypeNode<Type>, AlwaysDependent, LeafType;
def DependentNameType : TypeNode<Type>, AlwaysDependent;
def DependentTemplateSpecializationType : TypeNode<Type>, AlwaysDependent;
def PackExpansionType : TypeNode<Type>, AlwaysDependent;
def PackIndexingType : TypeNode<Type>, NeverCanonicalUnlessDependent;
def ObjCTypeParamType : TypeNode<Type>, NeverCanonical;
def ObjCObjectType : TypeNode<Type>;
-def ObjCInterfaceType : TypeNode<ObjCObjectType>, LeafType;
+def ObjCInterfaceType : TypeNode<ObjCObjectType>, AlwaysCanonical;
def ObjCObjectPointerType : TypeNode<Type>;
def BoundsAttributedType : TypeNode<Type, 1>;
def CountAttributedType : TypeNode<BoundsAttributedType>, NeverCanonical;
diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td
index c491eb0..a4eb92e 100644
--- a/clang/include/clang/Basic/arm_sme.td
+++ b/clang/include/clang/Basic/arm_sme.td
@@ -21,23 +21,21 @@ let SVETargetGuard = InvalidMode in {
// Loads
multiclass ZALoad<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> {
- let SMETargetGuard = "sme" in {
- def NAME # _H : MInst<"svld1_hor_" # n_suffix, "vimPQ", t,
- [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
- MemEltTyDefault, i_prefix # "_horiz", ch>;
-
- def NAME # _H_VNUM : MInst<"svld1_hor_vnum_" # n_suffix, "vimPQl", t,
- [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
- MemEltTyDefault, i_prefix # "_horiz", ch>;
-
- def NAME # _V : MInst<"svld1_ver_" # n_suffix, "vimPQ", t,
- [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
- MemEltTyDefault, i_prefix # "_vert", ch>;
-
- def NAME # _V_VNUM : MInst<"svld1_ver_vnum_" # n_suffix, "vimPQl", t,
- [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
- MemEltTyDefault, i_prefix # "_vert", ch>;
- }
+ def NAME # _H : MInst<"svld1_hor_" # n_suffix, "vimPQ", t,
+ [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
+ MemEltTyDefault, i_prefix # "_horiz", ch>;
+
+ def NAME # _H_VNUM : MInst<"svld1_hor_vnum_" # n_suffix, "vimPQl", t,
+ [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
+ MemEltTyDefault, i_prefix # "_horiz", ch>;
+
+ def NAME # _V : MInst<"svld1_ver_" # n_suffix, "vimPQ", t,
+ [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
+ MemEltTyDefault, i_prefix # "_vert", ch>;
+
+ def NAME # _V_VNUM : MInst<"svld1_ver_vnum_" # n_suffix, "vimPQl", t,
+ [IsLoad, IsOverloadNone, IsStreaming, IsInOutZA],
+ MemEltTyDefault, i_prefix # "_vert", ch>;
}
defm SVLD1_ZA8 : ZALoad<"za8", "c", "aarch64_sme_ld1b", [ImmCheck<0, ImmCheck0_0>]>;
@@ -46,7 +44,6 @@ defm SVLD1_ZA32 : ZALoad<"za32", "i", "aarch64_sme_ld1w", [ImmCheck<0, ImmCheck0
defm SVLD1_ZA64 : ZALoad<"za64", "l", "aarch64_sme_ld1d", [ImmCheck<0, ImmCheck0_7>]>;
defm SVLD1_ZA128 : ZALoad<"za128", "q", "aarch64_sme_ld1q", [ImmCheck<0, ImmCheck0_15>]>;
-let SMETargetGuard = "sme" in {
def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "",
[IsOverloadNone, IsStreamingCompatible, IsInOutZA],
MemEltTyDefault, "aarch64_sme_ldr">;
@@ -54,29 +51,26 @@ def SVLDR_VNUM_ZA : MInst<"svldr_vnum_za", "vmQl", "",
def SVLDR_ZA : MInst<"svldr_za", "vmQ", "",
[IsOverloadNone, IsStreamingCompatible, IsInOutZA],
MemEltTyDefault, "aarch64_sme_ldr", []>;
-}
////////////////////////////////////////////////////////////////////////////////
// Stores
multiclass ZAStore<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> {
- let SMETargetGuard = "sme" in {
- def NAME # _H : MInst<"svst1_hor_" # n_suffix, "vimP%", t,
- [IsStore, IsOverloadNone, IsStreaming, IsInZA],
- MemEltTyDefault, i_prefix # "_horiz", ch>;
-
- def NAME # _H_VNUM : MInst<"svst1_hor_vnum_" # n_suffix, "vimP%l", t,
- [IsStore, IsOverloadNone, IsStreaming, IsInZA],
- MemEltTyDefault, i_prefix # "_horiz", ch>;
-
- def NAME # _V : MInst<"svst1_ver_" # n_suffix, "vimP%", t,
- [IsStore, IsOverloadNone, IsStreaming, IsInZA],
- MemEltTyDefault, i_prefix # "_vert", ch>;
-
- def NAME # _V_VNUM : MInst<"svst1_ver_vnum_" # n_suffix, "vimP%l", t,
- [IsStore, IsOverloadNone, IsStreaming, IsInZA],
- MemEltTyDefault, i_prefix # "_vert", ch>;
- }
+ def NAME # _H : MInst<"svst1_hor_" # n_suffix, "vimP%", t,
+ [IsStore, IsOverloadNone, IsStreaming, IsInZA],
+ MemEltTyDefault, i_prefix # "_horiz", ch>;
+
+ def NAME # _H_VNUM : MInst<"svst1_hor_vnum_" # n_suffix, "vimP%l", t,
+ [IsStore, IsOverloadNone, IsStreaming, IsInZA],
+ MemEltTyDefault, i_prefix # "_horiz", ch>;
+
+ def NAME # _V : MInst<"svst1_ver_" # n_suffix, "vimP%", t,
+ [IsStore, IsOverloadNone, IsStreaming, IsInZA],
+ MemEltTyDefault, i_prefix # "_vert", ch>;
+
+ def NAME # _V_VNUM : MInst<"svst1_ver_vnum_" # n_suffix, "vimP%l", t,
+ [IsStore, IsOverloadNone, IsStreaming, IsInZA],
+ MemEltTyDefault, i_prefix # "_vert", ch>;
}
defm SVST1_ZA8 : ZAStore<"za8", "c", "aarch64_sme_st1b", [ImmCheck<0, ImmCheck0_0>]>;
@@ -85,7 +79,6 @@ defm SVST1_ZA32 : ZAStore<"za32", "i", "aarch64_sme_st1w", [ImmCheck<0, ImmCheck
defm SVST1_ZA64 : ZAStore<"za64", "l", "aarch64_sme_st1d", [ImmCheck<0, ImmCheck0_7>]>;
defm SVST1_ZA128 : ZAStore<"za128", "q", "aarch64_sme_st1q", [ImmCheck<0, ImmCheck0_15>]>;
-let SMETargetGuard = "sme" in {
def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "",
[IsOverloadNone, IsStreamingCompatible, IsInZA],
MemEltTyDefault, "aarch64_sme_str">;
@@ -93,21 +86,18 @@ def SVSTR_VNUM_ZA : MInst<"svstr_vnum_za", "vm%l", "",
def SVSTR_ZA : MInst<"svstr_za", "vm%", "",
[IsOverloadNone, IsStreamingCompatible, IsInZA],
MemEltTyDefault, "aarch64_sme_str", []>;
-}
////////////////////////////////////////////////////////////////////////////////
// Read horizontal/vertical ZA slices
multiclass ZARead<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> {
- let SMETargetGuard = "sme" in {
- def NAME # _H : SInst<"svread_hor_" # n_suffix # "[_{d}]", "ddPim", t,
- MergeOp1, i_prefix # "_horiz",
- [IsReadZA, IsStreaming, IsInZA], ch>;
-
- def NAME # _V : SInst<"svread_ver_" # n_suffix # "[_{d}]", "ddPim", t,
- MergeOp1, i_prefix # "_vert",
- [IsReadZA, IsStreaming, IsInZA], ch>;
- }
+ def NAME # _H : SInst<"svread_hor_" # n_suffix # "[_{d}]", "ddPim", t,
+ MergeOp1, i_prefix # "_horiz",
+ [IsReadZA, IsStreaming, IsInZA], ch>;
+
+ def NAME # _V : SInst<"svread_ver_" # n_suffix # "[_{d}]", "ddPim", t,
+ MergeOp1, i_prefix # "_vert",
+ [IsReadZA, IsStreaming, IsInZA], ch>;
}
defm SVREAD_ZA8 : ZARead<"za8", "cUcm", "aarch64_sme_read", [ImmCheck<2, ImmCheck0_0>]>;
@@ -120,15 +110,13 @@ defm SVREAD_ZA128 : ZARead<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_readq", [I
// Write horizontal/vertical ZA slices
multiclass ZAWrite<string n_suffix, string t, string i_prefix, list<ImmCheck> ch> {
- let SMETargetGuard = "sme" in {
- def NAME # _H : SInst<"svwrite_hor_" # n_suffix # "[_{d}]", "vimPd", t,
- MergeOp1, i_prefix # "_horiz",
- [IsWriteZA, IsStreaming, IsInOutZA], ch>;
-
- def NAME # _V : SInst<"svwrite_ver_" # n_suffix # "[_{d}]", "vimPd", t,
- MergeOp1, i_prefix # "_vert",
- [IsWriteZA, IsStreaming, IsInOutZA], ch>;
- }
+ def NAME # _H : SInst<"svwrite_hor_" # n_suffix # "[_{d}]", "vimPd", t,
+ MergeOp1, i_prefix # "_horiz",
+ [IsWriteZA, IsStreaming, IsInOutZA], ch>;
+
+ def NAME # _V : SInst<"svwrite_ver_" # n_suffix # "[_{d}]", "vimPd", t,
+ MergeOp1, i_prefix # "_vert",
+ [IsWriteZA, IsStreaming, IsInOutZA], ch>;
}
defm SVWRITE_ZA8 : ZAWrite<"za8", "cUcm", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>;
@@ -140,13 +128,11 @@ defm SVWRITE_ZA128 : ZAWrite<"za128", "csilUcUsUiUlmhbfd", "aarch64_sme_writeq",
////////////////////////////////////////////////////////////////////////////////
// SME - Zero
-let SMETargetGuard = "sme" in {
- def SVZERO_MASK_ZA : SInst<"svzero_mask_za", "vi", "", MergeNone, "aarch64_sme_zero",
- [IsOverloadNone, IsStreamingCompatible, IsInOutZA],
- [ImmCheck<0, ImmCheck0_255>]>;
- def SVZERO_ZA : SInst<"svzero_za", "vv", "", MergeNone, "aarch64_sme_zero",
- [IsOverloadNone, IsStreamingCompatible, IsOutZA]>;
-}
+def SVZERO_MASK_ZA : SInst<"svzero_mask_za", "vi", "", MergeNone, "aarch64_sme_zero",
+ [IsOverloadNone, IsStreamingCompatible, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_255>]>;
+def SVZERO_ZA : SInst<"svzero_za", "vv", "", MergeNone, "aarch64_sme_zero",
+ [IsOverloadNone, IsStreamingCompatible, IsOutZA]>;
let SMETargetGuard = "sme2p1" in {
def SVZERO_ZA64_VG1x2 : SInst<"svzero_za64_vg1x2", "vm", "", MergeNone, "aarch64_sme_zero_za64_vg1x2",
@@ -171,11 +157,9 @@ let SMETargetGuard = "sme2p1" in {
// SME - Counting elements in a streaming vector
multiclass ZACount<string n_suffix> {
- let SMETargetGuard = "sme" in {
- def NAME : SInst<"sv" # n_suffix, "nv", "", MergeNone,
- "aarch64_sme_" # n_suffix,
- [IsOverloadNone, IsStreamingCompatible]>;
- }
+ def NAME : SInst<"sv" # n_suffix, "nv", "", MergeNone,
+ "aarch64_sme_" # n_suffix,
+ [IsOverloadNone, IsStreamingCompatible]>;
}
defm SVCNTSB : ZACount<"cntsb">;
@@ -187,11 +171,9 @@ defm SVCNTSD : ZACount<"cntsd">;
// SME - ADDHA/ADDVA
multiclass ZAAdd<string n_suffix> {
- let SMETargetGuard = "sme" in {
- def NAME # _ZA32: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPd", "iUi", MergeOp1,
- "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
- }
+ def NAME # _ZA32: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPd", "iUi", MergeOp1,
+ "aarch64_sme_" # n_suffix, [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
let SMETargetGuard = "sme-i16i64" in {
def NAME # _ZA64: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPd", "lUl", MergeOp1,
@@ -207,13 +189,11 @@ defm SVADDVA : ZAAdd<"addva">;
// SME - SMOPA, SMOPS, UMOPA, UMOPS
multiclass ZAIntOuterProd<string n_suffix1, string n_suffix2> {
- let SMETargetGuard = "sme" in {
- def NAME # _ZA32_B: SInst<"sv" # n_suffix2 # "_za32[_{d}]",
- "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "c",
- MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide",
- [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
- }
+ def NAME # _ZA32_B: SInst<"sv" # n_suffix2 # "_za32[_{d}]",
+ "viPPdd", !cond(!eq(n_suffix1, "s") : "", true: "U") # "c",
+ MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide",
+ [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
let SMETargetGuard = "sme-i16i64" in {
def NAME # _ZA64_H: SInst<"sv" # n_suffix2 # "_za64[_{d}]",
@@ -233,14 +213,12 @@ defm SVUMOPS : ZAIntOuterProd<"u", "mops">;
// SME - SUMOPA, SUMOPS, USMOPA, USMOPS
multiclass ZAIntOuterProdMixedSigns<string n_suffix1, string n_suffix2> {
- let SMETargetGuard = "sme" in {
- def NAME # _ZA32_B: SInst<"sv" # n_suffix1 # n_suffix2 # "_za32[_{d}]",
- "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"),
- !cond(!eq(n_suffix1, "su") : "", true: "U") # "c",
- MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide",
- [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
- }
+ def NAME # _ZA32_B: SInst<"sv" # n_suffix1 # n_suffix2 # "_za32[_{d}]",
+ "viPPd" # !cond(!eq(n_suffix1, "su") : "u", true: "x"),
+ !cond(!eq(n_suffix1, "su") : "", true: "U") # "c",
+ MergeOp1, "aarch64_sme_" # n_suffix1 # n_suffix2 # "_wide",
+ [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
let SMETargetGuard = "sme-i16i64" in {
def NAME # _ZA64_H: SInst<"sv" # n_suffix1 # n_suffix2 # "_za64[_{d}]",
@@ -261,22 +239,20 @@ defm SVUSMOPS : ZAIntOuterProdMixedSigns<"us", "mops">;
// SME - FMOPA, FMOPS
multiclass ZAFPOuterProd<string n_suffix> {
- let SMETargetGuard = "sme" in {
- def NAME # _ZA32_B: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "h",
- MergeOp1, "aarch64_sme_" # n_suffix # "_wide",
- [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
+ def NAME # _ZA32_B: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "h",
+ MergeOp1, "aarch64_sme_" # n_suffix # "_wide",
+ [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
- def NAME # _ZA32_H: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "b",
- MergeOp1, "aarch64_sme_" # n_suffix # "_wide",
- [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
+ def NAME # _ZA32_H: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "b",
+ MergeOp1, "aarch64_sme_" # n_suffix # "_wide",
+ [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
- def NAME # _ZA32_S: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "f",
- MergeOp1, "aarch64_sme_" # n_suffix,
- [IsStreaming, IsInOutZA],
- [ImmCheck<0, ImmCheck0_3>]>;
- }
+ def NAME # _ZA32_S: SInst<"sv" # n_suffix # "_za32[_{d}]", "viPPdd", "f",
+ MergeOp1, "aarch64_sme_" # n_suffix,
+ [IsStreaming, IsInOutZA],
+ [ImmCheck<0, ImmCheck0_3>]>;
let SMETargetGuard = "sme-f64f64" in {
def NAME # _ZA64_D: SInst<"sv" # n_suffix # "_za64[_{d}]", "viPPdd", "d",
diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td
index 07786c6..b8b0f7f 100644
--- a/clang/include/clang/Basic/arm_sve.td
+++ b/clang/include/clang/Basic/arm_sve.td
@@ -36,7 +36,7 @@ def SVLD1UH_VNUM : MInst<"svld1uh_vnum_{d}", "dPXl", "ilUiUl", [IsLoa
def SVLD1SW_VNUM : MInst<"svld1sw_vnum_{d}", "dPUl", "lUl", [IsLoad, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">;
def SVLD1UW_VNUM : MInst<"svld1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_ld1">;
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
// Load one vector (vector base)
def SVLD1_GATHER_BASES_U : MInst<"svld1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ld1_gather_scalar_offset">;
def SVLD1SB_GATHER_BASES_U : MInst<"svld1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ld1_gather_scalar_offset">;
@@ -134,7 +134,7 @@ def SVLDFF1SW_VNUM : MInst<"svldff1sw_vnum_{d}", "dPUl", "lUl", [I
def SVLDFF1UW_VNUM : MInst<"svldff1uw_vnum_{d}", "dPYl", "lUl", [IsLoad, IsZExtReturn], MemEltTyInt32, "aarch64_sve_ldff1">;
}
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
// First-faulting load one vector (vector base)
def SVLDFF1_GATHER_BASES_U : MInst<"svldff1_gather[_{2}base]_{d}", "dPu", "ilUiUlfd", [IsGatherLoad], MemEltTyDefault, "aarch64_sve_ldff1_gather_scalar_offset">;
def SVLDFF1SB_GATHER_BASES_U : MInst<"svldff1sb_gather[_{2}base]_{d}", "dPu", "ilUiUl", [IsGatherLoad], MemEltTyInt8, "aarch64_sve_ldff1_gather_scalar_offset">;
@@ -251,15 +251,15 @@ def SVLD3_VNUM : SInst<"svld3_vnum[_{2}]", "3Pcl", "csilUcUsUiUlhfdbm", MergeNon
def SVLD4_VNUM : SInst<"svld4_vnum[_{2}]", "4Pcl", "csilUcUsUiUlhfdbm", MergeNone, "aarch64_sve_ld4_sret", [IsStructLoad, VerifyRuntimeMode]>;
// Load one octoword and replicate (scalar base)
-let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in {
+let SVETargetGuard = "f64mm", SMETargetGuard = InvalidMode in {
def SVLD1RO : SInst<"svld1ro[_{2}]", "dPc", "csilUcUsUiUlhfdbm", MergeNone, "aarch64_sve_ld1ro">;
}
-let SVETargetGuard = "sve,bf16", SMETargetGuard = InvalidMode in {
+let SVETargetGuard = "bf16", SMETargetGuard = InvalidMode in {
def SVBFMMLA : SInst<"svbfmmla[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmmla", [IsOverloadNone]>;
}
-let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in {
+let SVETargetGuard = "bf16", SMETargetGuard = "bf16" in {
def SVBFDOT : SInst<"svbfdot[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfdot", [IsOverloadNone, VerifyRuntimeMode]>;
def SVBFMLALB : SInst<"svbfmlalb[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalb", [IsOverloadNone, VerifyRuntimeMode]>;
def SVBFMLALT : SInst<"svbfmlalt[_{0}]", "MMdd", "b", MergeNone, "aarch64_sve_bfmlalt", [IsOverloadNone, VerifyRuntimeMode]>;
@@ -326,7 +326,7 @@ def SVST1H_VNUM_U : MInst<"svst1h_vnum[_{d}]", "vPFld", "UiUl", [Is
def SVST1W_VNUM_S : MInst<"svst1w_vnum[_{d}]", "vPCld", "l", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">;
def SVST1W_VNUM_U : MInst<"svst1w_vnum[_{d}]", "vPGld", "Ul", [IsStore, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_st1">;
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
// Store one vector (vector base)
def SVST1_SCATTER_BASES_U : MInst<"svst1_scatter[_{2}base_{d}]", "vPud", "ilUiUlfd", [IsScatterStore], MemEltTyDefault, "aarch64_sve_st1_scatter_scalar_offset">;
def SVST1B_SCATTER_BASES_U : MInst<"svst1b_scatter[_{2}base_{d}]", "vPud", "ilUiUl", [IsScatterStore], MemEltTyInt8, "aarch64_sve_st1_scatter_scalar_offset">;
@@ -464,7 +464,7 @@ def SVPRFH_VNUM : MInst<"svprfh_vnum", "vPQlJ", "s", [IsPrefetch, VerifyRuntimeM
def SVPRFW_VNUM : MInst<"svprfw_vnum", "vPQlJ", "i", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt32, "aarch64_sve_prf">;
def SVPRFD_VNUM : MInst<"svprfd_vnum", "vPQlJ", "l", [IsPrefetch, VerifyRuntimeMode], MemEltTyInt64, "aarch64_sve_prf">;
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
// Prefetch (Vector bases)
def SVPRFB_GATHER_BASES : MInst<"svprfb_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt8, "aarch64_sve_prfb_gather_scalar_offset">;
def SVPRFH_GATHER_BASES : MInst<"svprfh_gather[_{2}base]", "vPdJ", "UiUl", [IsGatherPrefetch], MemEltTyInt16, "aarch64_sve_prfh_gather_scalar_offset">;
@@ -502,7 +502,7 @@ def SVPRFD_GATHER_BASES_OFFSET : MInst<"svprfd_gather[_{2}base]_index", "vPdlJ"
////////////////////////////////////////////////////////////////////////////////
// Address calculations
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
def SVADRB : SInst<"svadrb[_{0}base]_[{2}]offset", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrb">;
def SVADRH : SInst<"svadrh[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrh">;
def SVADRW : SInst<"svadrw[_{0}base]_[{2}]index", "uud", "ilUiUl", MergeNone, "aarch64_sve_adrw">;
@@ -778,11 +778,11 @@ defm SVRINTX : SInstZPZ<"svrintx", "hfd", "aarch64_sve_frintx">;
defm SVRINTZ : SInstZPZ<"svrintz", "hfd", "aarch64_sve_frintz">;
defm SVSQRT : SInstZPZ<"svsqrt", "hfd", "aarch64_sve_fsqrt">;
-let SVETargetGuard = "sve", SMETargetGuard = "sme2,ssve-fexpa" in {
+let SMETargetGuard = "sme2,ssve-fexpa" in {
def SVEXPA : SInst<"svexpa[_{d}]", "du", "hfd", MergeNone, "aarch64_sve_fexpa_x", [VerifyRuntimeMode]>;
}
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
def SVTMAD : SInst<"svtmad[_{d}]", "dddi", "hfd", MergeNone, "aarch64_sve_ftmad_x", [], [ImmCheck<2, ImmCheck0_7>]>;
def SVTSMUL : SInst<"svtsmul[_{d}]", "ddu", "hfd", MergeNone, "aarch64_sve_ftsmul_x">;
def SVTSSEL : SInst<"svtssel[_{d}]", "ddu", "hfd", MergeNone, "aarch64_sve_ftssel_x">;
@@ -825,7 +825,7 @@ def SVRSQRTS : SInst<"svrsqrts[_{d}]", "ddd", "hfd", MergeNone, "aarch64_sve_frs
////////////////////////////////////////////////////////////////////////////////
// Floating-point reductions
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
def SVFADDA : SInst<"svadda[_{d}]", "sPsd", "hfd", MergeNone, "aarch64_sve_fadda">;
}
@@ -946,14 +946,14 @@ defm SVFCVT_F32_F64 : SInstCvtMXZ<"svcvt_f32[_f64]", "MMPd", "MPd", "d", "aarc
defm SVFCVT_F64_F16 : SInstCvtMXZ<"svcvt_f64[_f16]", "ddPO", "dPO", "d", "aarch64_sve_fcvt_f64f16">;
defm SVFCVT_F64_F32 : SInstCvtMXZ<"svcvt_f64[_f32]", "ddPM", "dPM", "d", "aarch64_sve_fcvt_f64f32">;
-let SVETargetGuard = "sve,bf16", SMETargetGuard = "sme,bf16" in {
+let SVETargetGuard = "bf16", SMETargetGuard = "bf16" in {
defm SVCVT_BF16_F32 : SInstCvtMXZ<"svcvt_bf16[_f32]", "$$Pd", "$Pd", "f", "aarch64_sve_fcvt_bf16f32_v2">;
def SVCVTNT_BF16_F32 : SInst<"svcvtnt_bf16[_f32]", "$$Pd", "f", MergeOp1, "aarch64_sve_fcvtnt_bf16f32_v2", [IsOverloadNone, VerifyRuntimeMode]>;
// SVCVTNT_X_BF16_F32 : Implemented as macro by SveEmitter.cpp
}
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVCVTLT_F32_F16 : SInstCvtMX<"svcvtlt_f32[_f16]", "ddPh", "dPh", "f", "aarch64_sve_fcvtlt_f32f16">;
defm SVCVTLT_F64_F32 : SInstCvtMX<"svcvtlt_f64[_f32]", "ddPh", "dPh", "d", "aarch64_sve_fcvtlt_f64f32">;
@@ -980,8 +980,8 @@ defm SVCLASTA_N : SVEPerm<"svclasta[_n_{d}]", "sPsd", "aarch64_sve_clasta_n">;
defm SVCLASTB : SVEPerm<"svclastb[_{d}]", "dPdd", "aarch64_sve_clastb">;
defm SVCLASTB_N : SVEPerm<"svclastb[_n_{d}]", "sPsd", "aarch64_sve_clastb_n">;
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
-def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNone, "aarch64_sve_compact">;
+let SMETargetGuard = "sme2p2" in {
+def SVCOMPACT : SInst<"svcompact[_{d}]", "dPd", "ilUiUlfd", MergeNone, "aarch64_sve_compact", [VerifyRuntimeMode]>;
}
// Note: svdup_lane is implemented using the intrinsic for TBL to represent a
@@ -1088,7 +1088,7 @@ def SVPTEST_LAST : SInst<"svptest_last", "sPP", "Pc", MergeNone, "aarch64_sve_
////////////////////////////////////////////////////////////////////////////////
// FFR manipulation
-let SVETargetGuard = "sve", SMETargetGuard = InvalidMode in {
+let SMETargetGuard = InvalidMode in {
def SVRDFFR : SInst<"svrdffr", "Pv", "Pc", MergeNone, "", [IsOverloadNone]>;
def SVRDFFR_Z : SInst<"svrdffr_z", "PP", "Pc", MergeNone, "", [IsOverloadNone]>;
def SVSETFFR : SInst<"svsetffr", "vv", "", MergeNone, "", [IsOverloadNone]>;
@@ -1173,13 +1173,13 @@ def SVQINCP_N_S64 : SInst<"svqincp[_n_s64]_{d}", "llP", "PcPsPiPl", MergeNone, "
def SVQINCP_N_U32 : SInst<"svqincp[_n_u32]_{d}", "mmP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n32", [VerifyRuntimeMode]>;
def SVQINCP_N_U64 : SInst<"svqincp[_n_u64]_{d}", "nnP", "PcPsPiPl", MergeNone, "aarch64_sve_uqincp_n64", [VerifyRuntimeMode]>;
-let SVETargetGuard = "sve,i8mm", SMETargetGuard = InvalidMode in {
+let SVETargetGuard = "i8mm", SMETargetGuard = InvalidMode in {
def SVMLLA_S32 : SInst<"svmmla[_s32]", "ddqq","i", MergeNone, "aarch64_sve_smmla">;
def SVMLLA_U32 : SInst<"svmmla[_u32]", "ddqq","Ui", MergeNone, "aarch64_sve_ummla">;
def SVUSMLLA_S32 : SInst<"svusmmla[_s32]", "ddbq","i", MergeNone, "aarch64_sve_usmmla">;
}
-let SVETargetGuard = "sve,i8mm", SMETargetGuard = "sme,i8mm"in {
+let SVETargetGuard = "i8mm", SMETargetGuard = "i8mm"in {
def SVUSDOT_S : SInst<"svusdot[_s32]", "ddbq", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>;
def SVUSDOT_N_S : SInst<"svusdot[_n_s32]", "ddbr", "i", MergeNone, "aarch64_sve_usdot", [VerifyRuntimeMode]>;
def SVSUDOT_S : SInst<"svsudot[_s32]", "ddqb", "i", MergeNone, "aarch64_sve_usdot", [ReverseUSDOT, VerifyRuntimeMode]>;
@@ -1189,11 +1189,11 @@ def SVUSDOT_LANE_S : SInst<"svusdot_lane[_s32]", "ddbqi", "i", MergeNone, "aarc
def SVSUDOT_LANE_S : SInst<"svsudot_lane[_s32]", "ddqbi", "i", MergeNone, "aarch64_sve_sudot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndexDot, 2>]>;
}
-let SVETargetGuard = "sve,f32mm", SMETargetGuard = InvalidMode in {
+let SVETargetGuard = "f32mm", SMETargetGuard = InvalidMode in {
def SVMLLA_F32 : SInst<"svmmla[_f32]", "dddd","f", MergeNone, "aarch64_sve_fmmla">;
}
-let SVETargetGuard = "sve,f64mm", SMETargetGuard = InvalidMode in {
+let SVETargetGuard = "f64mm", SMETargetGuard = InvalidMode in {
def SVMLLA_F64 : SInst<"svmmla[_f64]", "dddd", "d", MergeNone, "aarch64_sve_fmmla">;
def SVTRN1Q : SInst<"svtrn1q[_{d}]", "ddd", "csilUcUsUiUlhfdb", MergeNone, "aarch64_sve_trn1q">;
@@ -1243,7 +1243,7 @@ let SVETargetGuard = "sve2p1|sme2", SMETargetGuard = "sve2p1|sme2" in {
////////////////////////////////////////////////////////////////////////////////
// SVE2 WhileGE/GT
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
@@ -1268,7 +1268,7 @@ let SVETargetGuard = "sve2p1|sme2", SMETargetGuard = "sve2p1|sme2" in {
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Uniform DSP operations
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVQADD_S : SInstZPZZ<"svqadd", "csli", "aarch64_sve_sqadd", "aarch64_sve_sqadd">;
defm SVQADD_U : SInstZPZZ<"svqadd", "UcUsUiUl", "aarch64_sve_uqadd", "aarch64_sve_uqadd">;
defm SVHADD_S : SInstZPZZ<"svhadd", "csli", "aarch64_sve_shadd", "aarch64_sve_shadd">;
@@ -1303,7 +1303,7 @@ multiclass SInstZPZxZ<string name, string types, string pat_v, string pat_n, str
def _N_Z : SInst<name # "[_n_{d}]", pat_n, types, MergeZero, intrinsic, flags>;
}
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVQRSHL_S : SInstZPZxZ<"svqrshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqrshl", [VerifyRuntimeMode]>;
defm SVQRSHL_U : SInstZPZxZ<"svqrshl", "UcUsUiUl", "dPdx", "dPdK", "aarch64_sve_uqrshl", [VerifyRuntimeMode]>;
defm SVQSHL_S : SInstZPZxZ<"svqshl", "csil", "dPdx", "dPdK", "aarch64_sve_sqshl", [VerifyRuntimeMode]>;
@@ -1357,7 +1357,7 @@ multiclass SInstPairwise<string name, string types, string intrinsic, list<FlagT
def _X : SInst<name # "[_{d}]", "dPdd", types, MergeAny, intrinsic, flags>;
}
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVADDP : SInstPairwise<"svaddp", "csliUcUsUiUl", "aarch64_sve_addp", [VerifyRuntimeMode]>;
defm SVADDP_F : SInstPairwise<"svaddp", "hfd", "aarch64_sve_faddp", [VerifyRuntimeMode]>;
defm SVMAXNMP : SInstPairwise<"svmaxnmp", "hfd", "aarch64_sve_fmaxnmp", [VerifyRuntimeMode]>;
@@ -1373,7 +1373,7 @@ defm SVMINP_U : SInstPairwise<"svminp", "UcUsUiUl", "aarch64_sve_uminp", [
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Widening pairwise arithmetic
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVADALP_S_M : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeOp1, "aarch64_sve_sadalp", [VerifyRuntimeMode]>;
def SVADALP_S_X : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeAny, "aarch64_sve_sadalp", [VerifyRuntimeMode]>;
def SVADALP_S_Z : SInst<"svadalp[_{d}]", "dPdh", "sil", MergeZero, "aarch64_sve_sadalp", [VerifyRuntimeMode]>;
@@ -1387,7 +1387,7 @@ def SVADALP_U_Z : SInst<"svadalp[_{d}]", "dPdh", "UsUiUl", MergeZero, "aarch64_s
// SVE2 - Bitwise ternary logical instructions
//
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVBCAX : SInst<"svbcax[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bcax", [VerifyRuntimeMode]>;
def SVBSL : SInst<"svbsl[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl", [VerifyRuntimeMode]>;
def SVBSL1N : SInst<"svbsl1n[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_bsl1n", [VerifyRuntimeMode]>;
@@ -1407,7 +1407,7 @@ def SVXAR_N : SInst<"svxar[_n_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aar
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Large integer arithmetic
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVADCLB : SInst<"svadclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclb", [VerifyRuntimeMode]>;
def SVADCLT : SInst<"svadclt[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_adclt", [VerifyRuntimeMode]>;
def SVSBCLB : SInst<"svsbclb[_{d}]", "dddd", "UiUl", MergeNone, "aarch64_sve_sbclb", [VerifyRuntimeMode]>;
@@ -1422,7 +1422,7 @@ def SVSBCLT_N : SInst<"svsbclt[_n_{d}]", "ddda", "UiUl", MergeNone, "aarch64_sve
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Multiplication by indexed elements
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVMLA_LANE_2 : SInst<"svmla_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mla_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>;
def SVMLS_LANE_2 : SInst<"svmls_lane[_{d}]", "ddddi", "silUsUiUl", MergeNone, "aarch64_sve_mls_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>;
def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "aarch64_sve_mul_lane", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckLaneIndex, 1>]>;
@@ -1430,7 +1430,7 @@ def SVMUL_LANE_2 : SInst<"svmul_lane[_{d}]", "dddi", "silUsUiUl", MergeNone, "a
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Uniform complex integer arithmetic
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVCADD : SInst<"svcadd[_{d}]", "dddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>;
def SVSQCADD : SInst<"svqcadd[_{d}]", "dddi", "csil", MergeNone, "aarch64_sve_sqcadd_x", [VerifyRuntimeMode], [ImmCheck<2, ImmCheckComplexRot90_270>]>;
def SVCMLA : SInst<"svcmla[_{d}]", "ddddi", "csilUcUsUiUl", MergeNone, "aarch64_sve_cmla_x", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>;
@@ -1457,7 +1457,7 @@ multiclass SInstWideDSPWide<string name, string types, string intrinsic> {
def _N : SInst<name # "[_n_{d}]", "ddR", types, MergeNone, intrinsic, [VerifyRuntimeMode]>;
}
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVABALB_S : SInstWideDSPAcc<"svabalb", "sil", "aarch64_sve_sabalb">;
defm SVABALB_U : SInstWideDSPAcc<"svabalb", "UsUiUl", "aarch64_sve_uabalb">;
defm SVABALT_S : SInstWideDSPAcc<"svabalt", "sil", "aarch64_sve_sabalt">;
@@ -1536,7 +1536,7 @@ def SVQDMULLT_LANE : SInst<"svqdmullt_lane[_{d}]", "dhhi", "il", MergeNone, "
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Narrowing DSP operations
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVADDHNB : SInst<"svaddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnb", [VerifyRuntimeMode]>;
def SVADDHNT : SInst<"svaddhnt[_{d}]", "hhdd", "silUsUiUl", MergeNone, "aarch64_sve_addhnt", [VerifyRuntimeMode]>;
def SVRADDHNB : SInst<"svraddhnb[_{d}]", "hdd", "silUsUiUl", MergeNone, "aarch64_sve_raddhnb", [VerifyRuntimeMode]>;
@@ -1576,7 +1576,7 @@ def SVQRSHRNT_U : SInst<"svqrshrnt[_n_{d}]", "hhdi", "UsUiUl", MergeNone, "a
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Unary narrowing operations
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVQXTNB_S : SInst<"svqxtnb[_{d}]", "hd", "sil", MergeNone, "aarch64_sve_sqxtnb", [VerifyRuntimeMode]>;
def SVQXTNB_U : SInst<"svqxtnb[_{d}]", "hd", "UsUiUl", MergeNone, "aarch64_sve_uqxtnb", [VerifyRuntimeMode]>;
def SVQXTUNB_S : SInst<"svqxtunb[_{d}]", "ed", "sil", MergeNone, "aarch64_sve_sqxtunb", [VerifyRuntimeMode]>;
@@ -1589,7 +1589,7 @@ def SVQXTUNT_S : SInst<"svqxtunt[_{d}]", "eed", "sil", MergeNone, "aarch64_sv
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Widening complex integer arithmetic
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
defm SVADDLBT : SInstWideDSPLong<"svaddlbt", "sil", "aarch64_sve_saddlbt">;
defm SVSUBLBT : SInstWideDSPLong<"svsublbt", "sil", "aarch64_sve_ssublbt">;
defm SVSUBLTB : SInstWideDSPLong<"svsubltb", "sil", "aarch64_sve_ssubltb">;
@@ -1723,7 +1723,7 @@ def SVSTNT1W_SCATTER_INDEX_S : MInst<"svstnt1w_scatter[_{2}base]_index[_{d}]", "
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Polynomial arithmetic
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVEORBT : SInst<"sveorbt[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>;
def SVEORBT_N : SInst<"sveorbt[_n_{d}]", "ddda", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorbt", [VerifyRuntimeMode]>;
def SVEORTB : SInst<"sveortb[_{d}]", "dddd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eortb", [VerifyRuntimeMode]>;
@@ -1744,7 +1744,7 @@ def SVPMULLT_PAIR_N : SInst<"svpmullt_pair[_n_{d}]", "dda", "UcUi", MergeNone,
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Complex integer dot product
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVCDOT : SInst<"svcdot[_{d}]", "ddqqi", "il", MergeNone, "aarch64_sve_cdot", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckComplexRotAll90>]>;
def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch64_sve_cdot_lane", [VerifyRuntimeMode], [ImmCheck<4, ImmCheckComplexRotAll90>, ImmCheck<3, ImmCheckLaneIndexDot, 2>]>;
}
@@ -1752,7 +1752,7 @@ def SVCDOT_LANE : SInst<"svcdot_lane[_{d}]", "ddqqii", "il", MergeNone, "aarch
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Floating-point widening multiply-accumulate
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVMLALB_F : SInst<"svmlalb[_{d}]", "ddhh", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>;
def SVMLALB_F_N : SInst<"svmlalb[_n_{d}]", "ddhR", "f", MergeNone, "aarch64_sve_fmlalb", [VerifyRuntimeMode]>;
def SVMLALB_F_LANE : SInst<"svmlalb_lane[_{d}]", "ddhhi", "f", MergeNone, "aarch64_sve_fmlalb_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheckLaneIndex, 2>]>;
@@ -1770,7 +1770,7 @@ def SVMLSLT_F_LANE : SInst<"svmlslt_lane[_{d}]", "ddhhi", "f", MergeNone, "aarch
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Floating-point integer binary logarithm
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVLOGB_M : SInst<"svlogb[_{d}]", "xxPd", "hfd", MergeOp1, "aarch64_sve_flogb", [VerifyRuntimeMode]>;
def SVLOGB_X : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeAnyExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>;
def SVLOGB_Z : SInst<"svlogb[_{d}]", "xPd", "hfd", MergeZeroExp, "aarch64_sve_flogb", [VerifyRuntimeMode]>;
@@ -1794,7 +1794,7 @@ def SVNMATCH : SInst<"svnmatch[_{d}]", "PPdd", "csUcUs", MergeNone, "aarch64_sve
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Contiguous conflict detection
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVWHILERW_B : SInst<"svwhilerw[_{1}]", "Pcc", "cUc", MergeNone, "aarch64_sve_whilerw_b", [IsOverloadWhileRW, VerifyRuntimeMode]>;
def SVWHILERW_H : SInst<"svwhilerw[_{1}]", "Pcc", "sUshb", MergeNone, "aarch64_sve_whilerw_h", [IsOverloadWhileRW, VerifyRuntimeMode]>;
def SVWHILERW_S : SInst<"svwhilerw[_{1}]", "Pcc", "iUif", MergeNone, "aarch64_sve_whilerw_s", [IsOverloadWhileRW, VerifyRuntimeMode]>;
@@ -1808,7 +1808,7 @@ def SVWHILEWR_D : SInst<"svwhilewr[_{1}]", "Pcc", "lUld", MergeNone, "aarch64_sv
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Extended table lookup/permute
-let SVETargetGuard = "sve2", SMETargetGuard = "sme" in {
+let SVETargetGuard = "sve2" in {
def SVTBL2 : SInst<"svtbl2[_{d}]", "d2u", "csilUcUsUiUlhfdb", MergeNone, "", [VerifyRuntimeMode]>;
def SVTBX : SInst<"svtbx[_{d}]", "dddu", "csilUcUsUiUlhfdb", MergeNone, "aarch64_sve_tbx", [VerifyRuntimeMode]>;
}
@@ -1828,17 +1828,17 @@ let SVETargetGuard = "sve2,lut", SMETargetGuard = "sme2,lut" in {
////////////////////////////////////////////////////////////////////////////////
// SVE2 - Optional
-let SVETargetGuard = "sve2,sve-aes", SMETargetGuard = InvalidMode in {
-def SVAESD : SInst<"svaesd[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aesd", [IsOverloadNone]>;
-def SVAESIMC : SInst<"svaesimc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesimc", [IsOverloadNone]>;
-def SVAESE : SInst<"svaese[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aese", [IsOverloadNone]>;
-def SVAESMC : SInst<"svaesmc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesmc", [IsOverloadNone]>;
+let SVETargetGuard = "sve2,sve-aes", SMETargetGuard = "ssve-aes" in {
+def SVAESD : SInst<"svaesd[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aesd", [IsOverloadNone, VerifyRuntimeMode]>;
+def SVAESIMC : SInst<"svaesimc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesimc", [IsOverloadNone, VerifyRuntimeMode]>;
+def SVAESE : SInst<"svaese[_{d}]", "ddd", "Uc", MergeNone, "aarch64_sve_aese", [IsOverloadNone, VerifyRuntimeMode]>;
+def SVAESMC : SInst<"svaesmc[_{d}]", "dd", "Uc", MergeNone, "aarch64_sve_aesmc", [IsOverloadNone, VerifyRuntimeMode]>;
-def SVPMULLB_PAIR_U64 : SInst<"svpmullb_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullb_pair">;
-def SVPMULLB_PAIR_N_U64 : SInst<"svpmullb_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullb_pair">;
+def SVPMULLB_PAIR_U64 : SInst<"svpmullb_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullb_pair", [VerifyRuntimeMode]>;
+def SVPMULLB_PAIR_N_U64 : SInst<"svpmullb_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullb_pair", [VerifyRuntimeMode]>;
-def SVPMULLT_PAIR_U64 : SInst<"svpmullt_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullt_pair">;
-def SVPMULLT_PAIR_N_U64 : SInst<"svpmullt_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullt_pair">;
+def SVPMULLT_PAIR_U64 : SInst<"svpmullt_pair[_{d}]", "ddd", "Ul", MergeNone, "aarch64_sve_pmullt_pair", [VerifyRuntimeMode]>;
+def SVPMULLT_PAIR_N_U64 : SInst<"svpmullt_pair[_n_{d}]", "dda", "Ul", MergeNone, "aarch64_sve_pmullt_pair", [VerifyRuntimeMode]>;
}
let SVETargetGuard = "sve-sha3", SMETargetGuard = "sve-sha3,sme2p1" in {
@@ -1850,7 +1850,7 @@ def SVSM4E : SInst<"svsm4e[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm
def SVSM4EKEY : SInst<"svsm4ekey[_{d}]", "ddd", "Ui", MergeNone, "aarch64_sve_sm4ekey", [IsOverloadNone]>;
}
-let SVETargetGuard = "sve2,sve-bitperm", SMETargetGuard = "sme,ssve-bitperm" in {
+let SVETargetGuard = "sve2,sve-bitperm", SMETargetGuard = "ssve-bitperm" in {
def SVBDEP : SInst<"svbdep[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x", [VerifyRuntimeMode]>;
def SVBDEP_N : SInst<"svbdep[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bdep_x", [VerifyRuntimeMode]>;
def SVBEXT : SInst<"svbext[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sve_bext_x", [VerifyRuntimeMode]>;
@@ -1859,7 +1859,7 @@ def SVBGRP : SInst<"svbgrp[_{d}]", "ddd", "UcUsUiUl", MergeNone, "aarch64_sv
def SVBGRP_N : SInst<"svbgrp[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sve_bgrp_x", [VerifyRuntimeMode]>;
}
-let SVETargetGuard = "sve2p1|sme", SMETargetGuard = "sve2p1|sme" in {
+let SVETargetGuard = "sve2p1|sme" in {
def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [VerifyRuntimeMode], []>;
def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [VerifyRuntimeMode], []>;
def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [VerifyRuntimeMode], []>;
@@ -1965,7 +1965,7 @@ def SVDOT_LANE_X2_F : SInst<"svdot_lane[_{d}_{2}]", "ddhhi", "f", MergeNone, "a
def SVFCLAMP : SInst<"svclamp[_{d}]", "dddd", "hfd", MergeNone, "aarch64_sve_fclamp", [VerifyRuntimeMode], []>;
}
-let SVETargetGuard = "sve2p1|sme", SMETargetGuard = "sve2p1|sme" in {
+let SVETargetGuard = "sve2p1|sme" in {
def SVSCLAMP : SInst<"svclamp[_{d}]", "dddd", "csil", MergeNone, "aarch64_sve_sclamp", [VerifyRuntimeMode], []>;
def SVUCLAMP : SInst<"svclamp[_{d}]", "dddd", "UcUsUiUl", MergeNone, "aarch64_sve_uclamp", [VerifyRuntimeMode], []>;
@@ -2340,7 +2340,7 @@ let SVETargetGuard = "sve2,fp8", SMETargetGuard = "sme2,fp8" in {
def SVFCVTNT : SInst<"svcvtnt_mf8[_f32_x2]", "~~2>", "f", MergeNone, "aarch64_sve_fp8_cvtnt", [VerifyRuntimeMode]>;
}
-let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in {
+let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="ssve-fp8dot2" in {
// 8-bit floating-point dot product to half-precision (vectors)
def SVFDOT_2WAY : SInst<"svdot[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>;
def SVFDOT_N_2WAY : SInst<"svdot[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>;
@@ -2349,7 +2349,7 @@ let SVETargetGuard = "sve2,fp8dot2", SMETargetGuard ="sme,ssve-fp8dot2" in {
def SVFDOT_LANE_2WAY : SInst<"svdot_lane[_f16_mf8]", "dd~~i>", "h", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_7>]>;
}
-let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in {
+let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="ssve-fp8dot4" in {
// 8-bit floating-point dot product to single-precision (vectors)
def SVFDOT_4WAY : SInst<"svdot[_f32_mf8]", "dd~~>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>;
def SVFDOT_N_4WAY : SInst<"svdot[_n_f32_mf8]", "dd~!>", "f", MergeNone, "aarch64_sve_fp8_fdot", [VerifyRuntimeMode]>;
@@ -2358,7 +2358,7 @@ let SVETargetGuard = "sve2,fp8dot4", SMETargetGuard ="sme,ssve-fp8dot4" in {
def SVFDOT_LANE_4WAY : SInst<"svdot_lane[_f32_mf8]", "dd~~i>", "f", MergeNone, "aarch64_sve_fp8_fdot_lane", [VerifyRuntimeMode], [ImmCheck<3, ImmCheck0_3>]>;
}
-let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "sme,ssve-fp8fma" in {
+let SVETargetGuard = "sve2,fp8fma", SMETargetGuard = "ssve-fp8fma" in {
// 8-bit floating-point multiply-add long to half-precision (bottom)
def SVFMLALB : SInst<"svmlalb[_f16_mf8]", "dd~~>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>;
def SVFMLALB_N : SInst<"svmlalb[_n_f16_mf8]", "dd~!>", "h", MergeNone, "aarch64_sve_fp8_fmlalb", [VerifyRuntimeMode]>;
diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td
index 275bb2b..cc5ab38 100644
--- a/clang/include/clang/Basic/riscv_vector.td
+++ b/clang/include/clang/Basic/riscv_vector.td
@@ -56,34 +56,8 @@ multiclass RVVVLEFFBuiltin<list<string> types> {
SupportOverloading = false,
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- // Move mask to right before vl.
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- IntrinsicTypes = {ResultType, Ops[4]->getType(), Ops[2]->getType()};
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- IntrinsicTypes = {ResultType, Ops[3]->getType(), Ops[1]->getType()};
- }
- Value *NewVL = Ops[2];
- Ops.erase(Ops.begin() + 2);
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- llvm::Value *LoadValue = Builder.CreateCall(F, Ops, "");
- llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0});
- // Store new_vl.
- clang::CharUnits Align;
- if (IsMasked)
- Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(E->getNumArgs()-2)->getType());
- else
- Align = CGM.getNaturalPointeeTypeAlignment(E->getArg(1)->getType());
- llvm::Value *Val = Builder.CreateExtractValue(LoadValue, {1});
- Builder.CreateStore(Val, Address(NewVL, Val->getType(), Align));
- return V;
- }
+ return emitRVVVLEFFBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach type = types in {
def : RVVBuiltin<"v", "vPCePz", type>;
@@ -139,17 +113,8 @@ multiclass RVVIndexedLoad<string op> {
let HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- if (IsMasked) {
- // Builtin: (mask, ptr, value, vl). Intrinsic: (value, ptr, mask, vl)
- std::swap(Ops[0], Ops[2]);
- } else {
- // Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl)
- std::swap(Ops[0], Ops[1]);
- }
- if (IsMasked)
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
- else
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType()};
+ return emitRVVVSEMaskBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
class RVVVSEMaskBuiltin : RVVBuiltin<"m", "0PUem", "c"> {
let Name = "vsm_v";
@@ -177,17 +142,8 @@ multiclass RVVVSSEBuiltin<list<string> types> {
HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- if (IsMasked) {
- // Builtin: (mask, ptr, stride, value, vl). Intrinsic: (value, ptr, stride, mask, vl)
- std::swap(Ops[0], Ops[3]);
- } else {
- // Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
- std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
- }
- if (IsMasked)
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[4]->getType()};
- else
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[3]->getType()};
+ return emitRVVVSSEBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach type = types in {
def : RVVBuiltin<"v", "0Petv", type>;
@@ -202,17 +158,8 @@ multiclass RVVIndexedStore<string op> {
let HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- if (IsMasked) {
- // Builtin: (mask, ptr, index, value, vl). Intrinsic: (value, ptr, index, mask, vl)
- std::swap(Ops[0], Ops[3]);
- } else {
- // Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl)
- std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
- }
- if (IsMasked)
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[4]->getType()};
- else
- IntrinsicTypes = {Ops[0]->getType(), Ops[1]->getType(), Ops[2]->getType(), Ops[3]->getType()};
+ return emitRVVIndexedStoreBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach type = TypeList in {
foreach eew_list = EEWList[0-2] in {
@@ -367,28 +314,8 @@ multiclass RVVPseudoUnaryBuiltin<string IR, string type_range> {
MaskedIRName = IR # "_mask",
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- }
- auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
- Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
-
- if (IsMasked) {
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- // maskedoff, op1, op2, mask, vl, policy
- IntrinsicTypes = {ResultType, ElemTy, Ops[4]->getType()};
- } else {
- // passthru, op1, op2, vl
- IntrinsicTypes = {ResultType, ElemTy, Ops[3]->getType()};
- }
- break;
- }
+ return emitRVVPseudoUnaryBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
def : RVVBuiltin<"v", "vv", type_range>;
}
@@ -400,32 +327,8 @@ multiclass RVVPseudoVNotBuiltin<string IR, string type_range> {
MaskedIRName = IR # "_mask",
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- }
- auto ElemTy = cast<llvm::VectorType>(ResultType)->getElementType();
- Ops.insert(Ops.begin() + 2,
- llvm::Constant::getAllOnesValue(ElemTy));
- if (IsMasked) {
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- // maskedoff, op1, po2, mask, vl, policy
- IntrinsicTypes = {ResultType,
- ElemTy,
- Ops[4]->getType()};
- } else {
- // passthru, op1, op2, vl
- IntrinsicTypes = {ResultType,
- ElemTy,
- Ops[3]->getType()};
- }
- break;
- }
+ return emitRVVPseudoVNotBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
def : RVVBuiltin<"v", "vv", type_range>;
def : RVVBuiltin<"Uv", "UvUv", type_range>;
@@ -437,13 +340,8 @@ multiclass RVVPseudoMaskBuiltin<string IR, string type_range> {
IRName = IR,
HasMasked = false,
ManualCodegen = [{
- {
- // op1, vl
- IntrinsicTypes = {ResultType,
- Ops[1]->getType()};
- Ops.insert(Ops.begin() + 1, Ops[0]);
- break;
- }
+ return emitRVVPseudoMaskBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
def : RVVBuiltin<"m", "mm", type_range>;
}
@@ -455,28 +353,8 @@ multiclass RVVPseudoVFUnaryBuiltin<string IR, string type_range> {
MaskedIRName = IR # "_mask",
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- Ops.insert(Ops.begin() + 2, Ops[1]);
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- // maskedoff, op1, op2, mask, vl
- IntrinsicTypes = {ResultType,
- Ops[2]->getType(),
- Ops.back()->getType()};
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- // op1, po2, vl
- IntrinsicTypes = {ResultType,
- Ops[1]->getType(), Ops[2]->getType()};
- Ops.insert(Ops.begin() + 2, Ops[1]);
- break;
- }
- break;
- }
+ return emitRVVPseudoVFUnaryBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
def : RVVBuiltin<"v", "vv", type_range>;
}
@@ -490,33 +368,8 @@ multiclass RVVPseudoVWCVTBuiltin<string IR, string MName, string type_range,
MaskedIRName = IR # "_mask",
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- }
- auto ElemTy = cast<llvm::VectorType>(Ops[1]->getType())->getElementType();
- Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(ElemTy));
- if (IsMasked) {
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- // maskedoff, op1, op2, mask, vl, policy
- IntrinsicTypes = {ResultType,
- Ops[1]->getType(),
- ElemTy,
- Ops[4]->getType()};
- } else {
- // passtru, op1, op2, vl
- IntrinsicTypes = {ResultType,
- Ops[1]->getType(),
- ElemTy,
- Ops[3]->getType()};
- }
- break;
- }
+ return emitRVVPseudoVWCVTBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach s_p = suffixes_prototypes in {
def : RVVBuiltin<s_p[0], s_p[1], type_range>;
@@ -532,32 +385,8 @@ multiclass RVVPseudoVNCVTBuiltin<string IR, string MName, string type_range,
MaskedIRName = IR # "_mask",
UnMaskedPolicyScheme = HasPassthruOperand,
ManualCodegen = [{
- {
- if (IsMasked) {
- std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
- if ((PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA))
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- } else {
- if (PolicyAttrs & RVV_VTA)
- Ops.insert(Ops.begin(), llvm::PoisonValue::get(ResultType));
- }
- Ops.insert(Ops.begin() + 2, llvm::Constant::getNullValue(Ops.back()->getType()));
- if (IsMasked) {
- Ops.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- // maskedoff, op1, xlen, mask, vl
- IntrinsicTypes = {ResultType,
- Ops[1]->getType(),
- Ops[4]->getType(),
- Ops[4]->getType()};
- } else {
- // passthru, op1, xlen, vl
- IntrinsicTypes = {ResultType,
- Ops[1]->getType(),
- Ops[3]->getType(),
- Ops[3]->getType()};
- }
- break;
- }
+ return emitRVVPseudoVNCVTBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach s_p = suffixes_prototypes in {
def : RVVBuiltin<s_p[0], s_p[1], type_range>;
@@ -575,17 +404,8 @@ let HasBuiltinAlias = false, HasVL = false, HasMasked = false,
UnMaskedPolicyScheme = NonePolicy, MaskedPolicyScheme = NonePolicy,
Log2LMUL = [0], IRName = "",
ManualCodegen = [{
- {
- LLVMContext &Context = CGM.getLLVMContext();
- llvm::MDBuilder MDHelper(Context);
-
- llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "vlenb")};
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
- llvm::Function *F =
- CGM.getIntrinsic(llvm::Intrinsic::read_register, {SizeTy});
- return Builder.CreateCall(F, Metadata);
- }
+ return emitRVVVlenbBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in
{
def vlenb : RVVBuiltin<"", "u", "i">;
@@ -660,7 +480,10 @@ let HasBuiltinAlias = false,
HasMasked = false,
MaskedPolicyScheme = NonePolicy,
Log2LMUL = [0],
- ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type
+ ManualCodegen = [{
+ return emitRVVVsetvliBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
+ }] in // Set XLEN type
{
def vsetvli : RVVBuiltin<"", "zzKzKz", "i">;
def vsetvlimax : RVVBuiltin<"", "zKzKz", "i">;
@@ -720,43 +543,10 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
ManualCodegen = [{
- {
- SmallVector<llvm::Value*, 6> Operands;
-
- bool NoPassthru =
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
- (!IsMasked && (PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
-
- if (IsMasked)
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[0]->getType(), Ops.back()->getType()};
- else
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
-
- if (NoPassthru) { // Push poison into passthru
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- } else { // Push intrinsics operands into passthru
- llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
- Operands.push_back(PassthruOperand);
- }
-
- Operands.push_back(Ops[Offset]); // Ptr
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 1]); // VL
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
-
- llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
- if (ReturnValue.isNull())
- return LoadValue;
- else
- return Builder.CreateStore(LoadValue, ReturnValue.getValue());
- }
- }] in {
+ return emitRVVUnitStridedSegLoadTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs,
+ IsMasked, SegInstSEW);
+ }] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", T # "vPCe", type>;
if !not(IsFloat<type>.val) then {
@@ -784,31 +574,10 @@ multiclass RVVUnitStridedSegStoreTuple<string op> {
NF = nf,
HasMaskedOffOperand = false,
ManualCodegen = [{
- {
- // Masked
- // Builtin: (mask, ptr, v_tuple, vl)
- // Intrinsic: (tuple, ptr, mask, vl)
- // Unmasked
- // Builtin: (ptr, v_tuple, vl)
- // Intrinsic: (tuple, ptr, vl)
- unsigned Offset = IsMasked ? 1 : 0;
-
- SmallVector<llvm::Value*, 5> Operands;
- Operands.push_back(Ops[Offset + 1]); // tuple
- Operands.push_back(Ops[Offset]); // Ptr
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 2]); // VL
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- if (IsMasked)
- IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[0]->getType(), Operands.back()->getType()};
- else
- IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
- }
- }] in {
+ return emitRVVUnitStridedSegStoreTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs,
+ IsMasked, SegInstSEW);
+ }] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", "0Pe" # T # "v", type>;
if !not(IsFloat<type>.val) then {
@@ -835,52 +604,9 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
MaskedIRName = op # nf # "ff_mask",
NF = nf,
ManualCodegen = [{
- {
- SmallVector<llvm::Value*, 6> Operands;
-
- bool NoPassthru =
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
- (!IsMasked && (PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
-
- if (IsMasked)
- IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType(), Ops[0]->getType()};
- else
- IntrinsicTypes = {ResultType, Ops.back()->getType(), Ops[Offset]->getType()};
-
- if (NoPassthru) { // Push poison into passthru
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- } else { // Push intrinsics operands into passthru
- llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
- Operands.push_back(PassthruOperand);
- }
-
- Operands.push_back(Ops[Offset]); // Ptr
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 2]); // vl
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
-
- llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
- // Get alignment from the new vl operand
- clang::CharUnits Align =
- CGM.getNaturalPointeeTypeAlignment(E->getArg(Offset + 1)->getType());
-
- llvm::Value *ReturnTuple = Builder.CreateExtractValue(LoadValue, 0);
-
- // Store new_vl
- llvm::Value *V = Builder.CreateExtractValue(LoadValue, 1);
- Builder.CreateStore(V, Address(Ops[Offset + 1], V->getType(), Align));
-
- if (ReturnValue.isNull())
- return ReturnTuple;
- else
- return Builder.CreateStore(ReturnTuple, ReturnValue.getValue());
- }
+ return emitRVVUnitStridedSegLoadFFTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", T # "vPCePz", type>;
@@ -908,43 +634,9 @@ multiclass RVVStridedSegLoadTuple<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
ManualCodegen = [{
- {
- SmallVector<llvm::Value*, 7> Operands;
-
- bool NoPassthru =
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
- (!IsMasked && (PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
-
- if (IsMasked)
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType(), Ops[0]->getType()};
- else
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops.back()->getType()};
-
- if (NoPassthru) { // Push poison into passthru
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- } else { // Push intrinsics operands into passthru
- llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
- Operands.push_back(PassthruOperand);
- }
-
- Operands.push_back(Ops[Offset]); // Ptr
- Operands.push_back(Ops[Offset + 1]); // Stride
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 2]); // VL
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
-
- if (ReturnValue.isNull())
- return LoadValue;
- else
- return Builder.CreateStore(LoadValue, ReturnValue.getValue());
- }
+ return emitRVVStridedSegLoadTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", T # "vPCet", type>;
@@ -974,31 +666,9 @@ multiclass RVVStridedSegStoreTuple<string op> {
HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- {
- // Masked
- // Builtin: (mask, ptr, stride, v_tuple, vl)
- // Intrinsic: (tuple, ptr, stride, mask, vl)
- // Unmasked
- // Builtin: (ptr, stride, v_tuple, vl)
- // Intrinsic: (tuple, ptr, stride, vl)
- unsigned Offset = IsMasked ? 1 : 0;
-
- SmallVector<llvm::Value*, 6> Operands;
- Operands.push_back(Ops[Offset + 2]); // tuple
- Operands.push_back(Ops[Offset]); // Ptr
- Operands.push_back(Ops[Offset + 1]); // Stride
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 3]); // VL
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- if (IsMasked)
- IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType(), Ops[0]->getType()};
- else
- IntrinsicTypes = {Operands[0]->getType(), Operands[1]->getType(), Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
- }
+ return emitRVVStridedSegStoreTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", "0Pet" # T # "v", type>;
@@ -1021,47 +691,9 @@ multiclass RVVIndexedSegLoadTuple<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
ManualCodegen = [{
- {
- SmallVector<llvm::Value*, 7> Operands;
-
- bool NoPassthru =
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) |
- (!IsMasked && (PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ? NoPassthru ? 1 : 2 : NoPassthru ? 0 : 1;
-
- if (NoPassthru) { // Push poison into passthru
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- } else { // Push intrinsics operands into passthru
- llvm::Value *PassthruOperand = IsMasked ? Ops[1] : Ops[0];
- Operands.push_back(PassthruOperand);
- }
-
- Operands.push_back(Ops[Offset]); // Ptr
- Operands.push_back(Ops[Offset + 1]); // Idx
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 2]); // VL
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- if (IsMasked)
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
- Ops[Offset + 1]->getType(),
- Ops[0]->getType(),
- Ops.back()->getType()};
- else
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
- Ops[Offset + 1]->getType(),
- Ops.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- llvm::Value *LoadValue = Builder.CreateCall(F, Operands, "");
-
- if (ReturnValue.isNull())
- return LoadValue;
- else
- return Builder.CreateStore(LoadValue, ReturnValue.getValue());
- }
+ return emitRVVIndexedSegLoadTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", T # "vPCe" # eew_type # "Uv", type>;
@@ -1087,34 +719,9 @@ multiclass RVVIndexedSegStoreTuple<string op> {
HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- {
- // Masked
- // Builtin: (mask, ptr, index, v_tuple, vl)
- // Intrinsic: (tuple, ptr, index, mask, vl)
- // Unmasked
- // Builtin: (ptr, index, v_tuple, vl)
- // Intrinsic: (tuple, ptr, index, vl)
- unsigned Offset = IsMasked ? 1 : 0;
-
- SmallVector<llvm::Value*, 6> Operands;
- Operands.push_back(Ops[Offset + 2]); // tuple
- Operands.push_back(Ops[Offset]); // Ptr
- Operands.push_back(Ops[Offset + 1]); // Idx
- if (IsMasked)
- Operands.push_back(Ops[0]);
- Operands.push_back(Ops[Offset + 3]); // VL
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), SegInstSEW));
-
- if (IsMasked)
- IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
- Ops[0]->getType(),
- Operands.back()->getType()};
- else
- IntrinsicTypes = {Operands[0]->getType(), Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
- Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
- }
+ return emitRVVIndexedSegStoreTupleBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}] in {
defvar T = "(Tuple:" # nf # ")";
def : RVVBuiltin<T # "v", "0Pe" # eew_type # "Uv" # T # "v", type>;
@@ -1355,37 +962,8 @@ defm vssub : RVVSignedBinBuiltinSet;
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- Operands.push_back(Ops[Offset + 2]); // vxrm
- Operands.push_back(Ops[Offset + 3]); // vl
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(), Ops.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVAveragingBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
// 12.2. Vector Single-Width Averaging Add and Subtract
@@ -1404,38 +982,8 @@ let ManualCodegen = [{
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, vxrm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- Operands.push_back(Ops[Offset + 2]); // vxrm
- Operands.push_back(Ops[Offset + 3]); // vl
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
- Ops.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVNarrowingClipBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
// 12.5. Vector Narrowing Fixed-Point Clip Instructions
@@ -1459,47 +1007,8 @@ enum __RISCV_FRM {
let UnMaskedPolicyScheme = HasPassthruOperand in {
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- bool HasRoundModeOp = IsMasked ?
- (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
- (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
-
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 2]); // frm
- Operands.push_back(Ops[Offset + 3]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- }
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset + 1]->getType(),
- Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVFloatingPointBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = true in {
@@ -1536,47 +1045,9 @@ let ManualCodegen = [{
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- bool HasRoundModeOp = IsMasked ?
- (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
- (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
-
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 2]); // frm
- Operands.push_back(Ops[Offset + 3]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- }
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
- Ops.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVWideningFloatingPointBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = true in {
@@ -1618,39 +1089,8 @@ let ManualCodegen = [{
let UnMaskedPolicyScheme = HasPolicyOperand in {
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
-
- unsigned Offset = IsMasked ? 2 : 1;
-
- Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 2]); // frm
- Operands.push_back(Ops[Offset + 3]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- }
-
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
- Operands.back()->getType()};
-
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
-
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVFMABuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = 1 in {
@@ -1677,39 +1117,8 @@ let ManualCodegen = [{
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 7> Operands;
- bool HasRoundModeOp = IsMasked ? Ops.size() == 6 : Ops.size() == 5;
-
- unsigned Offset = IsMasked ? 2 : 1;
-
- Operands.push_back(Ops[IsMasked ? 1 : 0]); // passthrough
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 2]); // frm
- Operands.push_back(Ops[Offset + 3]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- }
-
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(), Ops[Offset + 1]->getType(),
- Operands.back()->getType()};
-
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
-
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVWideningFMABuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = 1 in {
@@ -1747,45 +1156,8 @@ let ManualCodegen = [{
let UnMaskedPolicyScheme = HasPassthruOperand in {
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, round_mode, vl)
- // Masked: (passthru, op0, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 6> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- bool HasRoundModeOp = IsMasked ?
- (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
- (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
-
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 1]); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 1]); // vl
- }
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVFloatingUnaryBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = 1 in {
@@ -1947,45 +1319,8 @@ def vfwcvtbf16_f_f_v : RVVConvBuiltin<"Fw", "Fwv", "y", "vfwcvtbf16_f">;
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, frm, vl)
- // Masked: (passthru, op0, mask, frm, vl, policy)
- SmallVector<llvm::Value*, 6> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- bool HasRoundModeOp = IsMasked ?
- (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4) :
- (HasMaskedOff ? Ops.size() == 4 : Ops.size() == 3);
-
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 1]); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 1]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 1]); // vl
- }
-
- if (IsMasked)
- Operands.push_back(ConstantInt::get(Ops.back()->getType(), PolicyAttrs));
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
- Operands.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVFloatingConvBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = 1 in {
@@ -2151,44 +1486,9 @@ defm vfredmax : RVVFloatingReductionBuiltin;
defm vfredmin : RVVFloatingReductionBuiltin;
let ManualCodegen = [{
{
- // LLVM intrinsic
- // Unmasked: (passthru, op0, op1, round_mode, vl)
- // Masked: (passthru, vector_in, vector_in/scalar_in, mask, frm, vl, policy)
-
- SmallVector<llvm::Value*, 6> Operands;
- bool HasMaskedOff = !(
- (IsMasked && (PolicyAttrs & RVV_VTA) && (PolicyAttrs & RVV_VMA)) ||
- (!IsMasked && PolicyAttrs & RVV_VTA));
- bool HasRoundModeOp = IsMasked ?
- (HasMaskedOff ? Ops.size() == 6 : Ops.size() == 5) :
- (HasMaskedOff ? Ops.size() == 5 : Ops.size() == 4);
-
- unsigned Offset = IsMasked ?
- (HasMaskedOff ? 2 : 1) : (HasMaskedOff ? 1 : 0);
-
- if (!HasMaskedOff)
- Operands.push_back(llvm::PoisonValue::get(ResultType));
- else
- Operands.push_back(Ops[IsMasked ? 1 : 0]);
-
- Operands.push_back(Ops[Offset]); // op0
- Operands.push_back(Ops[Offset + 1]); // op1
-
- if (IsMasked)
- Operands.push_back(Ops[0]); // mask
-
- if (HasRoundModeOp) {
- Operands.push_back(Ops[Offset + 2]); // frm
- Operands.push_back(Ops[Offset + 3]); // vl
- } else {
- Operands.push_back(ConstantInt::get(Ops[Offset + 2]->getType(), 7)); // frm
- Operands.push_back(Ops[Offset + 2]); // vl
- }
-
- IntrinsicTypes = {ResultType, Ops[Offset]->getType(),
- Ops.back()->getType()};
- llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
- return Builder.CreateCall(F, Operands, "");
+ return emitRVVFloatingReductionBuiltin(
+ this, E, ReturnValue, ResultType, ID, Ops, PolicyAttrs, IsMasked,
+ SegInstSEW);
}
}] in {
let HasFRMRoundModeOp = 1 in {
@@ -2346,37 +1646,8 @@ let HasMasked = false,
let HasMasked = false, HasVL = false, IRName = "" in {
let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- if (ResultType->isIntOrIntVectorTy(1) ||
- Ops[0]->getType()->isIntOrIntVectorTy(1)) {
- assert(isa<ScalableVectorType>(ResultType) &&
- isa<ScalableVectorType>(Ops[0]->getType()));
-
- LLVMContext &Context = CGM.getLLVMContext();
- ScalableVectorType *Boolean64Ty =
- ScalableVectorType::get(llvm::Type::getInt1Ty(Context), 64);
-
- if (ResultType->isIntOrIntVectorTy(1)) {
- // Casting from m1 vector integer -> vector boolean
- // Ex: <vscale x 8 x i8>
- // --(bitcast)--------> <vscale x 64 x i1>
- // --(vector_extract)-> <vscale x 8 x i1>
- llvm::Value *BitCast = Builder.CreateBitCast(Ops[0], Boolean64Ty);
- return Builder.CreateExtractVector(ResultType, BitCast,
- ConstantInt::get(Int64Ty, 0));
- } else {
- // Casting from vector boolean -> m1 vector integer
- // Ex: <vscale x 1 x i1>
- // --(vector_insert)-> <vscale x 64 x i1>
- // --(bitcast)-------> <vscale x 8 x i8>
- llvm::Value *Boolean64Val =
- Builder.CreateInsertVector(Boolean64Ty,
- llvm::PoisonValue::get(Boolean64Ty),
- Ops[0],
- ConstantInt::get(Int64Ty, 0));
- return Builder.CreateBitCast(Boolean64Val, ResultType);
- }
- }
- return Builder.CreateBitCast(Ops[0], ResultType);
+ return emitRVVReinterpretBuiltin(this, E, ReturnValue, ResultType, ID,
+ Ops, PolicyAttrs, IsMasked, SegInstSEW);
}] in {
// Reinterpret between different type under the same SEW and LMUL
def vreinterpret_i_u : RVVBuiltin<"Uvv", "vUv", "csil", "v">;
@@ -2502,25 +1773,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
let Name = "vget_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- {
- auto *VecTy = cast<ScalableVectorType>(ResultType);
- if (auto *OpVecTy = dyn_cast<ScalableVectorType>(Ops[0]->getType())) {
- unsigned MaxIndex = OpVecTy->getMinNumElements() / VecTy->getMinNumElements();
- assert(isPowerOf2_32(MaxIndex));
- // Mask to only valid indices.
- Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
- Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
- Ops[1] = Builder.CreateMul(Ops[1],
- ConstantInt::get(Ops[1]->getType(),
- VecTy->getMinNumElements()));
- return Builder.CreateExtractVector(ResultType, Ops[0], Ops[1]);
- }
-
- return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_extract,
- {ResultType, Ops[0]->getType()},
- {Ops[0], Builder.CreateTrunc(Ops[1],
- Builder.getInt32Ty())});
- }
+ return emitRVVGetBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach dst_lmul = ["(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in {
def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilxfdy", dst_lmul # "v">;
@@ -2535,25 +1789,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
let Name = "vset_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
- {
- if (auto *ResVecTy = dyn_cast<ScalableVectorType>(ResultType)) {
- auto *VecTy = cast<ScalableVectorType>(Ops[2]->getType());
- unsigned MaxIndex = ResVecTy->getMinNumElements() / VecTy->getMinNumElements();
- assert(isPowerOf2_32(MaxIndex));
- // Mask to only valid indices.
- Ops[1] = Builder.CreateZExt(Ops[1], Builder.getInt64Ty());
- Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1);
- Ops[1] = Builder.CreateMul(Ops[1],
- ConstantInt::get(Ops[1]->getType(),
- VecTy->getMinNumElements()));
- return Builder.CreateInsertVector(ResultType, Ops[0], Ops[2], Ops[1]);
- }
-
- return Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert,
- {ResultType, Ops[2]->getType()},
- {Ops[0], Ops[2],
- Builder.CreateTrunc(Ops[1],Builder.getInt32Ty())});
- }
+ return emitRVVSetBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in {
def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfdy">;
@@ -2571,26 +1808,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
MaskedPolicyScheme = NonePolicy,
SupportOverloading = false,
ManualCodegen = [{
- {
- llvm::Value *ReturnVector = llvm::PoisonValue::get(ResultType);
- auto *VecTy = cast<ScalableVectorType>(Ops[0]->getType());
- for (unsigned I = 0, N = Ops.size(); I < N; ++I) {
- if (isa<ScalableVectorType>(ResultType)) {
- llvm::Value *Idx = ConstantInt::get(Builder.getInt64Ty(),
- VecTy->getMinNumElements() * I);
- ReturnVector =
- Builder.CreateInsertVector(ResultType, ReturnVector, Ops[I], Idx);
- } else {
- llvm::Value *Idx = ConstantInt::get(Builder.getInt32Ty(), I);
- ReturnVector =
- Builder.CreateIntrinsic(Intrinsic::riscv_tuple_insert,
- {ResultType, Ops[I]->getType()},
- {ReturnVector, Ops[I], Idx});
- }
-
- }
- return ReturnVector;
- }
+ return emitRVVCreateBuiltin(this, E, ReturnValue, ResultType, ID, Ops,
+ PolicyAttrs, IsMasked, SegInstSEW);
}] in {
// Since the vcreate_v uses LFixedLog2LMUL, setting the Log2LMUL to [-3] can
diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index b26e558..96f55f5 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -19,7 +19,6 @@
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
-#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Location.h"
#include "mlir/IR/Types.h"
@@ -63,11 +62,11 @@ public:
mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
const llvm::APInt &val) {
- return create<cir::ConstantOp>(loc, cir::IntAttr::get(typ, val));
+ return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val));
}
cir::ConstantOp getConstant(mlir::Location loc, mlir::TypedAttr attr) {
- return create<cir::ConstantOp>(loc, attr);
+ return cir::ConstantOp::create(*this, loc, attr);
}
cir::ConstantOp getConstantInt(mlir::Location loc, mlir::Type ty,
@@ -119,7 +118,7 @@ public:
}
cir::ConstantOp getBool(bool state, mlir::Location loc) {
- return create<cir::ConstantOp>(loc, getCIRBoolAttr(state));
+ return cir::ConstantOp::create(*this, loc, getCIRBoolAttr(state));
}
cir::ConstantOp getFalse(mlir::Location loc) { return getBool(false, loc); }
cir::ConstantOp getTrue(mlir::Location loc) { return getBool(true, loc); }
@@ -144,21 +143,37 @@ public:
mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
mlir::Value imag) {
auto resultComplexTy = cir::ComplexType::get(real.getType());
- return create<cir::ComplexCreateOp>(loc, resultComplexTy, real, imag);
+ return cir::ComplexCreateOp::create(*this, loc, resultComplexTy, real,
+ imag);
}
mlir::Value createComplexReal(mlir::Location loc, mlir::Value operand) {
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexRealOp>(loc, operandTy.getElementType(), operand);
+ return cir::ComplexRealOp::create(*this, loc, operandTy.getElementType(),
+ operand);
}
mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) {
auto operandTy = mlir::cast<cir::ComplexType>(operand.getType());
- return create<cir::ComplexImagOp>(loc, operandTy.getElementType(), operand);
+ return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(),
+ operand);
+ }
+
+ cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr,
+ uint64_t alignment = 0) {
+ mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
+ assert(!cir::MissingFeatures::opLoadStoreVolatile());
+ return cir::LoadOp::create(*this, loc, ptr, /*isDeref=*/false,
+ alignmentAttr, cir::MemOrderAttr{});
+ }
+
+ mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr,
+ uint64_t alignment) {
+ return createLoad(loc, ptr, alignment);
}
mlir::Value createNot(mlir::Value value) {
- return create<cir::UnaryOp>(value.getLoc(), value.getType(),
+ return cir::UnaryOp::create(*this, value.getLoc(), value.getType(),
cir::UnaryOpKind::Not, value);
}
@@ -167,7 +182,7 @@ public:
mlir::Location loc,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
- return create<cir::DoWhileOp>(loc, condBuilder, bodyBuilder);
+ return cir::DoWhileOp::create(*this, loc, condBuilder, bodyBuilder);
}
/// Create a while operation.
@@ -175,7 +190,7 @@ public:
mlir::Location loc,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder) {
- return create<cir::WhileOp>(loc, condBuilder, bodyBuilder);
+ return cir::WhileOp::create(*this, loc, condBuilder, bodyBuilder);
}
/// Create a for operation.
@@ -184,22 +199,23 @@ public:
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> condBuilder,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> bodyBuilder,
llvm::function_ref<void(mlir::OpBuilder &, mlir::Location)> stepBuilder) {
- return create<cir::ForOp>(loc, condBuilder, bodyBuilder, stepBuilder);
+ return cir::ForOp::create(*this, loc, condBuilder, bodyBuilder,
+ stepBuilder);
}
/// Create a break operation.
cir::BreakOp createBreak(mlir::Location loc) {
- return create<cir::BreakOp>(loc);
+ return cir::BreakOp::create(*this, loc);
}
/// Create a continue operation.
cir::ContinueOp createContinue(mlir::Location loc) {
- return create<cir::ContinueOp>(loc);
+ return cir::ContinueOp::create(*this, loc);
}
mlir::Value createUnaryOp(mlir::Location loc, cir::UnaryOpKind kind,
mlir::Value operand) {
- return create<cir::UnaryOp>(loc, kind, operand);
+ return cir::UnaryOp::create(*this, loc, kind, operand);
}
mlir::TypedAttr getConstPtrAttr(mlir::Type type, int64_t value) {
@@ -209,13 +225,21 @@ public:
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType,
mlir::Type type, llvm::StringRef name,
mlir::IntegerAttr alignment) {
- return create<cir::AllocaOp>(loc, addrType, type, name, alignment);
+ return cir::AllocaOp::create(*this, loc, addrType, type, name, alignment);
+ }
+
+ /// Get constant address of a global variable as an MLIR attribute.
+ cir::GlobalViewAttr getGlobalViewAttr(cir::PointerType type,
+ cir::GlobalOp globalOp,
+ mlir::ArrayAttr indices = {}) {
+ auto symbol = mlir::FlatSymbolRefAttr::get(globalOp.getSymNameAttr());
+ return cir::GlobalViewAttr::get(type, symbol, indices);
}
mlir::Value createGetGlobal(mlir::Location loc, cir::GlobalOp global) {
assert(!cir::MissingFeatures::addressSpace());
- return create<cir::GetGlobalOp>(loc, getPointerTo(global.getSymType()),
- global.getSymName());
+ return cir::GetGlobalOp::create(
+ *this, loc, getPointerTo(global.getSymType()), global.getSymName());
}
mlir::Value createGetGlobal(cir::GlobalOp global) {
@@ -223,36 +247,39 @@ public:
}
cir::StoreOp createStore(mlir::Location loc, mlir::Value val, mlir::Value dst,
- mlir::IntegerAttr align = {}) {
- return create<cir::StoreOp>(loc, val, dst, align);
+ bool isVolatile = false,
+ mlir::IntegerAttr align = {},
+ cir::MemOrderAttr order = {}) {
+ return cir::StoreOp::create(*this, loc, val, dst, align, order);
}
[[nodiscard]] cir::GlobalOp createGlobal(mlir::ModuleOp mlirModule,
mlir::Location loc,
mlir::StringRef name,
- mlir::Type type,
+ mlir::Type type, bool isConstant,
cir::GlobalLinkageKind linkage) {
mlir::OpBuilder::InsertionGuard guard(*this);
setInsertionPointToStart(mlirModule.getBody());
- return create<cir::GlobalOp>(loc, name, type, linkage);
+ return cir::GlobalOp::create(*this, loc, name, type, isConstant, linkage);
}
cir::GetMemberOp createGetMember(mlir::Location loc, mlir::Type resultTy,
mlir::Value base, llvm::StringRef name,
unsigned index) {
- return create<cir::GetMemberOp>(loc, resultTy, base, name, index);
+ return cir::GetMemberOp::create(*this, loc, resultTy, base, name, index);
}
mlir::Value createDummyValue(mlir::Location loc, mlir::Type type,
clang::CharUnits alignment) {
mlir::IntegerAttr alignmentAttr = getAlignmentAttr(alignment);
auto addr = createAlloca(loc, getPointerTo(type), type, {}, alignmentAttr);
- return create<cir::LoadOp>(loc, addr, /*isDeref=*/false, alignmentAttr);
+ return cir::LoadOp::create(*this, loc, addr, /*isDeref=*/false,
+ alignmentAttr, /*mem_order=*/{});
}
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base,
mlir::Value stride) {
- return create<cir::PtrStrideOp>(loc, base.getType(), base, stride);
+ return cir::PtrStrideOp::create(*this, loc, base.getType(), base, stride);
}
//===--------------------------------------------------------------------===//
@@ -262,7 +289,7 @@ public:
cir::CallOp createCallOp(mlir::Location loc, mlir::SymbolRefAttr callee,
mlir::Type returnType, mlir::ValueRange operands,
llvm::ArrayRef<mlir::NamedAttribute> attrs = {}) {
- auto op = create<cir::CallOp>(loc, callee, returnType, operands);
+ auto op = cir::CallOp::create(*this, loc, callee, returnType, operands);
op->setAttrs(attrs);
return op;
}
@@ -285,6 +312,25 @@ public:
resOperands, attrs);
}
+ cir::CallOp createTryCallOp(
+ mlir::Location loc, mlir::SymbolRefAttr callee = mlir::SymbolRefAttr(),
+ mlir::Type returnType = cir::VoidType(),
+ mlir::ValueRange operands = mlir::ValueRange(),
+ [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
+ assert(!cir::MissingFeatures::opCallCallConv());
+ assert(!cir::MissingFeatures::opCallSideEffect());
+ return createCallOp(loc, callee, returnType, operands);
+ }
+
+ cir::CallOp createTryCallOp(
+ mlir::Location loc, cir::FuncOp callee, mlir::ValueRange operands,
+ [[maybe_unused]] cir::SideEffect sideEffect = cir::SideEffect::All) {
+ assert(!cir::MissingFeatures::opCallCallConv());
+ assert(!cir::MissingFeatures::opCallSideEffect());
+ return createTryCallOp(loc, mlir::SymbolRefAttr::get(callee),
+ callee.getFunctionType().getReturnType(), operands);
+ }
+
//===--------------------------------------------------------------------===//
// Cast/Conversion Operators
//===--------------------------------------------------------------------===//
@@ -293,7 +339,7 @@ public:
mlir::Value src, mlir::Type newTy) {
if (newTy == src.getType())
return src;
- return create<cir::CastOp>(loc, newTy, kind, src);
+ return cir::CastOp::create(*this, loc, newTy, kind, src);
}
mlir::Value createCast(cir::CastKind kind, mlir::Value src,
@@ -343,7 +389,7 @@ public:
mlir::Value createBinop(mlir::Location loc, mlir::Value lhs,
cir::BinOpKind kind, mlir::Value rhs) {
- return create<cir::BinOp>(loc, lhs.getType(), kind, lhs, rhs);
+ return cir::BinOp::create(*this, loc, lhs.getType(), kind, lhs, rhs);
}
mlir::Value createLowBitsSet(mlir::Location loc, unsigned size,
@@ -365,8 +411,8 @@ public:
mlir::Value trueValue, mlir::Value falseValue) {
assert(trueValue.getType() == falseValue.getType() &&
"trueValue and falseValue should have the same type");
- return create<cir::SelectOp>(loc, trueValue.getType(), condition, trueValue,
- falseValue);
+ return cir::SelectOp::create(*this, loc, trueValue.getType(), condition,
+ trueValue, falseValue);
}
mlir::Value createLogicalAnd(mlir::Location loc, mlir::Value lhs,
@@ -381,8 +427,8 @@ public:
mlir::Value createMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
OverflowBehavior ob = OverflowBehavior::None) {
- auto op =
- create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Mul, lhs, rhs);
+ auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Mul,
+ lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@@ -400,8 +446,8 @@ public:
mlir::Value createSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
OverflowBehavior ob = OverflowBehavior::Saturated) {
- auto op =
- create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Sub, lhs, rhs);
+ auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Sub,
+ lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@@ -422,8 +468,8 @@ public:
mlir::Value createAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
OverflowBehavior ob = OverflowBehavior::None) {
- auto op =
- create<cir::BinOp>(loc, lhs.getType(), cir::BinOpKind::Add, lhs, rhs);
+ auto op = cir::BinOp::create(*this, loc, lhs.getType(), cir::BinOpKind::Add,
+ lhs, rhs);
op.setNoUnsignedWrap(
llvm::to_underlying(ob & OverflowBehavior::NoUnsignedWrap));
op.setNoSignedWrap(
@@ -444,7 +490,7 @@ public:
cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
mlir::Value lhs, mlir::Value rhs) {
- return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs);
+ return cir::CmpOp::create(*this, loc, getBoolTy(), kind, lhs, rhs);
}
mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
@@ -453,7 +499,8 @@ public:
mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs,
bool isShiftLeft) {
- return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft);
+ return cir::ShiftOp::create(*this, loc, lhs.getType(), lhs, rhs,
+ isShiftLeft);
}
mlir::Value createShift(mlir::Location loc, mlir::Value lhs,
@@ -496,8 +543,7 @@ public:
static OpBuilder::InsertPoint getBestAllocaInsertPoint(mlir::Block *block) {
auto last =
std::find_if(block->rbegin(), block->rend(), [](mlir::Operation &op) {
- // TODO: Add LabelOp missing feature here
- return mlir::isa<cir::AllocaOp>(&op);
+ return mlir::isa<cir::AllocaOp, cir::LabelOp>(&op);
});
if (last != block->rend())
@@ -532,12 +578,12 @@ public:
/// Create a loop condition.
cir::ConditionOp createCondition(mlir::Value condition) {
- return create<cir::ConditionOp>(condition.getLoc(), condition);
+ return cir::ConditionOp::create(*this, condition.getLoc(), condition);
}
/// Create a yield operation.
cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) {
- return create<cir::YieldOp>(loc, value);
+ return cir::YieldOp::create(*this, loc, value);
}
};
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 588fb0d..16b818f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -51,6 +51,45 @@ class CIR_UnitAttr<string name, string attrMnemonic, list<Trait> traits = []>
}
//===----------------------------------------------------------------------===//
+// SourceLanguageAttr
+//===----------------------------------------------------------------------===//
+
+// TODO: Add cases for other languages that Clang supports.
+
+def CIR_SourceLanguage : CIR_I32EnumAttr<"SourceLanguage", "source language", [
+ I32EnumAttrCase<"C", 1, "c">,
+ I32EnumAttrCase<"CXX", 2, "cxx">
+]> {
+ // The enum attr class is defined in `CIR_SourceLanguageAttr` below,
+ // so that it can define extra class methods.
+ let genSpecializedAttr = 0;
+}
+
+def CIR_SourceLanguageAttr : CIR_EnumAttr<CIR_SourceLanguage, "lang"> {
+
+ let summary = "Module source language";
+ let description = [{
+ Represents the source language used to generate the module.
+
+ Example:
+ ```
+ // Module compiled from C.
+ module attributes {cir.lang = cir.lang<c>} {}
+ // Module compiled from C++.
+ module attributes {cir.lang = cir.lang<cxx>} {}
+ ```
+
+ Module source language attribute name is `cir.lang` is defined by
+ `getSourceLanguageAttrName` method in CIRDialect class.
+ }];
+
+ let extraClassDeclaration = [{
+ bool isC() const { return getValue() == SourceLanguage::C; }
+ bool isCXX() const { return getValue() == SourceLanguage::CXX; }
+ }];
+}
+
+//===----------------------------------------------------------------------===//
// OptInfoAttr
//===----------------------------------------------------------------------===//
@@ -342,6 +381,44 @@ def CIR_ConstVectorAttr : CIR_Attr<"ConstVector", "const_vector", [
}
//===----------------------------------------------------------------------===//
+// ConstRecordAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_ConstRecordAttr : CIR_Attr<"ConstRecord", "const_record", [
+ TypedAttrInterface
+]> {
+ let summary = "Represents a constant record";
+ let description = [{
+ Effectively supports "struct-like" constants. It's must be built from
+ an `mlir::ArrayAttr` instance where each element is a typed attribute
+ (`mlir::TypedAttribute`).
+
+ Example:
+ ```
+ cir.global external @rgb2 = #cir.const_record<{0 : i8,
+ 5 : i64, #cir.null : !cir.ptr<i8>
+ }> : !cir.record<"", i8, i64, !cir.ptr<i8>>
+ ```
+ }];
+
+ let parameters = (ins AttributeSelfTypeParameter<"">:$type,
+ "mlir::ArrayAttr":$members);
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "cir::RecordType":$type,
+ "mlir::ArrayAttr":$members), [{
+ return $_get(type.getContext(), type, members);
+ }]>
+ ];
+
+ let assemblyFormat = [{
+ `<` custom<RecordMembers>($members) `>`
+ }];
+
+ let genVerifyDecl = 1;
+}
+
+//===----------------------------------------------------------------------===//
// ConstPtrAttr
//===----------------------------------------------------------------------===//
@@ -371,6 +448,160 @@ def CIR_ConstPtrAttr : CIR_Attr<"ConstPtr", "ptr", [TypedAttrInterface]> {
}
//===----------------------------------------------------------------------===//
+// GlobalViewAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_GlobalViewAttr : CIR_Attr<"GlobalView", "global_view", [
+ TypedAttrInterface
+]> {
+ let summary = "Provides constant access to a global address";
+ let description = [{
+ Get constant address of global `symbol` and optionally apply offsets to
+ access existing subelements. It provides a way to access globals from other
+ global and always produces a pointer.
+
+ The type of the input symbol can be different from `#cir.global_view`
+ output type, since a given view of the global might require a static
+ cast for initializing other globals.
+
+ A list of indices can be optionally passed and each element subsequently
+ indexes underlying types. For `symbol` types like `!cir.array`
+ and `!cir.record`, it leads to the constant address of sub-elements, while
+ for `!cir.ptr`, an offset is applied. The first index is relative to the
+ original symbol type, not the produced one.
+
+ The result type of this attribute may be an integer type. In such a case,
+ the pointer to the referenced global is casted to an integer and this
+ attribute represents the casted result.
+
+ Example:
+
+ ```
+ cir.global external @s = @".str2": !cir.ptr<i8>
+ cir.global external @x = #cir.global_view<@s> : !cir.ptr<i8>
+ cir.global external @s_addr = #cir.global_view<@s> : !s64i
+
+ cir.global external @rgb = #cir.const_array<[0 : i8, -23 : i8, 33 : i8]
+ : !cir.array<i8 x 3>>
+ cir.global external @elt_ptr = #cir.global_view<@rgb, [1]> : !cir.ptr<i8>
+ ```
+
+ Note, that unlike LLVM IR's gep instruction, CIR doesn't add the leading
+ zero index when it's known to be constant zero, e.g. for pointers, i.e. we
+ use indexes exactly to access sub elements or for the offset. The leading
+ zero index is added later in the lowering.
+
+ Example:
+ ```
+ struct A {
+ int a;
+ };
+
+ struct B: virtual A {
+ int b;
+ };
+ ```
+ VTT for B in CIR:
+ ```
+ cir.global linkonce_odr @_ZTT1B = #cir.const_array<[
+ #cir.global_view<@_ZTV1B, [0 : i32, 3 : i32]> : !cir.ptr<!u8i>]>
+ : !cir.array<!cir.ptr<!u8i> x 1>
+ ```
+ VTT for B in LLVM IR:
+ ```
+ @_ZTT1B = linkonce_odr global [1 x ptr] [ptr getelementptr inbounds
+ ({ [3 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)], align 8
+ ```
+ }];
+
+ let parameters = (ins AttributeSelfTypeParameter<"">:$type,
+ "mlir::FlatSymbolRefAttr":$symbol,
+ OptionalParameter<"mlir::ArrayAttr">:$indices);
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ "mlir::FlatSymbolRefAttr":$symbol,
+ CArg<"mlir::ArrayAttr", "{}">:$indices), [{
+ return $_get(type.getContext(), type, symbol, indices);
+ }]>
+ ];
+
+ // let genVerifyDecl = 1;
+ let assemblyFormat = [{
+ `<`
+ $symbol
+ (`,` $indices^)?
+ `>`
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// VTableAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_VTableAttr : CIR_Attr<"VTable", "vtable", [TypedAttrInterface]> {
+ let summary = "Represents a C++ vtable";
+ let description = [{
+ Wraps a #cir.const_record containing one or more vtable arrays.
+
+ In most cases, the anonymous record type wrapped by this attribute will
+ contain a single array corresponding to the vtable for one class. However,
+ in the case of multiple inheritence, the anonymous structure may contain
+ multiple arrays, each of which is a vtable.
+
+ Example 1 (single vtable):
+ ```mlir
+ cir.global linkonce_odr @_ZTV6Mother =
+ #cir.vtable<{
+ #cir.const_array<[
+ #cir.ptr<null> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI6Mother> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 4>
+ }> : !rec_anon_struct1
+ ```
+
+ Example 2 (multiple vtables):
+ ```mlir
+ cir.global linkonce_odr @_ZTV5Child =
+ #cir.vtable<{
+ #cir.const_array<[
+ #cir.ptr<null> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 4>,
+ #cir.const_array<[
+ #cir.ptr<-8 : i64> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZTI5Child> : !cir.ptr<!u8i>,
+ #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr<!u8i>
+ ]> : !cir.array<!cir.ptr<!u8i> x 3>
+ }> : !rec_anon_struct2
+ ```
+ }];
+
+ // `data` is a const record with one element, containing an array of
+ // vtable information.
+ let parameters = (ins
+ AttributeSelfTypeParameter<"">:$type,
+ "mlir::ArrayAttr":$data
+ );
+
+ let builders = [
+ AttrBuilderWithInferredContext<(ins "mlir::Type":$type,
+ "mlir::ArrayAttr":$data), [{
+ return $_get(type.getContext(), type, data);
+ }]>
+ ];
+
+ let genVerifyDecl = 1;
+ let assemblyFormat = [{
+ `<` custom<RecordMembers>($data) `>`
+ }];
+}
+
+//===----------------------------------------------------------------------===//
// ConstComplexAttr
//===----------------------------------------------------------------------===//
@@ -516,4 +747,36 @@ def CIR_BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> {
];
}
+//===----------------------------------------------------------------------===//
+// AddressPointAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_AddressPointAttr : CIR_Attr<"AddressPoint", "address_point"> {
+ let summary = "Address point attribute";
+
+ let description = [{
+ Attribute specifying the address point within a C++ virtual table (vtable).
+
+ The `index` (vtable index) parameter identifies which vtable to use within a
+ vtable group, while the `offset` (address point index) specifies the offset
+ within that vtable where the address begins.
+
+ Example:
+ ```mlir
+ cir.global linkonce_odr @_ZTV1B = ...
+ ...
+ %3 = cir.vtable.address_point(@_ZTV1B,
+ address_point = <index = 0, offset = 2>)
+ : !cir.vptr
+ ```
+ }];
+
+ let parameters = (ins "int32_t":$index,
+ "int32_t":$offset);
+
+ let assemblyFormat = [{
+ `<` struct($index, $offset) `>`
+ }];
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIRATTRS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
index 8ef565d..ecc681e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
@@ -34,6 +34,41 @@ public:
void reset(mlir::DataLayoutSpecInterface spec);
bool isBigEndian() const { return bigEndian; }
+
+ /// Internal helper method that returns requested alignment for type.
+ llvm::Align getAlignment(mlir::Type ty, bool abiOrPref) const;
+
+ llvm::Align getABITypeAlign(mlir::Type ty) const {
+ return getAlignment(ty, true);
+ }
+
+ /// Returns the maximum number of bytes that may be overwritten by
+ /// storing the specified type.
+ ///
+ /// If Ty is a scalable vector type, the scalable property will be set and
+ /// the runtime size will be a positive integer multiple of the base size.
+ ///
+ /// For example, returns 5 for i36 and 10 for x86_fp80.
+ llvm::TypeSize getTypeStoreSize(mlir::Type ty) const {
+ llvm::TypeSize baseSize = getTypeSizeInBits(ty);
+ return {llvm::divideCeil(baseSize.getKnownMinValue(), 8),
+ baseSize.isScalable()};
+ }
+
+ /// Returns the offset in bytes between successive objects of the
+ /// specified type, including alignment padding.
+ ///
+ /// If Ty is a scalable vector type, the scalable property will be set and
+ /// the runtime size will be a positive integer multiple of the base size.
+ ///
+ /// This is the amount that alloca reserves for this type. For example,
+ /// returns 12 or 16 for x86_fp80, depending on alignment.
+ llvm::TypeSize getTypeAllocSize(mlir::Type ty) const {
+ // Round up to the next alignment boundary.
+ return llvm::alignTo(getTypeStoreSize(ty), getABITypeAlign(ty).value());
+ }
+
+ llvm::TypeSize getTypeSizeInBits(mlir::Type ty) const;
};
} // namespace cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 3fdbf65..15d5fa0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -35,11 +35,13 @@ def CIR_Dialect : Dialect {
let hasConstantMaterializer = 1;
let extraClassDeclaration = [{
+ static llvm::StringRef getSourceLanguageAttrName() { return "cir.lang"; }
static llvm::StringRef getTripleAttrName() { return "cir.triple"; }
static llvm::StringRef getOptInfoAttrName() { return "cir.opt_info"; }
static llvm::StringRef getCalleeAttrName() { return "callee"; }
static llvm::StringRef getNoThrowAttrName() { return "nothrow"; }
static llvm::StringRef getSideEffectAttrName() { return "side_effect"; }
+ static llvm::StringRef getModuleLevelAsmAttrName() { return "cir.module_asm"; }
void registerAttributes();
void registerTypes();
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 72841a1..982533f 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -300,6 +300,20 @@ def CIR_ConstantOp : CIR_Op<"const", [
}
//===----------------------------------------------------------------------===//
+// C/C++ memory order definitions
+//===----------------------------------------------------------------------===//
+
+def CIR_MemOrder : CIR_I32EnumAttr<
+ "MemOrder", "Memory order according to C++11 memory model", [
+ I32EnumAttrCase<"Relaxed", 0, "relaxed">,
+ I32EnumAttrCase<"Consume", 1, "consume">,
+ I32EnumAttrCase<"Acquire", 2, "acquire">,
+ I32EnumAttrCase<"Release", 3, "release">,
+ I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">,
+ I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">
+]>;
+
+//===----------------------------------------------------------------------===//
// AllocaOp
//===----------------------------------------------------------------------===//
@@ -408,13 +422,14 @@ def CIR_LoadOp : CIR_Op<"load", [
let arguments = (ins Arg<CIR_PointerType, "the address to load from",
[MemRead]>:$addr,
UnitAttr:$isDeref,
- OptionalAttr<I64Attr>:$alignment
- );
+ OptionalAttr<I64Attr>:$alignment,
+ OptionalAttr<CIR_MemOrder>:$mem_order);
let results = (outs CIR_AnyType:$result);
let assemblyFormat = [{
(`deref` $isDeref^)?
(`align` `(` $alignment^ `)`)?
+ (`atomic` `(` $mem_order^ `)`)?
$addr `:` qualified(type($addr)) `,` type($result) attr-dict
}];
@@ -451,10 +466,12 @@ def CIR_StoreOp : CIR_Op<"store", [
let arguments = (ins CIR_AnyType:$value,
Arg<CIR_PointerType, "the address to store the value",
[MemWrite]>:$addr,
- OptionalAttr<I64Attr>:$alignment);
+ OptionalAttr<I64Attr>:$alignment,
+ OptionalAttr<CIR_MemOrder>:$mem_order);
let assemblyFormat = [{
(`align` `(` $alignment^ `)`)?
+ (`atomic` `(` $mem_order^ `)`)?
$value `,` $addr attr-dict `:` type($value) `,` qualified(type($addr))
}];
@@ -1061,6 +1078,77 @@ def CIR_BrOp : CIR_Op<"br",[
}
//===----------------------------------------------------------------------===//
+// GotoOp
+//===----------------------------------------------------------------------===//
+
+def CIR_GotoOp : CIR_Op<"goto", [Terminator]> {
+ let description = [{
+
+ Transfers control to the specified `label`. This requires a corresponding
+ `cir.label` to exist and is used by to represent source level `goto`s
+ that jump across region boundaries. Alternatively, `cir.br` is used to
+ construct goto's that don't violate such boundaries.
+
+ `cir.goto` is completely symbolic (i.e. it "jumps" on a label that isn't
+ yet materialized) and should be taken into account by passes and analysis
+ when deciding if it's safe to make some assumptions about a given region
+ or basic block.
+
+ Example:
+ ```C++
+ int test(int x) {
+ if (x)
+ goto label;
+ {
+ x = 10;
+ label:
+ return x;
+ }
+ }
+ ```
+
+ ```mlir
+ cir.scope { // REGION #1
+ %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %3 = cir.cast(int_to_bool, %2 : !s32i), !cir.bool
+ cir.if %3 {
+ cir.goto "label"
+ }
+ }
+ cir.scope { // REGION #2
+ %2 = cir.const #cir.int<10> : !s32i
+ cir.store %2, %0 : !s32i, !cir.ptr<!s32i>
+ cir.br ^bb1
+ ^bb1: // pred: ^bb0
+ cir.label "label"
+ %3 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ cir.store %3, %1 : !s32i, !cir.ptr<!s32i>
+ %4 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+ cir.return %4 : !s32i
+ }
+ cir.unreachable
+ ```
+ }];
+ let arguments = (ins StrAttr:$label);
+ let assemblyFormat = [{ $label attr-dict }];
+}
+
+//===----------------------------------------------------------------------===//
+// LabelOp
+//===----------------------------------------------------------------------===//
+
+// The LabelOp has AlwaysSpeculatable trait in order to not to be swept
+// by canonicalizer
+def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> {
+ let description = [{
+ An identifier which may be referred by cir.goto operation
+ }];
+ let arguments = (ins StrAttr:$label);
+ let assemblyFormat = [{ $label attr-dict }];
+ let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
// UnaryOp
//===----------------------------------------------------------------------===//
@@ -1631,12 +1719,14 @@ def CIR_GlobalOp : CIR_Op<"global", [
CIR_GlobalLinkageKind:$linkage,
OptionalAttr<AnyAttr>:$initial_value,
UnitAttr:$comdat,
+ UnitAttr:$constant,
UnitAttr:$dso_local,
OptionalAttr<I64Attr>:$alignment);
let assemblyFormat = [{
($sym_visibility^)?
(`` $global_visibility^)?
+ (`constant` $constant^)?
$linkage
(`comdat` $comdat^)?
(`dso_local` $dso_local^)?
@@ -1655,6 +1745,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
let builders = [OpBuilder<(ins
"llvm::StringRef":$sym_name,
"mlir::Type":$sym_type,
+ CArg<"bool", "false">:$isConstant,
// CIR defaults to external linkage.
CArg<"cir::GlobalLinkageKind",
"cir::GlobalLinkageKind::ExternalLinkage">:$linkage)>];
@@ -1692,6 +1783,194 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [
}
//===----------------------------------------------------------------------===//
+// VTableAddrPointOp
+//===----------------------------------------------------------------------===//
+
+def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [
+ Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>
+]> {
+ let summary = "Get the vtable (global variable) address point";
+ let description = [{
+ The `vtable.address_point` operation retrieves the "effective" address
+ (address point) of a C++ virtual table. An object internal `__vptr`
+ gets initializated on top of the value returned by this operation.
+
+ `address_point.index` (vtable index) provides the appropriate vtable within
+ the vtable group (as specified by Itanium ABI), and `address_point.offset`
+ (address point index) the actual address point within that vtable.
+
+ The return type is always `!cir.vptr`.
+
+ Example:
+ ```mlir
+ cir.global linkonce_odr @_ZTV1B = ...
+ ...
+ %3 = cir.vtable.address_point(@_ZTV1B,
+ address_point = <index = 0, offset = 2>) : !cir.vptr
+ ```
+ }];
+
+ let arguments = (ins
+ FlatSymbolRefAttr:$name,
+ CIR_AddressPointAttr:$address_point
+ );
+
+ let results = (outs Res<CIR_VPtrType, "", []>:$addr);
+
+ let assemblyFormat = [{
+ `(`
+ $name `,` `address_point` `=` $address_point
+ `)`
+ `:` qualified(type($addr)) attr-dict
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// VTableGetVPtr
+//===----------------------------------------------------------------------===//
+
+def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> {
+ let summary = "Get a the address of the vtable pointer for an object";
+ let description = [{
+ The `vtable.get_vptr` operation retrieves the address of the vptr for a
+ C++ object. This operation requires that the object pointer points to
+ the start of a complete object. (TODO: Describe how we get that).
+ The vptr will always be at offset zero in the object, but this operation
+ is more explicit about what is being retrieved than a direct bitcast.
+
+ The return type is always `!cir.ptr<!cir.vptr>`.
+
+ Example:
+ ```mlir
+ %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+ %3 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+ ```
+ }];
+
+ let arguments = (ins
+ Arg<CIR_PointerType, "the vptr address", [MemRead]>:$src
+ );
+
+ let results = (outs CIR_PtrToVPtr:$result);
+
+ let assemblyFormat = [{
+ $src `:` qualified(type($src)) `->` qualified(type($result)) attr-dict
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// VTableGetVirtualFnAddrOp
+//===----------------------------------------------------------------------===//
+
+def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [
+ Pure
+]> {
+ let summary = "Get a the address of a virtual function pointer";
+ let description = [{
+ The `vtable.get_virtual_fn_addr` operation retrieves the address of a
+ virtual function pointer from an object's vtable (__vptr).
+ This is an abstraction to perform the basic pointer arithmetic to get
+ the address of the virtual function pointer, which can then be loaded and
+ called.
+
+ The `vptr` operand must be a `!cir.ptr<!cir.vptr>` value, which would
+ have been returned by a previous call to `cir.vatble.get_vptr`. The
+ `index` operand is an index of the virtual function in the vtable.
+
+ The return type is a pointer-to-pointer to the function type.
+
+ Example:
+ ```mlir
+ %2 = cir.load %0 : !cir.ptr<!cir.ptr<!rec_C>>, !cir.ptr<!rec_C>
+ %3 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_C> -> !cir.ptr<!cir.vptr>
+ %4 = cir.load %3 : !cir.ptr<!cir.vptr>, !cir.vptr
+ %5 = cir.vtable.get_virtual_fn_addr %4[2] : !cir.vptr
+ -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>>
+ %6 = cir.load align(8) %5 : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!rec_C>)
+ -> !s32i>>>,
+ !cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>
+ %7 = cir.call %6(%2) : (!cir.ptr<!cir.func<(!cir.ptr<!rec_C>) -> !s32i>>,
+ !cir.ptr<!rec_C>) -> !s32i
+ ```
+ }];
+
+ let arguments = (ins
+ Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr,
+ I64Attr:$index);
+
+ let results = (outs CIR_PointerType:$result);
+
+ let assemblyFormat = [{
+ $vptr `[` $index `]` attr-dict
+ `:` qualified(type($vptr)) `->` qualified(type($result))
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// VTTAddrPointOp
+//===----------------------------------------------------------------------===//
+
+def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [
+ Pure, DeclareOpInterfaceMethods<SymbolUserOpInterface>
+]> {
+ let summary = "Get the VTT address point";
+ let description = [{
+ The `vtt.address_point` operation retrieves an element from the virtual
+ table table (VTT), which is the address point of a C++ vtable. In virtual
+ inheritance, a set of internal `__vptr` members for an object are
+ initialized by this operation, which assigns an element from the VTT. The
+ initialization order is as follows:
+
+ The complete object constructors and destructors find the VTT,
+ via the mangled name of the VTT global variable. They pass the address of
+ the subobject's sub-VTT entry in the VTT as a second parameter
+ when calling the base object constructors and destructors.
+ The base object constructors and destructors use the address passed to
+ initialize the primary virtual pointer and virtual pointers that point to
+ the classes which either have virtual bases or override virtual functions
+ with a virtual step.
+
+ The first parameter is either the mangled name of VTT global variable
+ or the address of the subobject's sub-VTT entry in the VTT.
+ The second parameter `offset` provides a virtual step to adjust to
+ the actual address point of the vtable.
+
+ The return type is always a `!cir.ptr<!cir.ptr<void>>`.
+
+ Example:
+ ```mlir
+ cir.global linkonce_odr @_ZTV1B = ...
+ ...
+ %3 = cir.base_class_addr(%1 : !cir.ptr<!rec_D> nonnull) [0]
+ -> !cir.ptr<!rec_B>
+ %4 = cir.vtt.address_point @_ZTT1D, offset = 1
+ -> !cir.ptr<!cir.ptr<!void>>
+ cir.call @_ZN1BC2Ev(%3, %4)
+ ```
+ Or:
+ ```mlir
+ %7 = cir.vtt.address_point %3 : !cir.ptr<!cir.ptr<!void>>, offset = 1
+ -> !cir.ptr<!cir.ptr<!void>>
+ ```
+ }];
+
+ let arguments = (ins OptionalAttr<FlatSymbolRefAttr>:$name,
+ Optional<CIR_AnyType>:$sym_addr,
+ I32Attr:$offset);
+ let results = (outs CIR_PointerType:$addr);
+
+ let assemblyFormat = [{
+ ($name^)?
+ ($sym_addr^ `:` type($sym_addr))?
+ `,`
+ `offset` `=` $offset
+ `->` qualified(type($addr)) attr-dict
+ }];
+
+ let hasVerifier = 1;
+}
+
+//===----------------------------------------------------------------------===//
// SetBitfieldOp
//===----------------------------------------------------------------------===//
@@ -2153,6 +2432,68 @@ def CIR_CallOp : CIR_CallOpBase<"call", [NoRegionArguments]> {
}
//===----------------------------------------------------------------------===//
+// ReturnAddrOp and FrameAddrOp
+//===----------------------------------------------------------------------===//
+
+class CIR_FuncAddrBuiltinOp<string mnemonic> : CIR_Op<mnemonic, []> {
+ let arguments = (ins CIR_UInt32:$level);
+ let results = (outs CIR_VoidPtrType:$result);
+ let assemblyFormat = [{
+ `(` $level `)` attr-dict
+ }];
+}
+
+def CIR_ReturnAddrOp : CIR_FuncAddrBuiltinOp<"return_address"> {
+ let summary =
+ "The return address of the current function, or of one of its callers";
+
+ let description = [{
+ Represents a call to builtin function ` __builtin_return_address` in CIR.
+ This builtin function returns the return address of the current function,
+ or of one of its callers.
+
+ The `level` argument is number of frames to scan up the call stack.
+ For instance, value of 0 yields the return address of the current function,
+ value of 1 yields the return address of the caller of the current function,
+ and so forth.
+
+ Examples:
+
+ ```mlir
+ %p = return_address(%level) -> !cir.ptr<!void>
+ ```
+ }];
+}
+
+def CIR_FrameAddrOp : CIR_FuncAddrBuiltinOp<"frame_address"> {
+ let summary =
+ "The frame address of the current function, or of one of its callers";
+
+ let description = [{
+ Represents a call to builtin function ` __builtin_frame_address` in CIR.
+ This builtin function returns the frame address of the current function,
+ or of one of its callers. The frame is the area on the stack that holds
+ local variables and saved registers. The frame address is normally the
+ address of the first word pushed on to the stack by the function.
+ However, the exact definition depends upon the processor and the calling
+ convention. If the processor has a dedicated frame pointer register, and
+ the function has a frame, then __builtin_frame_address returns the value of
+ the frame pointer register.
+
+ The `level` argument is number of frames to scan up the call stack.
+ For instance, value of 0 yields the frame address of the current function,
+ value of 1 yields the frame address of the caller of the current function,
+ and so forth.
+
+ Examples:
+
+ ```mlir
+ %p = frame_address(%level) -> !cir.ptr<!void>
+ ```
+ }];
+}
+
+//===----------------------------------------------------------------------===//
// StackSaveOp & StackRestoreOp
//===----------------------------------------------------------------------===//
@@ -2197,6 +2538,87 @@ def CIR_StackRestoreOp : CIR_Op<"stackrestore"> {
}
//===----------------------------------------------------------------------===//
+// InlineAsmOp
+//===----------------------------------------------------------------------===//
+
+def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel",
+ [I32EnumAttrCase<"x86_att", 0>,
+ I32EnumAttrCase<"x86_intel", 1>]>;
+
+def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> {
+ let description = [{
+ The `cir.asm` operation represents C/C++ asm inline.
+
+ CIR constraints strings follow the same rules that are established for
+ the C level assembler constraints with several differences caused by
+ clang::AsmStmt processing.
+
+ Thus, numbers that appears in the constraint string may also refer to:
+ - the output variable index referenced by the input operands.
+ - the index of early-clobber operand
+
+ Operand attributes are a storage, where each element corresponds to the
+ operand with the same index. The first index relates to the operation
+ result (if any).
+ The operands themselves are stored as VariadicOfVariadic in the following
+ order: output, input and then in/out operands. When several output operands
+ are present, the result type may be represented as an anonymous record type.
+
+ Example:
+ ```C++
+ __asm__("foo" : : : );
+ __asm__("bar $42 %[val]" : [val] "=r" (x), "+&r"(x));
+ __asm__("baz $42 %[val]" : [val] "=r" (x), "+&r"(x) : "[val]"(y));
+ ```
+
+ ```mlir
+ !rec_22anon2E022 = !cir.record<struct "anon.0" {!cir.int<s, 32>, !cir.int<s, 32>}>
+ !rec_22anon2E122 = !cir.record<struct "anon.1" {!cir.int<s, 32>, !cir.int<s, 32>}>
+ ...
+ %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
+ %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init]
+ ...
+ %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ %3 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+
+ cir.asm(x86_att,
+ out = [],
+ in = [],
+ in_out = [],
+ {"foo" "~{dirflag},~{fpsr},~{flags}"}) side_effects
+
+ cir.asm(x86_att,
+ out = [],
+ in = [],
+ in_out = [%2 : !s32i],
+ {"bar $$42 $0" "=r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E022
+
+ cir.asm(x86_att,
+ out = [],
+ in = [%3 : !s32i],
+ in_out = [%2 : !s32i],
+ {"baz $$42 $0" "=r,=&r,0,1,~{dirflag},~{fpsr},~{flags}"}) -> !rec_22anon2E122
+ ```
+ }];
+
+ let results = (outs Optional<CIR_AnyType>:$res);
+
+ let arguments =
+ (ins VariadicOfVariadic<AnyType, "operands_segments">:$asm_operands,
+ StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects,
+ CIR_AsmFlavor:$asm_flavor, ArrayAttr:$operand_attrs,
+ DenseI32ArrayAttr:$operands_segments);
+
+ let builders = [OpBuilder<(ins
+ "llvm::ArrayRef<mlir::ValueRange>":$asmOperands,
+ "llvm::StringRef":$asmString, "llvm::StringRef":$constraints,
+ "bool":$sideEffects, "AsmFlavor":$asmFlavor,
+ "llvm::ArrayRef<mlir::Attribute>":$operandAttrs)>];
+
+ let hasCustomAssemblyFormat = 1;
+}
+
+//===----------------------------------------------------------------------===//
// UnreachableOp
//===----------------------------------------------------------------------===//
@@ -2827,7 +3249,7 @@ def CIR_ComplexSubOp : CIR_Op<"complex.sub", [
}
//===----------------------------------------------------------------------===//
-// ComplexMulOp
+// ComplexMulOp & ComplexDivOp
//===----------------------------------------------------------------------===//
def CIR_ComplexRangeKind : CIR_I32EnumAttr<
@@ -2846,12 +3268,13 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
The `cir.complex.mul` operation takes two complex numbers and returns
their product.
- Range is used to select the implementation used when the operation
- is lowered to the LLVM dialect. For multiplication, 'improved',
- 'promoted', and 'basic' are all handled equivalently, producing the
- algebraic formula with no special handling for NaN value. If 'full' is
- used, a runtime-library function is called if one of the intermediate
- calculations produced a NaN value.
+ For complex types with floating-point components, the `range` attribute
+ specifies the algorithm to be used when the operation is lowered to
+ the LLVM dialect. For multiplication, 'improved', 'promoted', and 'basic'
+ are all handled equivalently, producing the algebraic formula with no
+ special handling for NaN value. If 'full' is used, a runtime-library
+ function is called if one of the intermediate calculations produced
+ a NaN value.
Example:
@@ -2874,6 +3297,48 @@ def CIR_ComplexMulOp : CIR_Op<"complex.mul", [
}];
}
+def CIR_ComplexDivOp : CIR_Op<"complex.div", [
+ Pure, SameOperandsAndResultType
+]> {
+ let summary = "Complex division";
+ let description = [{
+ The `cir.complex.div` operation takes two complex numbers and returns
+ their quotient.
+
+ For complex types with floating-point components, the `range` attribute
+ specifies the algorithm to be used when the operation is lowered to
+ the LLVM dialect. For division, 'improved' produces Smith's algorithms for
+ Complex division with no additional handling for NaN values. If 'promoted'
+ is used, the values are promoted to a higher precision type, if possible,
+ and the calculation is performed using the algebraic formula, with
+ no additional handling for NaN values. We fall back on Smith's algorithm
+ when the target doesn't support a higher precision type. If 'full' is used,
+ a runtime-library function is called if one of the intermediate
+ calculations produced a NaN value. and for 'basic' algebraic formula with
+ no additional handling for the NaN value will be used. For integers types
+ `range` attribute will be ignored.
+
+ Example:
+
+ ```mlir
+ %2 = cir.complex.div %0, %1 range(basic) : !cir.complex<!cir.float>
+ %2 = cir.complex.div %0, %1 range(full) : !cir.complex<!cir.float>
+ ```
+ }];
+
+ let arguments = (ins
+ CIR_ComplexType:$lhs,
+ CIR_ComplexType:$rhs,
+ CIR_ComplexRangeKind:$range
+ );
+
+ let results = (outs CIR_ComplexType:$result);
+
+ let assemblyFormat = [{
+ $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict
+ }];
+}
+
//===----------------------------------------------------------------------===//
// Bit Manipulation Operations
//===----------------------------------------------------------------------===//
@@ -3143,6 +3608,56 @@ def CIR_AssumeOp : CIR_Op<"assume"> {
}];
}
+def CIR_AssumeAlignedOp : CIR_Op<"assume_aligned", [
+ Pure, AllTypesMatch<["pointer", "result"]>
+]> {
+ let summary = "Tell the optimizer that a pointer is aligned";
+ let description = [{
+ The `cir.assume_aligned` operation takes two or three arguments. The first
+ argument `pointer` gives the pointer value whose alignment is to be assumed,
+ and the second argument `align` is an integer attribute that gives the
+ assumed alignment.
+
+ The `offset` argument is optional. If given, it represents misalignment
+ offset. When it's present, this operation tells the optimizer that the
+ pointer is always misaligned to the alignment by `offset` bytes, a.k.a. the
+ pointer yielded by `(char *)pointer - offset` is aligned to the specified
+ alignment. Note that the `offset` argument is an SSA value rather than an
+ attribute, which means that you could pass a dynamically determined value
+ as the mialignment offset.
+
+ The result of this operation has the same value as the `pointer` argument,
+ but it additionally carries any alignment information indicated by this
+ operation.
+
+ This operation corresponds to the `__builtin_assume_aligned` builtin
+ function.
+
+ Example:
+
+ ```mlir
+ // Assume that %0 is a CIR pointer value of type !cir.ptr<!s32i>
+ %1 = cir.assume_aligned %0 alignment 16 : !cir.ptr<!s32i>
+
+ // With a misalignment offset of 4 bytes:
+ %2 = cir.const #cir.int<4> : !u64i
+ %3 = cir.assume_aligned %0 alignment 16 [offset %2 : !u64i] : !cir.ptr<!s32i>
+ ```
+ }];
+
+ let arguments = (ins CIR_PointerType:$pointer,
+ I64Attr:$alignment,
+ Optional<CIR_IntType>:$offset);
+ let results = (outs CIR_PointerType:$result);
+
+ let assemblyFormat = [{
+ $pointer
+ `alignment` $alignment
+ (`[` `offset` $offset^ `:` type($offset) `]`)?
+ `:` qualified(type($pointer)) attr-dict
+ }];
+}
+
def CIR_AssumeSepStorageOp : CIR_Op<"assume_separate_storage", [
SameTypeOperands
]> {
@@ -3202,4 +3717,210 @@ def CIR_ExpectOp : CIR_Op<"expect", [
}];
}
+//===----------------------------------------------------------------------===//
+// Floating Point Ops
+//===----------------------------------------------------------------------===//
+
+class CIR_UnaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
+ : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
+{
+ let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src);
+ let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
+
+ let assemblyFormat = "$src `:` type($src) attr-dict";
+
+ let llvmOp = llvmOpName;
+}
+
+def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
+ let summary = "Computes the floating-point absolute value";
+ let description = [{
+ `cir.fabs` computes the absolute value of a floating-point operand
+ and returns a result of the same type, ignoring floating-point
+ exceptions. It does not set `errno`.
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// Variadic Operations
+//===----------------------------------------------------------------------===//
+
+def CIR_VAStartOp : CIR_Op<"va_start"> {
+ let summary = "Starts a variable argument list";
+ let description = [{
+ The cir.va_start operation models the C/C++ va_start macro by
+ initializing a variable argument list at the given va_list storage
+ location.
+
+ The first operand must be a pointer to the target's `va_list`
+ representation. This operation has no results and produces its effect by
+ mutating the storage referenced by the pointer operand. The second operand
+ must be an integer value that contains the expected number of arguments in
+ that list.
+
+ Each `cir.va_start` must be paired with a corresponding `cir.va_end`
+ on the same logical `va_list` object along all control-flow paths. After
+ `cir.va_end`, the `va_list` must not be accessed unless reinitialized
+ with another `cir.va_start`.
+
+ Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the
+ appropriately decayed pointer to the underlying `va_list` storage.
+
+ Example:
+
+ ```mlir
+ // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+ %p = cir.cast(array_to_ptrdecay, %args
+ : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
+ !cir.ptr<!rec___va_list_tag>
+ %count = cir.load %0 : !cir.ptr<!s32i>, !s32i
+ cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i
+ ```
+ }];
+ let arguments = (ins
+ CIR_PointerType:$arg_list,
+ CIR_AnyFundamentalIntType:$count
+ );
+
+ let assemblyFormat = [{
+ $arg_list $count attr-dict `:` type(operands)
+ }];
+}
+
+def CIR_VAEndOp : CIR_Op<"va_end"> {
+ let summary = "Ends a variable argument list";
+ let description = [{
+ The `cir.va_end` operation models the C/C++ va_end macro by finalizing
+ and cleaning up a variable argument list previously initialized with
+ `cir.va_start`.
+
+ The operand must be a pointer to the target's `va_list` representation.
+ This operation has no results and produces its effect by mutating the
+ storage referenced by the pointer operand.
+
+ `cir.va_end` must only be called after a matching `cir.va_start` on the
+ same `va_list` along all control-flow paths. After `cir.va_end`, the
+ `va_list` is invalid and must not be accessed unless reinitialized.
+
+ Lowering typically maps this to the LLVM intrinsic `llvm.va_end`,
+ passing the appropriately decayed pointer to the underlying `va_list`
+ storage.
+
+ Example:
+ ```mlir
+ // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+ %p = cir.cast(array_to_ptrdecay, %args
+ : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
+ !cir.ptr<!rec___va_list_tag>
+ cir.va_end %p : !cir.ptr<!rec___va_list_tag>
+ ```
+ }];
+
+ let arguments = (ins CIR_PointerType:$arg_list);
+
+ let assemblyFormat = [{
+ $arg_list attr-dict `:` type(operands)
+ }];
+}
+
+def CIR_VAArgOp : CIR_Op<"va_arg"> {
+ let summary = "Fetches next variadic element as a given type";
+ let description = [{
+ The `cir.va_arg` operation models the C/C++ `va_arg` macro by reading the
+ next argument from an active variable argument list and producing it as a
+ value of a specified result type.
+
+ The operand must be a pointer to the target's `va_list` representation.
+ The operation advances the `va_list` state as a side effect and returns
+ the fetched value as the result, whose type is chosen by the user of the
+ operation.
+
+ A `cir.va_arg` must only be used on a `va_list` that has been initialized
+ with `cir.va.start` and not yet finalized by `cir.va.end`. The semantics
+ (including alignment and promotion rules) follow the platform ABI; the
+ frontend is responsible for providing a `va_list` pointer that matches the
+ target representation.
+
+ Example:
+ ```mlir
+ // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+ %p = cir.cast(array_to_ptrdecay, %args
+ : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
+ !cir.ptr<!rec___va_list_tag>
+ cir.va.start %p : !cir.ptr<!rec___va_list_tag>
+
+ // Fetch an `int` from the vararg list.
+ %v = cir.va_arg %p : (!cir.ptr<!rec___va_list_tag>) -> !s32i
+
+ cir.va.end %p : !cir.ptr<!rec___va_list_tag>
+ ```
+ }];
+
+ let arguments = (ins CIR_PointerType:$arg_list);
+ let results = (outs CIR_AnyType:$result);
+
+ let assemblyFormat = [{
+ $arg_list attr-dict `:` functional-type(operands, $result)
+ }];
+}
+
+//===----------------------------------------------------------------------===//
+// ThrowOp
+//===----------------------------------------------------------------------===//
+
+def CIR_ThrowOp : CIR_Op<"throw"> {
+ let summary = "(Re)Throws an exception";
+ let description = [{
+ This operation is equivalent to either __cxa_throw or __cxa_rethrow,
+ depending on the arguments.
+
+ The absense of arguments for `cir.throw` means it rethrows.
+
+ For the no-rethrow version, it must have at least two operands, the RTTI
+ information, a pointer to the exception object (likely allocated via
+ `cir.alloc_exception`) and finally an optional dtor, which might run as
+ part of this operation.
+
+ Example:
+
+ ```mlir
+ // re-throw;
+ cir.throw
+
+ // if (b == 0)
+ // throw "Division by zero condition!";
+
+ // Type info for char const*
+ cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i>
+ cir.if %cond {
+ %exception_addr = cir.alloc_exception 8 -> !cir.ptr<!void>
+ ...
+ // Store string addr for "Division by zero condition!"
+ cir.store %string_addr, %exception_addr : !cir.ptr<!s8i>,
+ !cir.ptr<!cir.ptr<!s8i>>
+ cir.throw %exception_addr : !cir.ptr<!cir.ptr<!u8i>>,
+ @_ZTIPKc
+ ```
+ }];
+
+ let arguments = (ins
+ Optional<CIR_PointerType>:$exception_ptr,
+ OptionalAttr<FlatSymbolRefAttr>:$type_info,
+ OptionalAttr<FlatSymbolRefAttr>:$dtor
+ );
+
+ let assemblyFormat = [{
+ ($exception_ptr^ `:` type($exception_ptr))?
+ (`,` $type_info^)?
+ (`,` $dtor^)?
+ attr-dict
+ }];
+
+ let extraClassDeclaration = [{
+ bool rethrows() { return getNumOperands() == 0; }
+ }];
+
+ let hasVerifier = 1;
+}
+
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
index fead572..17fddae 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
+++ b/clang/include/clang/CIR/Dialect/IR/CIROpsEnums.h
@@ -113,6 +113,18 @@ LLVM_ATTRIBUTE_UNUSED static bool isValidLinkage(GlobalLinkageKind gl) {
isLinkOnceLinkage(gl);
}
+bool operator<(cir::MemOrder, cir::MemOrder) = delete;
+bool operator>(cir::MemOrder, cir::MemOrder) = delete;
+bool operator<=(cir::MemOrder, cir::MemOrder) = delete;
+bool operator>=(cir::MemOrder, cir::MemOrder) = delete;
+
+// Validate an integral value which isn't known to fit within the enum's range
+// is a valid AtomicOrderingCABI.
+template <typename Int> inline bool isValidCIRAtomicOrderingCABI(Int value) {
+ return static_cast<Int>(cir::MemOrder::Relaxed) <= value &&
+ value <= static_cast<Int>(cir::MemOrder::SequentiallyConsistent);
+}
+
} // namespace cir
#endif // CLANG_CIR_DIALECT_IR_CIROPSENUMS_H
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
index d7d55df..82f6e1d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
@@ -290,6 +290,14 @@ def CIR_AnyFloatOrVecOfFloatType
}
//===----------------------------------------------------------------------===//
+// VPtr type predicates
+//===----------------------------------------------------------------------===//
+
+def CIR_AnyVPtrType : CIR_TypeBase<"::cir::VPtrType", "vptr type">;
+
+def CIR_PtrToVPtr : CIR_PtrToType<CIR_AnyVPtrType>;
+
+//===----------------------------------------------------------------------===//
// Scalar Type predicates
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index a258df7..312d0a9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -296,10 +296,10 @@ def CIR_VPtrType : CIR_Type<"VPtr", "vptr", [
access to the vptr.
This type will be the element type of the 'vptr' member of structures that
- require a vtable pointer. A pointer to this type is returned by the
- `cir.vtable.address_point` and `cir.vtable.get_vptr` operations, and this
- pointer may be passed to the `cir.vtable.get_virtual_fn_addr` operation to
- get the address of a virtual function pointer.
+ require a vtable pointer. The `cir.vtable.address_point` operation returns
+ this type. The `cir.vtable.get_vptr` operations returns a pointer to this
+ type. This pointer may be passed to the `cir.vtable.get_virtual_fn_addr`
+ operation to get the address of a virtual function pointer.
The pointer may also be cast to other pointer types in order to perform
pointer arithmetic based on information encoded in the AST layout to get
diff --git a/clang/include/clang/CIR/Dialect/Passes.h b/clang/include/clang/CIR/Dialect/Passes.h
index 7a202b1..32c3e27 100644
--- a/clang/include/clang/CIR/Dialect/Passes.h
+++ b/clang/include/clang/CIR/Dialect/Passes.h
@@ -26,6 +26,7 @@ std::unique_ptr<Pass> createCIRSimplifyPass();
std::unique_ptr<Pass> createHoistAllocasPass();
std::unique_ptr<Pass> createLoweringPreparePass();
std::unique_ptr<Pass> createLoweringPreparePass(clang::ASTContext *astCtx);
+std::unique_ptr<Pass> createGotoSolverPass();
void populateCIRPreLoweringPasses(mlir::OpPassManager &pm);
diff --git a/clang/include/clang/CIR/Dialect/Passes.td b/clang/include/clang/CIR/Dialect/Passes.td
index 7d5ec2f..0f57839 100644
--- a/clang/include/clang/CIR/Dialect/Passes.td
+++ b/clang/include/clang/CIR/Dialect/Passes.td
@@ -72,6 +72,16 @@ def CIRFlattenCFG : Pass<"cir-flatten-cfg"> {
let dependentDialects = ["cir::CIRDialect"];
}
+def GotoSolver : Pass<"cir-goto-solver"> {
+ let summary = "Replaces goto operations with branches";
+ let description = [{
+ This pass transforms CIR and replaces goto-s with branch
+ operations to the proper blocks.
+ }];
+ let constructor = "mlir::createGotoSolverPass()";
+ let dependentDialects = ["cir::CIRDialect"];
+}
+
def LoweringPrepare : Pass<"cir-lowering-prepare"> {
let summary = "Lower to more fine-grained CIR operations before lowering to "
"other dialects";
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 27dd181..6a8bab2 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -27,9 +27,6 @@ struct MissingFeatures {
// Address space related
static bool addressSpace() { return false; }
- // CIRGenFunction implementation details
- static bool cgfSymbolTable() { return false; }
-
// Unhandled global/linkage information.
static bool opGlobalThreadLocal() { return false; }
static bool opGlobalConstant() { return false; }
@@ -52,7 +49,6 @@ struct MissingFeatures {
static bool opLoadEmitScalarRangeCheck() { return false; }
static bool opLoadBooleanRepresentation() { return false; }
static bool opLoadStoreTbaa() { return false; }
- static bool opLoadStoreMemOrder() { return false; }
static bool opLoadStoreVolatile() { return false; }
static bool opLoadStoreAtomic() { return false; }
static bool opLoadStoreObjC() { return false; }
@@ -87,7 +83,6 @@ struct MissingFeatures {
static bool setFunctionAttributes() { return false; }
// CallOp handling
- static bool opCallPseudoDtor() { return false; }
static bool opCallAggregateArgs() { return false; }
static bool opCallPaddingArgs() { return false; }
static bool opCallABIExtendArg() { return false; }
@@ -98,8 +93,8 @@ struct MissingFeatures {
static bool opCallReturn() { return false; }
static bool opCallArgEvaluationOrder() { return false; }
static bool opCallCallConv() { return false; }
+ static bool opCallSideEffect() { return false; }
static bool opCallMustTail() { return false; }
- static bool opCallVirtual() { return false; }
static bool opCallInAlloca() { return false; }
static bool opCallAttrs() { return false; }
static bool opCallSurroundingTry() { return false; }
@@ -162,6 +157,15 @@ struct MissingFeatures {
static bool addressIsKnownNonNull() { return false; }
static bool addressPointerAuthInfo() { return false; }
+ // Atomic
+ static bool atomicExpr() { return false; }
+ static bool atomicInfo() { return false; }
+ static bool atomicInfoGetAtomicPointer() { return false; }
+ static bool atomicInfoGetAtomicAddress() { return false; }
+ static bool atomicUseLibCall() { return false; }
+ static bool atomicScope() { return false; }
+ static bool atomicSyncScopeID() { return false; }
+
// Misc
static bool abiArgInfo() { return false; }
static bool addHeapAllocSiteMetadata() { return false; }
@@ -173,7 +177,12 @@ struct MissingFeatures {
static bool aggValueSlotVolatile() { return false; }
static bool alignCXXRecordDecl() { return false; }
static bool armComputeVolatileBitfields() { return false; }
+ static bool asmGoto() { return false; }
+ static bool asmInputOperands() { return false; }
static bool asmLabelAttr() { return false; }
+ static bool asmMemoryEffects() { return false; }
+ static bool asmOutputOperands() { return false; }
+ static bool asmUnwindClobber() { return false; }
static bool assignMemcpyizer() { return false; }
static bool astVarDeclInterface() { return false; }
static bool attributeBuiltin() { return false; }
@@ -187,18 +196,26 @@ struct MissingFeatures {
static bool cirgenABIInfo() { return false; }
static bool cleanupAfterErrorDiags() { return false; }
static bool cleanupsToDeactivate() { return false; }
+ static bool constEmitterAggILE() { return false; }
static bool constEmitterArrayILE() { return false; }
static bool constEmitterVectorILE() { return false; }
static bool constantFoldSwitchStatement() { return false; }
static bool constructABIArgDirectExtend() { return false; }
static bool coverageMapping() { return false; }
+ static bool createInvariantGroup() { return false; }
static bool createProfileWeightsForLoop() { return false; }
static bool ctorMemcpyizer() { return false; }
static bool cudaSupport() { return false; }
static bool cxxRecordStaticMembers() { return false; }
+ static bool dataLayoutTypeIsSized() { return false; }
static bool dataLayoutTypeAllocSize() { return false; }
+ static bool dataLayoutTypeStoreSize() { return false; }
static bool deferredCXXGlobalInit() { return false; }
+ static bool devirtualizeMemberFunction() { return false; }
static bool ehCleanupFlags() { return false; }
+ static bool ehCleanupScope() { return false; }
+ static bool ehCleanupScopeRequiresEHCleanup() { return false; }
+ static bool ehCleanupBranchFixups() { return false; }
static bool ehstackBranches() { return false; }
static bool emitCheckedInBoundsGEP() { return false; }
static bool emitCondLikelihoodViaExpectIntrinsic() { return false; }
@@ -206,12 +223,16 @@ struct MissingFeatures {
static bool emitLValueAlignmentAssumption() { return false; }
static bool emitNullabilityCheck() { return false; }
static bool emitTypeCheck() { return false; }
+ static bool emitTypeMetadataCodeForVCall() { return false; }
static bool fastMathFlags() { return false; }
static bool fpConstraints() { return false; }
static bool generateDebugInfo() { return false; }
+ static bool globalViewIndices() { return false; }
+ static bool globalViewIntLowering() { return false; }
static bool hip() { return false; }
static bool implicitConstructorArgs() { return false; }
static bool incrementProfileCounter() { return false; }
+ static bool innermostEHScope() { return false; }
static bool insertBuiltinUnpredictable() { return false; }
static bool instrumentation() { return false; }
static bool intrinsics() { return false; }
@@ -231,8 +252,8 @@ struct MissingFeatures {
static bool objCBlocks() { return false; }
static bool objCGC() { return false; }
static bool objCLifetime() { return false; }
+ static bool openCL() { return false; }
static bool openMP() { return false; }
- static bool opGlobalViewAttr() { return false; }
static bool opTBAA() { return false; }
static bool peepholeProtection() { return false; }
static bool pgoUse() { return false; }
@@ -245,6 +266,7 @@ struct MissingFeatures {
static bool setNonGC() { return false; }
static bool setObjCGCLValueClass() { return false; }
static bool setTargetAttributes() { return false; }
+ static bool sourceLanguageCases() { return false; }
static bool stackBase() { return false; }
static bool stackSaveOp() { return false; }
static bool targetCIRGenInfoArch() { return false; }
@@ -258,7 +280,10 @@ struct MissingFeatures {
static bool appleKext() { return false; }
static bool dtorCleanups() { return false; }
static bool vtableInitialization() { return false; }
+ static bool vtableEmitMetadata() { return false; }
+ static bool vtableRelativeLayout() { return false; }
static bool msvcBuiltins() { return false; }
+ static bool vaArgABILowering() { return false; }
static bool vlas() { return false; }
// Missing types
diff --git a/clang/include/clang/CodeGen/CGFunctionInfo.h b/clang/include/clang/CodeGen/CGFunctionInfo.h
index 50be517..713b52a 100644
--- a/clang/include/clang/CodeGen/CGFunctionInfo.h
+++ b/clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -77,6 +77,11 @@ public:
/// Array elements in the type are assumed to be padding and skipped.
CoerceAndExpand,
+ /// TargetSpecific - Some argument types are passed as target specific types
+ /// such as RISC-V's tuple type, these need to be handled in the target
+ /// hook.
+ TargetSpecific,
+
/// InAlloca - Pass the argument directly using the LLVM inalloca attribute.
/// This is similar to indirect with byval, except it only applies to
/// arguments stored in memory and forbids any implicit copies. When
@@ -120,7 +125,7 @@ private:
bool canHavePaddingType() const {
return isDirect() || isExtend() || isIndirect() || isIndirectAliased() ||
- isExpand();
+ isExpand() || isTargetSpecific();
}
void setPaddingType(llvm::Type *T) {
assert(canHavePaddingType());
@@ -291,6 +296,20 @@ public:
return AI;
}
+ static ABIArgInfo getTargetSpecific(llvm::Type *T = nullptr,
+ unsigned Offset = 0,
+ llvm::Type *Padding = nullptr,
+ bool CanBeFlattened = true,
+ unsigned Align = 0) {
+ auto AI = ABIArgInfo(TargetSpecific);
+ AI.setCoerceToType(T);
+ AI.setPaddingType(Padding);
+ AI.setDirectOffset(Offset);
+ AI.setDirectAlign(Align);
+ AI.setCanBeFlattened(CanBeFlattened);
+ return AI;
+ }
+
static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) {
return eltType->isArrayTy() &&
eltType->getArrayElementType()->isIntegerTy(8);
@@ -305,27 +324,33 @@ public:
bool isIndirectAliased() const { return TheKind == IndirectAliased; }
bool isExpand() const { return TheKind == Expand; }
bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
+ bool isTargetSpecific() const { return TheKind == TargetSpecific; }
bool canHaveCoerceToType() const {
- return isDirect() || isExtend() || isCoerceAndExpand();
+ return isDirect() || isExtend() || isCoerceAndExpand() ||
+ isTargetSpecific();
}
// Direct/Extend accessors
unsigned getDirectOffset() const {
- assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ assert((isDirect() || isExtend() || isTargetSpecific()) &&
+ "Not a direct or extend or target specific kind");
return DirectAttr.Offset;
}
void setDirectOffset(unsigned Offset) {
- assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ assert((isDirect() || isExtend() || isTargetSpecific()) &&
+ "Not a direct or extend or target specific kind");
DirectAttr.Offset = Offset;
}
unsigned getDirectAlign() const {
- assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ assert((isDirect() || isExtend() || isTargetSpecific()) &&
+ "Not a direct or extend or target specific kind");
return DirectAttr.Align;
}
void setDirectAlign(unsigned Align) {
- assert((isDirect() || isExtend()) && "Not a direct or extend kind");
+ assert((isDirect() || isExtend() || isTargetSpecific()) &&
+ "Not a direct or extend or target specific kind");
DirectAttr.Align = Align;
}
@@ -394,12 +419,14 @@ public:
}
bool getInReg() const {
- assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
+ assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
+ "Invalid kind!");
return InReg;
}
void setInReg(bool IR) {
- assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
+ assert((isDirect() || isExtend() || isIndirect() || isTargetSpecific()) &&
+ "Invalid kind!");
InReg = IR;
}
@@ -481,12 +508,12 @@ public:
}
bool getCanBeFlattened() const {
- assert(isDirect() && "Invalid kind!");
+ assert((isDirect() || isTargetSpecific()) && "Invalid kind!");
return CanBeFlattened;
}
void setCanBeFlattened(bool Flatten) {
- assert(isDirect() && "Invalid kind!");
+ assert((isDirect() || isTargetSpecific()) && "Invalid kind!");
CanBeFlattened = Flatten;
}
diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h
index 836fdd7..16f39b991 100644
--- a/clang/include/clang/CodeGen/CodeGenABITypes.h
+++ b/clang/include/clang/CodeGen/CodeGenABITypes.h
@@ -32,6 +32,7 @@
namespace llvm {
class AttrBuilder;
class Constant;
+class ConstantInt;
class Function;
class FunctionType;
class Type;
@@ -126,6 +127,12 @@ uint16_t getPointerAuthDeclDiscriminator(CodeGenModule &CGM, GlobalDecl GD);
uint16_t getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
QualType FunctionType);
+/// Return a signed constant pointer.
+llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
+ llvm::Constant *Pointer, unsigned Key,
+ llvm::Constant *StorageAddress,
+ llvm::ConstantInt *OtherDiscriminator);
+
/// Given the language and code-generation options that Clang was configured
/// with, set the default LLVM IR attributes for a function definition.
/// The attributes set here are mostly global target-configuration and
diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h
index 7aecfd8..dbf1187 100644
--- a/clang/include/clang/Driver/Action.h
+++ b/clang/include/clang/Driver/Action.h
@@ -76,9 +76,10 @@ public:
StaticLibJobClass,
BinaryAnalyzeJobClass,
BinaryTranslatorJobClass,
+ ObjcopyJobClass,
JobClassFirst = PreprocessJobClass,
- JobClassLast = BinaryTranslatorJobClass
+ JobClassLast = ObjcopyJobClass
};
// The offloading kind determines if this action is binded to a particular
@@ -687,6 +688,17 @@ public:
}
};
+class ObjcopyJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ ObjcopyJobAction(Action *Input, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == ObjcopyJobClass;
+ }
+};
+
} // namespace driver
} // namespace clang
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index 9802962d..1464ce4 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -85,6 +85,8 @@ const char *RelocationModelName(llvm::Reloc::Model Model);
std::tuple<llvm::Reloc::Model, unsigned, bool>
ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args);
+bool getStaticPIE(const llvm::opt::ArgList &Args, const ToolChain &TC);
+
unsigned ParseFunctionAlignment(const ToolChain &TC,
const llvm::opt::ArgList &Args);
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index 4d32552..b9b187a 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -512,6 +512,9 @@ public:
/// BuildActions - Construct the list of actions to perform for the
/// given arguments, which are only done for a single architecture.
+ /// If the compilation is an explicit module build, delegates to
+ /// BuildDriverManagedModuleBuildActions. Otherwise, BuildDefaultActions is
+ /// used.
///
/// \param C - The compilation that is being built.
/// \param Args - The input arguments.
@@ -796,6 +799,35 @@ private:
/// compilation based on which -f(no-)?lto(=.*)? option occurs last.
void setLTOMode(const llvm::opt::ArgList &Args);
+ /// BuildDefaultActions - Constructs the list of actions to perform
+ /// for the provided arguments, which are only done for a single architecture.
+ ///
+ /// \param C - The compilation that is being built.
+ /// \param Args - The input arguments.
+ /// \param Actions - The list to store the resulting actions onto.
+ void BuildDefaultActions(Compilation &C, llvm::opt::DerivedArgList &Args,
+ const InputList &Inputs, ActionList &Actions) const;
+
+ /// BuildDriverManagedModuleBuildActions - Performs a dependency
+ /// scan and constructs the list of actions to perform for dependency order
+ /// and the provided arguments. This is only done for a single a architecture.
+ ///
+ /// \param C - The compilation that is being built.
+ /// \param Args - The input arguments.
+ /// \param Actions - The list to store the resulting actions onto.
+ void BuildDriverManagedModuleBuildActions(Compilation &C,
+ llvm::opt::DerivedArgList &Args,
+ const InputList &Inputs,
+ ActionList &Actions) const;
+
+ /// Scans the leading lines of the C++ source inputs to detect C++20 module
+ /// usage.
+ ///
+ /// \returns True if module usage is detected, false otherwise, or an error on
+ /// read failure.
+ llvm::ErrorOr<bool>
+ ScanInputsForCXX20ModulesUsage(const InputList &Inputs) const;
+
/// Retrieves a ToolChain for a particular \p Target triple.
///
/// Will cache ToolChains for the life of the driver object, and create them
diff --git a/clang/include/clang/Driver/OffloadBundler.h b/clang/include/clang/Driver/OffloadBundler.h
index 667156a..e7306ce 100644
--- a/clang/include/clang/Driver/OffloadBundler.h
+++ b/clang/include/clang/Driver/OffloadBundler.h
@@ -120,7 +120,7 @@ public:
static llvm::Expected<CompressedBundleHeader> tryParse(llvm::StringRef);
};
- static inline const uint16_t DefaultVersion = 2;
+ static inline const uint16_t DefaultVersion = 3;
static llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
compress(llvm::compression::Params P, const llvm::MemoryBuffer &Input,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 6aab43c..f507968d 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1851,7 +1851,7 @@ defm pseudo_probe_for_profiling
CodeGenOpts<"PseudoProbeForProfiling">, DefaultFalse,
PosFlag<SetTrue, [], [ClangOption], "Emit">,
NegFlag<SetFalse, [], [ClangOption], "Do not emit">,
- BothFlags<[], [ClangOption, CC1Option],
+ BothFlags<[], [ClangOption, CC1Option, CLOption],
" pseudo probes for sample profiling">>;
def fprofile_list_EQ : Joined<["-"], "fprofile-list=">,
Group<f_Group>, Visibility<[ClangOption, CC1Option, CLOption]>,
@@ -2612,16 +2612,27 @@ def fsanitize_undefined_trap_on_error
def fno_sanitize_undefined_trap_on_error
: Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group<f_clang_Group>,
Alias<fno_sanitize_trap_EQ>, AliasArgs<["undefined"]>;
-defm sanitize_debug_trap_reasons
- : BoolFOption<
- "sanitize-debug-trap-reasons",
- CodeGenOpts<"SanitizeDebugTrapReasons">, DefaultTrue,
- PosFlag<SetTrue, [], [ClangOption, CC1Option],
- "Annotate trap blocks in debug info with UBSan trap reasons">,
- NegFlag<SetFalse, [], [ClangOption, CC1Option],
- "Do not annotate trap blocks in debug info with UBSan trap "
- "reasons">>;
-
+def fsanitize_debug_trap_reasons_EQ
+ : Joined<["-"], "fsanitize-debug-trap-reasons=">, Group<f_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"Set how trap reasons are emitted. "
+ "`none` - Not emitted. This gives the smallest debug info; "
+ "`basic` - Emit a fixed trap message per check type. This increases the "
+ "debug info size but not as much as `detailed`; "
+ "`detailed` - Emit a more detailed trap message. This increases the "
+ "debug info size the most. Default is `detailed`.">,
+ Values<"none,basic,detailed">,
+ NormalizedValuesScope<"CodeGenOptions::SanitizeDebugTrapReasonKind">,
+ NormalizedValues<["None", "Basic", "Detailed"]>,
+ MarshallingInfoEnum<CodeGenOpts<"SanitizeDebugTrapReasons">, "Detailed">;
+def fsanitize_debug_trap_reasons
+ : Flag<["-"], "fsanitize-debug-trap-reasons">, Group<f_clang_Group>,
+ Alias<fsanitize_debug_trap_reasons_EQ>, AliasArgs<["detailed"]>,
+ HelpText<"Alias for -fsanitize-debug-trap-reasons=detailed">;
+def fno_sanitize_debug_trap_reasons
+ : Flag<["-"], "fno-sanitize-debug-trap-reasons">, Group<f_clang_Group>,
+ Alias<fsanitize_debug_trap_reasons_EQ>, AliasArgs<["none"]>,
+ HelpText<"Alias for -fsanitize-debug-trap-reasons=none">;
defm sanitize_minimal_runtime : BoolOption<"f", "sanitize-minimal-runtime",
CodeGenOpts<"SanitizeMinimalRuntime">, DefaultFalse,
PosFlag<SetTrue>,
@@ -3296,6 +3307,13 @@ defm modules_reduced_bmi : BoolOption<"f", "modules-reduced-bmi",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Generate the reduced BMI">>;
+def fmodules_driver : Flag<["-"], "fmodules-driver">,
+ Group<f_Group>, Visibility<[ClangOption]>,
+ HelpText<"Enable support for driver managed module builds (experimental)">;
+def fno_modules_driver : Flag<["-"], "fno-modules-driver">,
+ Group<f_Group>, Visibility<[ClangOption]>,
+ HelpText<"Disable support for driver managed module builds (experimental)">;
+
def experimental_modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
Group<f_Group>, Visibility<[ClangOption, CC1Option]>, Alias<fmodules_reduced_bmi>;
@@ -3731,14 +3749,20 @@ def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">,
def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">,
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>,
Visibility<[ClangOption, CC1Option]>;
-def fopenmp_simd : Flag<["-"], "fopenmp-simd">, Group<f_Group>,
- Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>,
- HelpText<"Emit OpenMP code only for SIMD-based constructs.">;
+def fopenmp_simd : Flag<["-"], "fopenmp-simd">,
+ Group<f_Group>,
+ Flags<[NoArgumentUnused]>,
+ Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
+ HelpText<"Emit OpenMP code only for SIMD-based constructs.">;
def fopenmp_enable_irbuilder : Flag<["-"], "fopenmp-enable-irbuilder">, Group<f_Group>,
Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Use the experimental OpenMP-IR-Builder codegen path.">;
-def fno_openmp_simd : Flag<["-"], "fno-openmp-simd">, Group<f_Group>,
- Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>;
+def fno_openmp_simd
+ : Flag<["-"], "fno-openmp-simd">,
+ Group<f_Group>,
+ Flags<[NoArgumentUnused]>,
+ Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
+ HelpText<"Do not emit code for any OpenMP constructs.">;
def fopenmp_cuda_mode : Flag<["-"], "fopenmp-cuda-mode">, Group<f_Group>,
Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
def fno_openmp_cuda_mode : Flag<["-"], "fno-openmp-cuda-mode">, Group<f_Group>,
@@ -4540,6 +4564,7 @@ defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening",
defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and authentication of Objective-C object's 'isa' field">;
defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", "Enable signing and authentication of Objective-C object's 'SEL' fields">;
defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable signing and authentication for ObjC class_ro pointers">;
+defm ptrauth_block_descriptor_pointers : OptInCC1FFlag<"ptrauth-block-descriptor-pointers", "Enable signing and authentication of block descriptors">;
}
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
@@ -5589,7 +5614,8 @@ def mno_outline_atomics : Flag<["-"], "mno-outline-atomics">, Group<f_clang_Grou
HelpText<"Don't generate local calls to out-of-line atomic operations">;
def mno_implicit_float : Flag<["-"], "mno-implicit-float">, Group<m_Group>,
HelpText<"Don't generate implicit floating point or vector instructions">;
-def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>;
+def mimplicit_float : Flag<["-"], "mimplicit-float">, Group<m_Group>,
+ HelpText<"Generate implicit floating point or vector instructions">;
def mrecip : Flag<["-"], "mrecip">, Group<m_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Equivalent to '-mrecip=all'">;
@@ -6805,10 +6831,10 @@ def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group<m_x86_Feature
def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group<m_x86_Features_Group>,
HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">, Visibility<[ClangOption, CLOption, FlangOption]>;
def mapxf : Flag<["-"], "mapxf">, Alias<mapx_features_EQ>,
- AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf","zu"]>,
+ AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","zu"]>,
Group<m_x86_Features_Group>;
def mno_apxf : Flag<["-"], "mno-apxf">, Alias<mno_apx_features_EQ>,
- AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","cf","zu"]>,
+ AliasArgs<["egpr","push2pop2","ppx","ndd","ccmp","nf","zu"]>,
Group<m_x86_Features_Group>;
def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>,
HelpText<"Enable use of GPR32 in inline assembly for APX">;
@@ -6979,7 +7005,6 @@ def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group
// "f" options with values for gfortran.
def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>;
def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
-def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
@@ -8688,6 +8713,15 @@ def fopenmp_host_ir_file_path : Separate<["-"], "fopenmp-host-ir-file-path">,
} // let Visibility = [CC1Option, FC1Option]
//===----------------------------------------------------------------------===//
+// Coarray Options
+//===----------------------------------------------------------------------===//
+
+def fcoarray : Flag<["-"], "fcoarray">,
+ Group<f_Group>,
+ Visibility<[FlangOption, FC1Option]>,
+ HelpText<"Enable Coarray features">;
+
+//===----------------------------------------------------------------------===//
// SYCL Options
//===----------------------------------------------------------------------===//
@@ -9381,6 +9415,11 @@ def res_may_alias : Option<["/", "-"], "res-may-alias", KIND_FLAG>,
Visibility<[DXCOption, ClangOption, CC1Option]>,
HelpText<"Assume that UAVs/SRVs may alias">,
MarshallingInfoFlag<CodeGenOpts<"ResMayAlias">>;
+def dxc_strip_rootsignature :
+ Option<["/", "-"], "Qstrip-rootsignature", KIND_FLAG>,
+ Group<dxc_Group>,
+ Visibility<[DXCOption]>,
+ HelpText<"Omit the root signature from produced DXContainer">;
def target_profile : DXCJoinedOrSeparate<"T">, MetaVarName<"<profile>">,
HelpText<"Set target profile">,
Values<"ps_6_0, ps_6_1, ps_6_2, ps_6_3, ps_6_4, ps_6_5, ps_6_6, ps_6_7,"
@@ -9413,6 +9452,18 @@ def dxc_rootsig_ver :
Alias<fdx_rootsignature_version>,
Group<dxc_Group>,
Visibility<[DXCOption]>;
+def fdx_rootsignature_define :
+ Joined<["-"], "fdx-rootsignature-define=">,
+ Group<dxc_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ MarshallingInfoString<LangOpts<"HLSLRootSigOverride">, "\"\"">,
+ HelpText<"Override entry function root signature with root signature at "
+ "given macro name.">;
+def dxc_rootsig_define :
+ Separate<["-"], "rootsig-define">,
+ Alias<fdx_rootsignature_define>,
+ Group<dxc_Group>,
+ Visibility<[DXCOption]>;
def hlsl_entrypoint : Option<["-"], "hlsl-entry", KIND_SEPARATE>,
Group<dxc_Group>,
Visibility<[ClangOption, CC1Option]>,
@@ -9445,8 +9496,12 @@ def fspv_target_env_EQ : Joined<["-"], "fspv-target-env=">, Group<dxc_Group>,
def fspv_extension_EQ
: Joined<["-"], "fspv-extension=">,
Group<dxc_Group>,
- HelpText<"Specify the available SPIR-V extensions. If this option is not "
- "specified, then all extensions are available.">;
+ HelpText<
+ "Specify the available SPIR-V extensions. If this option is not "
+ "specified, then all extensions are available. If KHR is specified, "
+ "then all KHR extensions will be available. If DXC is specifided, "
+ "then all extensions implemented by the DirectX Shader compiler will "
+ "be available. This option is useful for moving from DXC to Clang.">;
def fvk_use_dx_layout
: DXCFlag<"fvk-use-dx-layout">,
HelpText<"Use DirectX memory layout for Vulkan resources.">;
@@ -9457,6 +9512,16 @@ def fvk_use_scalar_layout
: DXCFlag<"fvk-use-scalar-layout">,
HelpText<"Use scalar memory layout for Vulkan resources.">;
+def fhlsl_spv_use_unknown_image_format
+ : Flag<["-"], "fspv-use-unknown-image-format">,
+ Group<dxc_Group>,
+ Visibility<[CC1Option, DXCOption]>,
+ HelpText<"For storage images and texel buffers, sets the default format "
+ "to 'Unknown' when not specified via the `vk::image_format` "
+ "attribute. If this option is not used, the format is inferred "
+ "from the resource's data type.">,
+ MarshallingInfoFlag<LangOpts<"HLSLSpvUseUnknownImageFormat">>;
+
def no_wasm_opt : Flag<["--"], "no-wasm-opt">,
Group<m_Group>,
HelpText<"Disable the wasm-opt optimizer">,
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index 2430563..1425714 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -224,9 +224,6 @@ protected:
static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
- static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args,
- const Twine &Path);
static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
const Twine &Path);
@@ -246,6 +243,9 @@ protected:
///@}
public:
+ static void addSystemInclude(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ const Twine &Path);
virtual ~ToolChain();
// Accessors
diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h
index 4ac7444..4859225 100644
--- a/clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -440,9 +440,8 @@ private:
DeclarationFragments &);
/// Build DeclarationFragments for a NestedNameSpecifier.
- static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *,
- ASTContext &,
- DeclarationFragments &);
+ static DeclarationFragments
+ getFragmentsForNNS(NestedNameSpecifier, ASTContext &, DeclarationFragments &);
/// Build DeclarationFragments for Qualifiers.
static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals);
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 31582a4..5dfdb23 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4813,14 +4813,45 @@ struct FormatStyle {
/// \version 7
bool SpaceBeforeRangeBasedForLoopColon;
- /// If ``true``, spaces will be inserted into ``{}``.
- /// \code
- /// true: false:
- /// void f() { } vs. void f() {}
- /// while (true) { } while (true) {}
- /// \endcode
+ /// This option is **deprecated**. See ``Block`` of ``SpaceInEmptyBraces``.
/// \version 10
- bool SpaceInEmptyBlock;
+ // bool SpaceInEmptyBlock;
+
+ /// Style of when to insert a space in empty braces.
+ enum SpaceInEmptyBracesStyle : int8_t {
+ /// Always insert a space in empty braces.
+ /// \code
+ /// void f() { }
+ /// class Unit { };
+ /// auto a = [] { };
+ /// int x{ };
+ /// \endcode
+ SIEB_Always,
+ /// Only insert a space in empty blocks.
+ /// \code
+ /// void f() { }
+ /// class Unit { };
+ /// auto a = [] { };
+ /// int x{};
+ /// \endcode
+ SIEB_Block,
+ /// Never insert a space in empty braces.
+ /// \code
+ /// void f() {}
+ /// class Unit {};
+ /// auto a = [] {};
+ /// int x{};
+ /// \endcode
+ SIEB_Never
+ };
+
+ /// Specifies when to insert a space in empty braces.
+ /// \note
+ /// This option doesn't apply to initializer braces if
+ /// ``Cpp11BracedListStyle`` is set to ``true``.
+ /// \endnote
+ /// \version 22
+ SpaceInEmptyBracesStyle SpaceInEmptyBraces;
/// If ``true``, spaces may be inserted into ``()``.
/// This option is **deprecated**. See ``InEmptyParentheses`` of
@@ -5494,7 +5525,7 @@ struct FormatStyle {
SpaceBeforeRangeBasedForLoopColon ==
R.SpaceBeforeRangeBasedForLoopColon &&
SpaceBeforeSquareBrackets == R.SpaceBeforeSquareBrackets &&
- SpaceInEmptyBlock == R.SpaceInEmptyBlock &&
+ SpaceInEmptyBraces == R.SpaceInEmptyBraces &&
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
SpacesInAngles == R.SpacesInAngles &&
SpacesInContainerLiterals == R.SpacesInContainerLiterals &&
diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h
index a5dfb77..73308c0 100644
--- a/clang/include/clang/Frontend/FrontendActions.h
+++ b/clang/include/clang/Frontend/FrontendActions.h
@@ -329,6 +329,18 @@ public:
: ModuleName(ModuleName) {}
};
+//===----------------------------------------------------------------------===//
+// HLSL Specific Actions
+//===----------------------------------------------------------------------===//
+
+class HLSLFrontendAction : public WrapperFrontendAction {
+protected:
+ void ExecuteAction() override;
+
+public:
+ HLSLFrontendAction(std::unique_ptr<FrontendAction> WrappedAction);
+};
+
} // end namespace clang
#endif
diff --git a/clang/include/clang/Index/IndexSymbol.h b/clang/include/clang/Index/IndexSymbol.h
index 59e90fc..deb9337 100644
--- a/clang/include/clang/Index/IndexSymbol.h
+++ b/clang/include/clang/Index/IndexSymbol.h
@@ -27,6 +27,7 @@ enum class SymbolKind : uint8_t {
Namespace,
NamespaceAlias,
Macro,
+ IncludeDirective,
Enum,
Struct,
diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 83d2962..8c124aa 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -37,7 +37,6 @@ class ThreadSafeContext;
namespace clang {
class CompilerInstance;
-class CodeGenerator;
class CXXRecordDecl;
class Decl;
class IncrementalExecutor;
@@ -110,10 +109,6 @@ class Interpreter {
// printing happens, it's in an invalid state.
Value LastValue;
- /// When CodeGen is created the first llvm::Module gets cached in many places
- /// and we must keep it alive.
- std::unique_ptr<llvm::Module> CachedInCodeGenModule;
-
/// Compiler instance performing the incremental compilation.
std::unique_ptr<CompilerInstance> CI;
@@ -175,15 +170,9 @@ public:
llvm::Expected<llvm::orc::ExecutorAddr>
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
- std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
- PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
- std::unique_ptr<llvm::Module> M = {},
- IncrementalAction *Action = nullptr);
-
private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();
- llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
// A cache for the compiled destructors used to for de-allocation of managed
// clang::Values.
@@ -206,11 +195,6 @@ private:
// This function forces emission of the needed dtor.
llvm::Expected<llvm::orc::ExecutorAddr>
CompileDtorCall(CXXRecordDecl *CXXRD) const;
-
- /// @}
- /// @name Code generation
- /// @{
- CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
};
} // namespace clang
diff --git a/clang/include/clang/Lex/DependencyDirectivesScanner.h b/clang/include/clang/Lex/DependencyDirectivesScanner.h
index f9fec39..c0b742d 100644
--- a/clang/include/clang/Lex/DependencyDirectivesScanner.h
+++ b/clang/include/clang/Lex/DependencyDirectivesScanner.h
@@ -135,6 +135,13 @@ void printDependencyDirectivesAsSource(
ArrayRef<dependency_directives_scan::Directive> Directives,
llvm::raw_ostream &OS);
+/// Scan an input source buffer for C++20 named module usage.
+///
+/// \param Source The input source buffer.
+///
+/// \returns true if any C++20 named modules related directive was found.
+bool scanInputForCXX20ModulesUsage(StringRef Source);
+
/// Functor that returns the dependency directives for a given file.
class DependencyDirectivesGetter {
public:
diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index 06971ff..423f2ff 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -143,9 +143,6 @@ class Lexer : public PreprocessorLexer {
/// True if this is the first time we're lexing the input file.
bool IsFirstTimeLexingFile;
- /// True if current lexing token is the first pp-token.
- bool IsFirstPPToken;
-
// NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n',
// it also points to '\n.'
const char *NewLinePtr;
diff --git a/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h b/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h
new file mode 100644
index 0000000..9ab3c6a
--- /dev/null
+++ b/clang/include/clang/Lex/NoTrivialPPDirectiveTracer.h
@@ -0,0 +1,310 @@
+//===--- NoTrivialPPDirectiveTracer.h ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the NoTrivialPPDirectiveTracer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
+#define LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
+
+#include "clang/Lex/PPCallbacks.h"
+
+namespace clang {
+class Preprocessor;
+
+/// Consider the following code:
+///
+/// # 1 __FILE__ 1 3
+/// export module a;
+///
+/// According to the wording in
+/// [P1857R3](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1857r3.html):
+///
+/// A module directive may only appear as the first preprocessing tokens in a
+/// file (excluding the global module fragment.)
+///
+/// and the wording in
+/// [[cpp.pre]](https://eel.is/c++draft/cpp.pre#nt:module-file):
+/// module-file:
+/// pp-global-module-fragment[opt] pp-module group[opt]
+/// pp-private-module-fragment[opt]
+///
+/// `#` is the first pp-token in the translation unit, and it was rejected by
+/// clang, but they really should be exempted from this rule. The goal is to not
+/// allow any preprocessor conditionals or most state changes, but these don't
+/// fit that.
+///
+/// State change would mean most semantically observable preprocessor state,
+/// particularly anything that is order dependent. Global flags like being a
+/// system header/module shouldn't matter.
+///
+/// We should exempt a brunch of directives, even though it violates the current
+/// standard wording.
+///
+/// This class used to trace 'no-trivial' pp-directives in main file, which may
+/// change the preprocessing state.
+///
+/// FIXME: Once the wording of the standard is revised, we need to follow the
+/// wording of the standard. Currently this is just a workaround
+class NoTrivialPPDirectiveTracer : public PPCallbacks {
+ Preprocessor &PP;
+
+ /// Whether preprocessing main file. We only focus on the main file.
+ bool InMainFile = true;
+
+ /// Whether one or more conditional, include or other 'no-trivial'
+ /// pp-directives has seen before.
+ bool SeenNoTrivialPPDirective = false;
+
+ void setSeenNoTrivialPPDirective();
+
+public:
+ NoTrivialPPDirectiveTracer(Preprocessor &P) : PP(P) {}
+
+ bool hasSeenNoTrivialPPDirective() const;
+
+ /// Callback invoked whenever the \p Lexer moves to a different file for
+ /// lexing. Unlike \p FileChanged line number directives and other related
+ /// pragmas do not trigger callbacks to \p LexedFileChanged.
+ ///
+ /// \param FID The \p FileID that the \p Lexer moved to.
+ ///
+ /// \param Reason Whether the \p Lexer entered a new file or exited one.
+ ///
+ /// \param FileType The \p CharacteristicKind of the file the \p Lexer moved
+ /// to.
+ ///
+ /// \param PrevFID The \p FileID the \p Lexer was using before the change.
+ ///
+ /// \param Loc The location where the \p Lexer entered a new file from or the
+ /// location that the \p Lexer moved into after exiting a file.
+ void LexedFileChanged(FileID FID, LexedFileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType, FileID PrevFID,
+ SourceLocation Loc) override;
+
+ /// Callback invoked whenever an embed directive has been processed,
+ /// regardless of whether the embed will actually find a file.
+ ///
+ /// \param HashLoc The location of the '#' that starts the embed directive.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \param IsAngled Whether the file name was enclosed in angle brackets;
+ /// otherwise, it was enclosed in quotes.
+ ///
+ /// \param File The actual file that may be included by this embed directive.
+ ///
+ /// \param Params The parameters used by the directive.
+ void EmbedDirective(SourceLocation HashLoc, StringRef FileName, bool IsAngled,
+ OptionalFileEntryRef File,
+ const LexEmbedParametersResult &Params) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Callback invoked whenever an inclusion directive of
+ /// any kind (\c \#include, \c \#import, etc.) has been processed, regardless
+ /// of whether the inclusion will actually result in an inclusion.
+ ///
+ /// \param HashLoc The location of the '#' that starts the inclusion
+ /// directive.
+ ///
+ /// \param IncludeTok The token that indicates the kind of inclusion
+ /// directive, e.g., 'include' or 'import'.
+ ///
+ /// \param FileName The name of the file being included, as written in the
+ /// source code.
+ ///
+ /// \param IsAngled Whether the file name was enclosed in angle brackets;
+ /// otherwise, it was enclosed in quotes.
+ ///
+ /// \param FilenameRange The character range of the quotes or angle brackets
+ /// for the written file name.
+ ///
+ /// \param File The actual file that may be included by this inclusion
+ /// directive.
+ ///
+ /// \param SearchPath Contains the search path which was used to find the file
+ /// in the file system. If the file was found via an absolute include path,
+ /// SearchPath will be empty. For framework includes, the SearchPath and
+ /// RelativePath will be split up. For example, if an include of "Some/Some.h"
+ /// is found via the framework path
+ /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be
+ /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be
+ /// "Some.h".
+ ///
+ /// \param RelativePath The path relative to SearchPath, at which the include
+ /// file was found. This is equal to FileName except for framework includes.
+ ///
+ /// \param SuggestedModule The module suggested for this header, if any.
+ ///
+ /// \param ModuleImported Whether this include was translated into import of
+ /// \p SuggestedModule.
+ ///
+ /// \param FileType The characteristic kind, indicates whether a file or
+ /// directory holds normal user code, system code, or system code which is
+ /// implicitly 'extern "C"' in C++ mode.
+ ///
+ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange,
+ OptionalFileEntryRef File, StringRef SearchPath,
+ StringRef RelativePath, const Module *SuggestedModule,
+ bool ModuleImported,
+ SrcMgr::CharacteristicKind FileType) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Callback invoked whenever there was an explicit module-import
+ /// syntax.
+ ///
+ /// \param ImportLoc The location of import directive token.
+ ///
+ /// \param Path The identifiers (and their locations) of the module
+ /// "path", e.g., "std.vector" would be split into "std" and "vector".
+ ///
+ /// \param Imported The imported module; can be null if importing failed.
+ ///
+ void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path,
+ const Module *Imported) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Callback invoked when the end of the main file is reached.
+ ///
+ /// No subsequent callbacks will be made.
+ void EndOfMainFile() override { setSeenNoTrivialPPDirective(); }
+
+ /// Callback invoked when start reading any pragma directive.
+ void PragmaDirective(SourceLocation Loc,
+ PragmaIntroducerKind Introducer) override {}
+
+ /// Called by Preprocessor::HandleMacroExpandedIdentifier when a
+ /// macro invocation is found.
+ void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range, const MacroArgs *Args) override;
+
+ /// Hook called whenever a macro definition is seen.
+ void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever a macro \#undef is seen.
+ /// \param MacroNameTok The active Token
+ /// \param MD A MacroDefinition for the named macro.
+ /// \param Undef New MacroDirective if the macro was defined, null otherwise.
+ ///
+ /// MD is released immediately following this callback.
+ void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+ const MacroDirective *Undef) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever the 'defined' operator is seen.
+ /// \param MD The MacroDirective if the name was a macro, null otherwise.
+ void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
+ SourceRange Range) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#if is seen.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param ConditionValue The evaluated value of the condition.
+ ///
+ // FIXME: better to pass in a list (or tree!) of Tokens.
+ void If(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#elif is seen.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param ConditionValue The evaluated value of the condition.
+ /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+ // FIXME: better to pass in a list (or tree!) of Tokens.
+ void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue, SourceLocation IfLoc) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#ifdef is seen.
+ /// \param Loc the source location of the directive.
+ /// \param MacroNameTok Information on the token being tested.
+ /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+ void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#elifdef branch is taken.
+ /// \param Loc the source location of the directive.
+ /// \param MacroNameTok Information on the token being tested.
+ /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+ void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override {
+ setSeenNoTrivialPPDirective();
+ }
+ /// Hook called whenever an \#elifdef is skipped.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+ // FIXME: better to pass in a list (or tree!) of Tokens.
+ void Elifdef(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#ifndef is seen.
+ /// \param Loc the source location of the directive.
+ /// \param MacroNameTok Information on the token being tested.
+ /// \param MD The MacroDefiniton if the name was a macro, null otherwise.
+ void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#elifndef branch is taken.
+ /// \param Loc the source location of the directive.
+ /// \param MacroNameTok Information on the token being tested.
+ /// \param MD The MacroDefinition if the name was a macro, null otherwise.
+ void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDefinition &MD) override {
+ setSeenNoTrivialPPDirective();
+ }
+ /// Hook called whenever an \#elifndef is skipped.
+ /// \param Loc the source location of the directive.
+ /// \param ConditionRange The SourceRange of the expression being tested.
+ /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+ // FIXME: better to pass in a list (or tree!) of Tokens.
+ void Elifndef(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#else is seen.
+ /// \param Loc the source location of the directive.
+ /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+ void Else(SourceLocation Loc, SourceLocation IfLoc) override {
+ setSeenNoTrivialPPDirective();
+ }
+
+ /// Hook called whenever an \#endif is seen.
+ /// \param Loc the source location of the directive.
+ /// \param IfLoc the source location of the \#if/\#ifdef/\#ifndef directive.
+ void Endif(SourceLocation Loc, SourceLocation IfLoc) override {
+ setSeenNoTrivialPPDirective();
+ }
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_LEX_NO_TRIVIAL_PPDIRECTIVE_TRACER_H
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 71b0f8e..3975484 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -82,6 +82,7 @@ class PreprocessorLexer;
class PreprocessorOptions;
class ScratchBuffer;
class TargetInfo;
+class NoTrivialPPDirectiveTracer;
namespace Builtin {
class Context;
@@ -353,6 +354,11 @@ private:
/// First pp-token source location in current translation unit.
SourceLocation FirstPPTokenLoc;
+ /// A preprocessor directive tracer to trace whether the preprocessing
+ /// state changed. These changes would mean most semantically observable
+ /// preprocessor state, particularly anything that is order dependent.
+ NoTrivialPPDirectiveTracer *DirTracer = nullptr;
+
/// A position within a C++20 import-seq.
class StdCXXImportSeq {
public:
@@ -609,6 +615,8 @@ private:
return State == NamedModuleImplementation && !getName().contains(':');
}
+ bool isNotAModuleDecl() const { return State == NotAModuleDecl; }
+
StringRef getName() const {
assert(isNamedModule() && "Can't get name from a non named module");
return Name;
@@ -3091,6 +3099,10 @@ public:
bool setDeserializedSafeBufferOptOutMap(
const SmallVectorImpl<SourceLocation> &SrcLocSeqs);
+ /// Whether we've seen pp-directives which may have changed the preprocessing
+ /// state.
+ bool hasSeenNoTrivialPPDirective() const;
+
private:
/// Helper functions to forward lexing to the actual lexer. They all share the
/// same signature.
diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h
index fc43e72..d9dc5a5 100644
--- a/clang/include/clang/Lex/Token.h
+++ b/clang/include/clang/Lex/Token.h
@@ -86,12 +86,12 @@ public:
// macro stringizing or charizing operator.
CommaAfterElided = 0x200, // The comma following this token was elided (MS).
IsEditorPlaceholder = 0x400, // This identifier is a placeholder.
-
- IsReinjected = 0x800, // A phase 4 token that was produced before and
- // re-added, e.g. via EnterTokenStream. Annotation
- // tokens are *not* reinjected.
- FirstPPToken = 0x1000, // This token is the first pp token in the
- // translation unit.
+ IsReinjected = 0x800, // A phase 4 token that was produced before and
+ // re-added, e.g. via EnterTokenStream. Annotation
+ // tokens are *not* reinjected.
+ HasSeenNoTrivialPPDirective =
+ 0x1000, // Whether we've seen any 'no-trivial' pp-directives before
+ // current position.
};
tok::TokenKind getKind() const { return Kind; }
@@ -321,8 +321,9 @@ public:
/// lexer uses identifier tokens to represent placeholders.
bool isEditorPlaceholder() const { return getFlag(IsEditorPlaceholder); }
- /// Returns true if this token is the first pp-token.
- bool isFirstPPToken() const { return getFlag(FirstPPToken); }
+ bool hasSeenNoTrivialPPDirective() const {
+ return getFlag(HasSeenNoTrivialPPDirective);
+ }
};
/// Information about the conditional stack (\#if directives)
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index a49bdfd..c87e6637c 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -236,6 +236,10 @@ private:
RootSignatureToken CurToken;
};
+IdentifierInfo *ParseHLSLRootSignature(Sema &Actions,
+ llvm::dxbc::RootSignatureVersion Version,
+ StringLiteral *Signature);
+
} // namespace hlsl
} // namespace clang
diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h
index 2dd2759..c26f4e3 100644
--- a/clang/include/clang/Sema/CodeCompleteConsumer.h
+++ b/clang/include/clang/Sema/CodeCompleteConsumer.h
@@ -162,7 +162,8 @@ SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T);
/// Determine the type that this declaration will have if it is used
/// as a type or in an expression.
-QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND);
+QualType getDeclUsageType(ASTContext &C, NestedNameSpecifier Qualifier,
+ const NamedDecl *ND);
/// Determine the priority to be given to a macro code completion result
/// with the given name.
@@ -867,7 +868,7 @@ public:
/// If the result should have a nested-name-specifier, this is it.
/// When \c QualifierIsInformative, the nested-name-specifier is
/// informative rather than required.
- NestedNameSpecifier *Qualifier = nullptr;
+ NestedNameSpecifier Qualifier = std::nullopt;
/// If this Decl was unshadowed by using declaration, this can store a
/// pointer to the UsingShadowDecl which was used in the unshadowing process.
@@ -882,7 +883,7 @@ public:
/// Build a result that refers to a declaration.
CodeCompletionResult(const NamedDecl *Declaration, unsigned Priority,
- NestedNameSpecifier *Qualifier = nullptr,
+ NestedNameSpecifier Qualifier = std::nullopt,
bool QualifierIsInformative = false,
bool Accessible = true,
std::vector<FixItHint> FixIts = std::vector<FixItHint>())
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index e568081..c1a99a1 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -91,12 +91,11 @@ public:
}
/// Retrieve the representation of the nested-name-specifier.
- NestedNameSpecifier *getScopeRep() const {
+ NestedNameSpecifier getScopeRep() const {
return Builder.getRepresentation();
}
- /// Extend the current nested-name-specifier by another
- /// nested-name-specifier component of the form 'type::'.
+ /// Make a nested-name-specifier of the form 'type::'.
///
/// \param Context The AST context in which this nested-name-specifier
/// resides.
@@ -106,21 +105,7 @@ public:
/// \param TL The TypeLoc that describes the type preceding the '::'.
///
/// \param ColonColonLoc The location of the trailing '::'.
- void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
-
- /// Extend the current nested-name-specifier by another
- /// nested-name-specifier component of the form 'identifier::'.
- ///
- /// \param Context The AST context in which this nested-name-specifier
- /// resides.
- ///
- /// \param Identifier The identifier.
- ///
- /// \param IdentifierLoc The location of the identifier.
- ///
- /// \param ColonColonLoc The location of the trailing '::'.
- void Extend(ASTContext &Context, IdentifierInfo *Identifier,
- SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
+ void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
/// Extend the current nested-name-specifier by another
/// nested-name-specifier component of the form 'namespace::'.
@@ -154,8 +139,9 @@ public:
/// name.
///
/// \param ColonColonLoc The location of the trailing '::'.
- void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
- SourceLocation SuperLoc, SourceLocation ColonColonLoc);
+ void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD,
+ SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc);
/// Make a new nested-name-specifier from incomplete source-location
/// information.
@@ -163,7 +149,7 @@ public:
/// FIXME: This routine should be used very, very rarely, in cases where we
/// need to synthesize a nested-name-specifier. Most code should instead use
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
- void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
+ void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier,
SourceRange R);
/// Adopt an existing nested-name-specifier (with source-range
@@ -189,14 +175,14 @@ public:
SourceLocation getLastQualifierNameLoc() const;
/// No scope specifier.
- bool isEmpty() const { return Range.isInvalid() && getScopeRep() == nullptr; }
+ bool isEmpty() const { return Range.isInvalid() && !getScopeRep(); }
/// A scope specifier is present, but may be valid or invalid.
bool isNotEmpty() const { return !isEmpty(); }
/// An error occurred during parsing of the scope specifier.
- bool isInvalid() const { return Range.isValid() && getScopeRep() == nullptr; }
+ bool isInvalid() const { return Range.isValid() && !getScopeRep(); }
/// A scope specifier is present, and it refers to a real scope.
- bool isValid() const { return getScopeRep() != nullptr; }
+ bool isValid() const { return bool(getScopeRep()); }
/// Indicate that this nested-name-specifier is invalid.
void SetInvalid(SourceRange R) {
@@ -209,7 +195,7 @@ public:
/// Deprecated. Some call sites intend isNotEmpty() while others intend
/// isValid().
- bool isSet() const { return getScopeRep() != nullptr; }
+ bool isSet() const { return bool(getScopeRep()); }
void clear() {
Range = SourceRange();
diff --git a/clang/include/clang/Sema/HeuristicResolver.h b/clang/include/clang/Sema/HeuristicResolver.h
index e193c0b..71588be 100644
--- a/clang/include/clang/Sema/HeuristicResolver.h
+++ b/clang/include/clang/Sema/HeuristicResolver.h
@@ -67,8 +67,7 @@ public:
// Try to heuristically resolve a dependent nested name specifier
// to the type it likely denotes. Note that *dependent* name specifiers always
// denote types, not namespaces.
- QualType
- resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const;
+ QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS) const;
// Perform an imprecise lookup of a dependent name in `RD`.
// This function does not follow strict semantic rules and should be used
diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h
index 3a8050f..4a3df78 100644
--- a/clang/include/clang/Sema/ParsedTemplate.h
+++ b/clang/include/clang/Sema/ParsedTemplate.h
@@ -48,8 +48,8 @@ namespace clang {
///
/// \param Arg the template type argument or non-type template argument.
/// \param Loc the location of the type.
- ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc)
- : Kind(Kind), Arg(Arg), Loc(Loc) { }
+ ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation NameLoc)
+ : Kind(Kind), Arg(Arg), NameLoc(NameLoc) {}
/// Create a template template argument.
///
@@ -60,11 +60,11 @@ namespace clang {
/// argument refers.
///
/// \param TemplateLoc the location of the template name.
- ParsedTemplateArgument(const CXXScopeSpec &SS,
- ParsedTemplateTy Template,
- SourceLocation TemplateLoc)
- : Kind(ParsedTemplateArgument::Template),
- Arg(Template.getAsOpaquePtr()), SS(SS), Loc(TemplateLoc) {}
+ ParsedTemplateArgument(SourceLocation TemplateKwLoc, const CXXScopeSpec &SS,
+ ParsedTemplateTy Template, SourceLocation NameLoc)
+ : Kind(ParsedTemplateArgument::Template),
+ Arg(Template.getAsOpaquePtr()), SS(SS), TemplateKwLoc(TemplateKwLoc),
+ NameLoc(NameLoc) {}
/// Determine whether the given template argument is invalid.
bool isInvalid() const { return Arg == nullptr; }
@@ -91,7 +91,10 @@ namespace clang {
}
/// Retrieve the location of the template argument.
- SourceLocation getLocation() const { return Loc; }
+ SourceLocation getTemplateKwLoc() const { return TemplateKwLoc; }
+
+ /// Retrieve the location of the template argument.
+ SourceLocation getNameLoc() const { return NameLoc; }
/// Retrieve the nested-name-specifier that precedes the template
/// name in a template template argument.
@@ -128,8 +131,11 @@ namespace clang {
/// argument.
CXXScopeSpec SS;
- /// the location of the template argument.
- SourceLocation Loc;
+ /// the location of the template keyword.
+ SourceLocation TemplateKwLoc;
+
+ /// the location of the template name.
+ SourceLocation NameLoc;
/// The ellipsis location that can accompany a template template
/// argument (turning it into a template template argument expansion).
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 94b247a..4f4d38c 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -933,7 +933,7 @@ public:
/// to local variables that are usable as constant expressions and
/// do not involve an odr-use (they may still need to be captured
/// if the enclosing full-expression is instantiation dependent).
- llvm::SmallSet<Expr *, 8> NonODRUsedCapturingExprs;
+ llvm::SmallPtrSet<Expr *, 8> NonODRUsedCapturingExprs;
/// A map of explicit capture indices to their introducer source ranges.
llvm::DenseMap<unsigned, SourceRange> ExplicitCaptureRanges;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5211373..c3fb57774 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -228,7 +228,9 @@ void threadSafetyCleanup(BeforeSet *Cache);
// FIXME: No way to easily map from TemplateTypeParmTypes to
// TemplateTypeParmDecls, so we have this horrible PointerUnion.
-typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>,
+typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *,
+ const TemplateSpecializationType *,
+ const SubstBuiltinTemplatePackType *>,
SourceLocation>
UnexpandedParameterPack;
@@ -2659,9 +2661,9 @@ public:
/// identifies the magic value.
typedef std::pair<const IdentifierInfo *, uint64_t> TypeTagMagicValue;
- /// Diagnoses the current set of gathered accesses. This typically
- /// happens at full expression level. The set is cleared after emitting the
- /// diagnostics.
+ /// Diagnoses the current set of gathered accesses. This happens at the end of
+ /// each expression evaluation context. Diagnostics are emitted only for
+ /// accesses gathered in the current evaluation context.
void DiagnoseMisalignedMembers();
/// This function checks if the expression is in the sef of potentially
@@ -3117,9 +3119,6 @@ private:
bool operator==(const MisalignedMember &m) { return this->E == m.E; }
};
- /// Small set of gathered accesses to potentially misaligned members
- /// due to the packed attribute.
- SmallVector<MisalignedMember, 4> MisalignedMembers;
/// Adds an expression to the set of gathered misaligned members.
void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD,
@@ -3225,7 +3224,7 @@ public:
/// current instantiation (C++0x [temp.dep.type]p1).
///
/// \param NNS a dependent nested name specifier.
- CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
+ CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier NNS);
/// The parser has parsed a global nested-name-specifier '::'.
///
@@ -3262,7 +3261,7 @@ public:
/// (e.g., Base::), perform name lookup for that identifier as a
/// nested-name-specifier within the given scope, and return the result of
/// that name lookup.
- NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
+ NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier NNS);
/// Keeps information about an identifier in a nested-name-spec.
///
@@ -3581,8 +3580,8 @@ public:
/// Returns the TypeDeclType for the given type declaration,
/// as ASTContext::getTypeDeclType would, but
/// performs the required semantic checks for name lookup of said entity.
- QualType getTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK,
- TypeDecl *TD, SourceLocation NameLoc);
+ void checkTypeDeclType(DeclContext *LookupCtx, DiagCtorKind DCK, TypeDecl *TD,
+ SourceLocation NameLoc);
/// If the identifier refers to a type name within this scope,
/// return the declaration of that type.
@@ -4179,8 +4178,15 @@ public:
/// return statement in the scope of a variable has the same NRVO candidate,
/// that candidate is an NRVO variable.
void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
- Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
- Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
+
+ /// Performs semantic analysis at the end of a function body.
+ ///
+ /// \param RetainFunctionScopeInfo If \c true, the client is responsible for
+ /// releasing the associated \p FunctionScopeInfo. This is useful when
+ /// building e.g. LambdaExprs.
+ Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body,
+ bool IsInstantiation = false,
+ bool RetainFunctionScopeInfo = false);
Decl *ActOnSkippedFunctionBody(Decl *Decl);
void ActOnFinishInlineFunctionDef(FunctionDecl *D);
@@ -5398,7 +5404,7 @@ public:
/// FinalizeVarWithDestructor - Prepare for calling destructor on the
/// constructed variable.
- void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType);
+ void FinalizeVarWithDestructor(VarDecl *VD, CXXRecordDecl *DeclInit);
/// Helper class that collects exception specifications for
/// implicitly-declared special member functions.
@@ -6765,6 +6771,10 @@ public:
/// InLifetimeExtendingContext is true.
SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps;
+ /// Small set of gathered accesses to potentially misaligned members
+ /// due to the packed attribute.
+ SmallVector<MisalignedMember, 4> MisalignedMembers;
+
/// \brief Describes whether we are in an expression constext which we have
/// to handle differently.
enum ExpressionKind {
@@ -6873,23 +6883,23 @@ public:
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back();
- };
+ }
ExpressionEvaluationContextRecord &currentEvaluationContext() {
assert(!ExprEvalContexts.empty() &&
"Must be in an expression evaluation context");
return ExprEvalContexts.back();
- };
+ }
ExpressionEvaluationContextRecord &parentEvaluationContext() {
assert(ExprEvalContexts.size() >= 2 &&
"Must be in an expression evaluation context");
return ExprEvalContexts[ExprEvalContexts.size() - 2];
- };
+ }
const ExpressionEvaluationContextRecord &parentEvaluationContext() const {
return const_cast<Sema *>(this)->parentEvaluationContext();
- };
+ }
bool isAttrContext() const {
return ExprEvalContexts.back().ExprContext ==
@@ -7618,7 +7628,7 @@ public:
/// "real" base class is checked as appropriate when checking the access of
/// the member name.
ExprResult PerformObjectMemberConversion(Expr *From,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifier Qualifier,
NamedDecl *FoundDecl,
NamedDecl *Member);
@@ -8055,8 +8065,8 @@ public:
ExprResult &RHS);
QualType CheckMultiplyDivideOperands( // C99 6.5.5
- ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign,
- bool IsDivide);
+ ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
+ BinaryOperatorKind Opc);
QualType CheckRemainderOperands( // C99 6.5.5
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
bool IsCompAssign = false);
@@ -8065,7 +8075,7 @@ public:
BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
QualType CheckSubtractionOperands( // C99 6.5.6
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
- QualType *CompLHSTy = nullptr);
+ BinaryOperatorKind Opc, QualType *CompLHSTy = nullptr);
QualType CheckShiftOperands( // C99 6.5.7
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
BinaryOperatorKind Opc, bool IsCompAssign = false);
@@ -9139,8 +9149,7 @@ public:
/// Complete a lambda-expression having processed and attached the
/// lambda body.
- ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
- sema::LambdaScopeInfo *LSI);
+ ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc);
/// Get the return type to use for a lambda's conversion function(s) to
/// function pointer type, given the type of the call operator.
@@ -9836,7 +9845,7 @@ public:
SourceLocation ModuleLoc, ModuleDeclKind MDK,
ModuleIdPath Path, ModuleIdPath Partition,
ModuleImportState &ImportState,
- bool IntroducerIsFirstPPToken);
+ bool SeenNoTrivialPPDirective);
/// The parser has processed a global-module-fragment declaration that begins
/// the definition of the global module fragment of the current module unit.
@@ -10210,7 +10219,7 @@ public:
ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj,
FunctionDecl *Fun);
ExprResult PerformImplicitObjectArgumentInitialization(
- Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl,
+ Expr *From, NestedNameSpecifier Qualifier, NamedDecl *FoundDecl,
CXXMethodDecl *Method);
/// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -11618,13 +11627,16 @@ public:
void NoteAllFoundTemplates(TemplateName Name);
- QualType CheckTemplateIdType(TemplateName Template,
+ QualType CheckTemplateIdType(ElaboratedTypeKeyword Keyword,
+ TemplateName Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs);
TypeResult
- ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
- TemplateTy Template, const IdentifierInfo *TemplateII,
+ ActOnTemplateIdType(Scope *S, ElaboratedTypeKeyword ElaboratedKeyword,
+ SourceLocation ElaboratedKeywordLoc, CXXScopeSpec &SS,
+ SourceLocation TemplateKWLoc, TemplateTy Template,
+ const IdentifierInfo *TemplateII,
SourceLocation TemplateIILoc, SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc,
bool IsCtorOrDtorName = false, bool IsClassName = false,
@@ -11858,8 +11870,8 @@ public:
/// argument, substitute into that default template argument and
/// return the corresponding template argument.
TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(
- TemplateDecl *Template, SourceLocation TemplateLoc,
- SourceLocation RAngleLoc, Decl *Param,
+ TemplateDecl *Template, SourceLocation TemplateKWLoc,
+ SourceLocation TemplateNameLoc, SourceLocation RAngleLoc, Decl *Param,
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg);
@@ -13487,8 +13499,6 @@ public:
~ArgPackSubstIndexRAII() { Self.ArgPackSubstIndex = OldSubstIndex; }
};
- friend class ArgumentPackSubstitutionRAII;
-
void pushCodeSynthesisContext(CodeSynthesisContext Ctx);
void popCodeSynthesisContext();
@@ -13762,8 +13772,9 @@ public:
SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo,
const MultiLevelTemplateArgumentList &TemplateArgs);
TemplateName
- SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name,
- SourceLocation Loc,
+ SubstTemplateName(SourceLocation TemplateKWLoc,
+ NestedNameSpecifierLoc &QualifierLoc, TemplateName Name,
+ SourceLocation NameLoc,
const MultiLevelTemplateArgumentList &TemplateArgs);
bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC,
@@ -14417,6 +14428,15 @@ public:
static void collectUnexpandedParameterPacks(
Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded);
+ /// Invoked when parsing a template argument.
+ ///
+ /// \param Arg the template argument, which may already be invalid.
+ ///
+ /// If it is followed by ellipsis, this function is called before
+ /// `ActOnPackExpansion`.
+ ParsedTemplateArgument
+ ActOnTemplateTemplateArgument(const ParsedTemplateArgument &Arg);
+
/// Invoked when parsing a template argument followed by an
/// ellipsis, which creates a pack expansion.
///
@@ -14504,7 +14524,8 @@ public:
bool CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
- const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool FailOnPackProducingTemplates, bool &ShouldExpand,
bool &RetainExpansion, UnsignedOrNone &NumExpansions);
/// Determine the number of arguments in the given pack expansion
@@ -15179,14 +15200,6 @@ public:
return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser);
}
- /// Retrieve a version of the type 'T' that is elaborated by Keyword,
- /// qualified by the nested-name-specifier contained in SS, and that is
- /// (re)declared by OwnedTagDecl, which is nullptr if this is not a
- /// (re)declaration.
- QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
- const CXXScopeSpec &SS, QualType T,
- TagDecl *OwnedTagDecl = nullptr);
-
// Returns the underlying type of a decltype with the given expression.
QualType getDecltypeForExpr(Expr *E);
@@ -15331,6 +15344,16 @@ public:
NamedDecl *Hidden;
return hasVisibleDefinition(const_cast<NamedDecl *>(D), &Hidden);
}
+ /// Determine if \p D has a definition which allows we redefine it in current
+ /// TU. \p Suggested is the definition that should be made visible to expose
+ /// the definition.
+ bool isRedefinitionAllowedFor(NamedDecl *D, NamedDecl **Suggested,
+ bool &Visible);
+ bool isRedefinitionAllowedFor(const NamedDecl *D, bool &Visible) {
+ NamedDecl *Hidden;
+ return isRedefinitionAllowedFor(const_cast<NamedDecl *>(D), &Hidden,
+ Visible);
+ }
/// Determine if \p D has a reachable definition. If not, suggest a
/// declaration that should be made reachable to expose the definition.
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index 085c9ed..5cbe1b6 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -153,6 +153,10 @@ public:
ActOnFinishRootSignatureDecl(SourceLocation Loc, IdentifierInfo *DeclIdent,
ArrayRef<hlsl::RootSignatureElement> Elements);
+ void SetRootSignatureOverride(IdentifierInfo *DeclIdent) {
+ RootSigOverrideIdent = DeclIdent;
+ }
+
// Returns true if any RootSignatureElement is invalid and a diagnostic was
// produced
bool
@@ -221,6 +225,8 @@ private:
uint32_t ImplicitBindingNextOrderID = 0;
+ IdentifierInfo *RootSigOverrideIdent = nullptr;
+
private:
void collectResourceBindingsOnVarDecl(VarDecl *D);
void collectResourceBindingsOnUserRecordDecl(const VarDecl *VD,
@@ -229,10 +235,17 @@ private:
void diagnoseAvailabilityViolations(TranslationUnitDecl *TU);
- bool initGlobalResourceDecl(VarDecl *VD);
uint32_t getNextImplicitBindingOrderID() {
return ImplicitBindingNextOrderID++;
}
+
+ bool initGlobalResourceDecl(VarDecl *VD);
+ bool initGlobalResourceArrayDecl(VarDecl *VD);
+ void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName,
+ HLSLResourceBindingAttr *RBA,
+ HLSLVkBindingAttr *VkBinding,
+ uint32_t ArrayIndex,
+ llvm::SmallVectorImpl<Expr *> &Args);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h
index 42c9469..8f6041b 100644
--- a/clang/include/clang/Sema/SemaInternal.h
+++ b/clang/include/clang/Sema/SemaInternal.h
@@ -71,12 +71,17 @@ inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) {
}
/// Retrieve the depth and index of an unexpanded parameter pack.
-inline std::pair<unsigned, unsigned>
+/// Returns nullopt when the unexpanded packs do not correspond to template
+/// parameters, e.g. __builtin_dedup_types.
+inline std::optional<std::pair<unsigned, unsigned>>
getDepthAndIndex(UnexpandedParameterPack UPP) {
if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first))
return std::make_pair(TTP->getDepth(), TTP->getIndex());
-
- return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
+ if (isa<NamedDecl *>(UPP.first))
+ return getDepthAndIndex(cast<NamedDecl *>(UPP.first));
+ assert((isa<const TemplateSpecializationType *,
+ const SubstBuiltinTemplatePackType *>(UPP.first)));
+ return std::nullopt;
}
class TypoCorrectionConsumer : public VisibleDeclConsumer {
@@ -209,7 +214,7 @@ private:
class NamespaceSpecifierSet {
struct SpecifierInfo {
DeclContext* DeclCtx;
- NestedNameSpecifier* NameSpecifier;
+ NestedNameSpecifier NameSpecifier;
unsigned EditDistance;
};
@@ -229,9 +234,9 @@ private:
static DeclContextList buildContextChain(DeclContext *Start);
unsigned buildNestedNameSpecifier(DeclContextList &DeclChain,
- NestedNameSpecifier *&NNS);
+ NestedNameSpecifier &NNS);
- public:
+ public:
NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext,
CXXScopeSpec *CurScopeSpec);
@@ -276,7 +281,7 @@ private:
};
void addName(StringRef Name, NamedDecl *ND,
- NestedNameSpecifier *NNS = nullptr, bool isKeyword = false);
+ NestedNameSpecifier NNS = std::nullopt, bool isKeyword = false);
/// Find any visible decls for the given typo correction candidate.
/// If none are found, it to the set of candidates for which qualified lookups
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 964749c..42e8658 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -240,7 +240,18 @@ public:
// Creates a VarDecl with a proper default init for the purposes of a
// `private`/'firstprivate'/'reduction' clause, so it can be used to generate
// a recipe later.
- VarDecl *CreateInitRecipe(OpenACCClauseKind CK, const Expr *VarExpr);
+ // The first entry is the recipe itself, the second is any required
+ // 'temporary' created for the init (in the case of a copy), such as with
+ // firstprivate.
+ std::pair<VarDecl *, VarDecl *> CreateInitRecipe(OpenACCClauseKind CK,
+ const Expr *VarExpr) {
+ assert(CK != OpenACCClauseKind::Reduction);
+ return CreateInitRecipe(CK, OpenACCReductionOperator::Invalid, VarExpr);
+ }
+ std::pair<VarDecl *, VarDecl *>
+ CreateInitRecipe(OpenACCClauseKind CK,
+ OpenACCReductionOperator ReductionOperator,
+ const Expr *VarExpr);
public:
ComputeConstructInfo &getActiveComputeConstructInfo() {
@@ -943,12 +954,12 @@ public:
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
// Does the checking for a 'reduction ' clause that needs to be done in
// dependent and not dependent cases.
- OpenACCClause *
- CheckReductionClause(ArrayRef<const OpenACCClause *> ExistingClauses,
- OpenACCDirectiveKind DirectiveKind,
- SourceLocation BeginLoc, SourceLocation LParenLoc,
- OpenACCReductionOperator ReductionOp,
- ArrayRef<Expr *> Vars, SourceLocation EndLoc);
+ OpenACCClause *CheckReductionClause(
+ ArrayRef<const OpenACCClause *> ExistingClauses,
+ OpenACCDirectiveKind DirectiveKind, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, OpenACCReductionOperator ReductionOp,
+ ArrayRef<Expr *> Vars, ArrayRef<OpenACCReductionRecipe> Recipes,
+ SourceLocation EndLoc);
ExprResult BuildOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc);
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index b47b2f15..7ae556d 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -64,6 +64,7 @@ public:
void handleKernelAttr(Decl *D, const ParsedAttr &AL);
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
+ void CheckSYCLExternalFunctionDecl(FunctionDecl *FD);
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body);
};
diff --git a/clang/include/clang/Sema/SemaWasm.h b/clang/include/clang/Sema/SemaWasm.h
index 8c0639f..f825907 100644
--- a/clang/include/clang/Sema/SemaWasm.h
+++ b/clang/include/clang/Sema/SemaWasm.h
@@ -37,7 +37,8 @@ public:
bool BuiltinWasmTableGrow(CallExpr *TheCall);
bool BuiltinWasmTableFill(CallExpr *TheCall);
bool BuiltinWasmTableCopy(CallExpr *TheCall);
- bool BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall);
+ bool BuiltinWasmTestFunctionPointerSignature(const TargetInfo &TI,
+ CallExpr *TheCall);
WebAssemblyImportNameAttr *
mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL);
diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h
index 09de164..1d780c4 100644
--- a/clang/include/clang/Sema/TypoCorrection.h
+++ b/clang/include/clang/Sema/TypoCorrection.h
@@ -57,15 +57,15 @@ public:
static const unsigned CallbackDistanceWeight = 150U;
TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl,
- NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0,
- unsigned QualifierDistance = 0)
+ NestedNameSpecifier NNS = std::nullopt,
+ unsigned CharDistance = 0, unsigned QualifierDistance = 0)
: CorrectionName(Name), CorrectionNameSpec(NNS),
CharDistance(CharDistance), QualifierDistance(QualifierDistance) {
if (NameDecl)
CorrectionDecls.push_back(NameDecl);
}
- TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr,
+ TypoCorrection(NamedDecl *Name, NestedNameSpecifier NNS = std::nullopt,
unsigned CharDistance = 0)
: CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS),
CharDistance(CharDistance) {
@@ -73,7 +73,7 @@ public:
CorrectionDecls.push_back(Name);
}
- TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr,
+ TypoCorrection(DeclarationName Name, NestedNameSpecifier NNS = std::nullopt,
unsigned CharDistance = 0)
: CorrectionName(Name), CorrectionNameSpec(NNS),
CharDistance(CharDistance) {}
@@ -88,13 +88,13 @@ public:
}
/// Gets the NestedNameSpecifier needed to use the typo correction
- NestedNameSpecifier *getCorrectionSpecifier() const {
+ NestedNameSpecifier getCorrectionSpecifier() const {
return CorrectionNameSpec;
}
- void setCorrectionSpecifier(NestedNameSpecifier *NNS) {
+ void setCorrectionSpecifier(NestedNameSpecifier NNS) {
CorrectionNameSpec = NNS;
- ForceSpecifierReplacement = (NNS != nullptr);
+ ForceSpecifierReplacement = !!NNS;
}
void WillReplaceSpecifier(bool ForceReplacement) {
@@ -264,7 +264,7 @@ private:
// Results.
DeclarationName CorrectionName;
- NestedNameSpecifier *CorrectionNameSpec = nullptr;
+ NestedNameSpecifier CorrectionNameSpec = std::nullopt;
SmallVector<NamedDecl *, 1> CorrectionDecls;
unsigned CharDistance = 0;
unsigned QualifierDistance = 0;
@@ -282,8 +282,9 @@ class CorrectionCandidateCallback {
public:
static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
- explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr,
- NestedNameSpecifier *TypoNNS = nullptr)
+ explicit CorrectionCandidateCallback(
+ const IdentifierInfo *Typo = nullptr,
+ NestedNameSpecifier TypoNNS = std::nullopt)
: Typo(Typo), TypoNNS(TypoNNS) {}
virtual ~CorrectionCandidateCallback() = default;
@@ -320,7 +321,7 @@ public:
virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
void setTypoName(const IdentifierInfo *II) { Typo = II; }
- void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
+ void setTypoNNS(NestedNameSpecifier NNS) { TypoNNS = NNS; }
// Flags for context-dependent keywords. WantFunctionLikeCasts is only
// used/meaningful when WantCXXNamedCasts is false.
@@ -346,13 +347,13 @@ protected:
}
const IdentifierInfo *Typo;
- NestedNameSpecifier *TypoNNS;
+ NestedNameSpecifier TypoNNS;
};
class DefaultFilterCCC final : public CorrectionCandidateCallback {
public:
explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
- NestedNameSpecifier *TypoNNS = nullptr)
+ NestedNameSpecifier TypoNNS = std::nullopt)
: CorrectionCandidateCallback(Typo, TypoNNS) {}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
@@ -366,7 +367,7 @@ template <class C>
class DeclFilterCCC final : public CorrectionCandidateCallback {
public:
explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
- NestedNameSpecifier *TypoNNS = nullptr)
+ NestedNameSpecifier TypoNNS = std::nullopt)
: CorrectionCandidateCallback(Typo, TypoNNS) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 7ce626c..3ede092 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -526,6 +526,9 @@ private:
/// A timer used to track the time spent deserializing.
std::unique_ptr<llvm::Timer> ReadTimer;
+ // A TimeRegion used to start and stop ReadTimer via RAII.
+ std::optional<llvm::TimeRegion> ReadTimeRegion;
+
/// The location where the module file will be considered as
/// imported from. For non-module AST types it should be invalid.
SourceLocation CurrentImportLoc;
diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h
index 1472497..aed1b7d 100644
--- a/clang/include/clang/Serialization/ASTRecordReader.h
+++ b/clang/include/clang/Serialization/ASTRecordReader.h
@@ -223,7 +223,7 @@ public:
void readQualifierInfo(QualifierInfo &Info);
/// Return a nested name specifier, advancing Idx.
- // NestedNameSpecifier *readNestedNameSpecifier(); (inherited)
+ // NestedNameSpecifier readNestedNameSpecifier(); (inherited)
NestedNameSpecifierLoc readNestedNameSpecifierLoc();
diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h
index ee005ec..9849ea6 100644
--- a/clang/include/clang/Serialization/ASTRecordWriter.h
+++ b/clang/include/clang/Serialization/ASTRecordWriter.h
@@ -247,8 +247,7 @@ public:
void AddTypeLoc(TypeLoc TL);
/// Emits a template argument location info.
- void AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind,
- const TemplateArgumentLocInfo &Arg);
+ void AddTemplateArgumentLocInfo(const TemplateArgumentLoc &Arg);
/// Emits a template argument location.
void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg);
@@ -280,7 +279,7 @@ public:
void AddQualifierInfo(const QualifierInfo &Info);
/// Emit a nested name specifier.
- void AddNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ void AddNestedNameSpecifier(NestedNameSpecifier NNS) {
writeNestedNameSpecifier(NNS);
}
diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def
index 613eb6a..bea1525 100644
--- a/clang/include/clang/Serialization/TypeBitCodes.def
+++ b/clang/include/clang/Serialization/TypeBitCodes.def
@@ -32,7 +32,6 @@ TYPE_BIT_CODE(Enum, ENUM, 20)
TYPE_BIT_CODE(ObjCInterface, OBJC_INTERFACE, 21)
TYPE_BIT_CODE(ObjCObjectPointer, OBJC_OBJECT_POINTER, 22)
TYPE_BIT_CODE(Decltype, DECLTYPE, 23)
-TYPE_BIT_CODE(Elaborated, ELABORATED, 24)
TYPE_BIT_CODE(SubstTemplateTypeParm, SUBST_TEMPLATE_TYPE_PARM, 25)
TYPE_BIT_CODE(UnresolvedUsing, UNRESOLVED_USING, 26)
TYPE_BIT_CODE(InjectedClassName, INJECTED_CLASS_NAME, 27)
@@ -70,5 +69,6 @@ TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58)
TYPE_BIT_CODE(HLSLAttributedResource, HLSLRESOURCE_ATTRIBUTED, 59)
TYPE_BIT_CODE(HLSLInlineSpirv, HLSL_INLINE_SPIRV, 60)
TYPE_BIT_CODE(PredefinedSugar, PREDEFINED_SUGAR, 61)
+TYPE_BIT_CODE(SubstBuiltinTemplatePack, SUBST_BUILTIN_TEMPLATE_PACK, 62)
#undef TYPE_BIT_CODE
diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 8696fce..f6a0233 100644
--- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -320,7 +320,7 @@ protected:
/// A set of location contexts that correspoind to call sites which should be
/// considered "interesting".
- llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
+ llvm::SmallPtrSet<const LocationContext *, 2> InterestingLocationContexts;
/// A set of custom visitors which generate "event" diagnostics at
/// interesting points in the path.
@@ -348,7 +348,7 @@ protected:
llvm::SmallSet<InvalidationRecord, 4> Invalidations;
/// Conditions we're already tracking.
- llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
+ llvm::SmallPtrSet<const ExplodedNode *, 4> TrackedConditions;
/// Reports with different uniqueing locations are considered to be different
/// for the purposes of deduplication.
@@ -623,10 +623,12 @@ public:
ASTContext &getContext() { return D.getASTContext(); }
const SourceManager &getSourceManager() { return D.getSourceManager(); }
+ const SourceManager &getSourceManager() const { return D.getSourceManager(); }
const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
Preprocessor &getPreprocessor() { return D.getPreprocessor(); }
+ const Preprocessor &getPreprocessor() const { return D.getPreprocessor(); }
/// Get the top-level entry point for the issue to be reported.
const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; }
diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h
index 31cc095c..d9a7c00 100644
--- a/clang/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h
@@ -209,8 +209,8 @@ public:
class Bind {
template <typename CHECKER>
static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S,
- CheckerContext &C) {
- ((const CHECKER *)checker)->checkBind(location, val, S, C);
+ bool AtDeclInit, CheckerContext &C) {
+ ((const CHECKER *)checker)->checkBind(location, val, S, AtDeclInit, C);
}
public:
diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
index c8e6f12..bf33ce6 100644
--- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -338,10 +338,9 @@ public:
ExprEngine &Eng);
/// Run checkers for binding of a value to a location.
- void runCheckersForBind(ExplodedNodeSet &Dst,
- const ExplodedNodeSet &Src,
- SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng,
+ void runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+ SVal location, SVal val, const Stmt *S,
+ bool AtDeclInit, ExprEngine &Eng,
const ProgramPoint &PP);
/// Run checkers after taking a control flow edge.
@@ -499,8 +498,8 @@ public:
using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad,
const Stmt *S, CheckerContext &)>;
- using CheckBindFunc =
- CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;
+ using CheckBindFunc = CheckerFn<void(SVal location, SVal val, const Stmt *S,
+ bool AtDeclInit, CheckerContext &)>;
using CheckBlockEntranceFunc =
CheckerFn<void(const BlockEntrance &, CheckerContext &)>;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index f20b003..cf035a9 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -58,25 +58,34 @@ public:
AnalysisManager &getAnalysisManager() {
return Eng.getAnalysisManager();
}
+ const AnalysisManager &getAnalysisManager() const {
+ return Eng.getAnalysisManager();
+ }
ConstraintManager &getConstraintManager() {
return Eng.getConstraintManager();
}
+ const ConstraintManager &getConstraintManager() const {
+ return Eng.getConstraintManager();
+ }
StoreManager &getStoreManager() {
return Eng.getStoreManager();
}
+ const StoreManager &getStoreManager() const { return Eng.getStoreManager(); }
/// Returns the previous node in the exploded graph, which includes
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
ExplodedNode *getPredecessor() { return Pred; }
+ const ExplodedNode *getPredecessor() const { return Pred; }
const ProgramPoint getLocation() const { return Location; }
const ProgramStateRef &getState() const { return Pred->getState(); }
/// Check if the checker changed the state of the execution; ex: added
/// a new transition or a bug report.
bool isDifferent() { return Changed; }
+ bool isDifferent() const { return Changed; }
/// Returns the number of times the current block has been visited
/// along the analyzed path.
@@ -108,24 +117,38 @@ public:
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
+ const BugReporter &getBugReporter() const { return Eng.getBugReporter(); }
const SourceManager &getSourceManager() {
return getBugReporter().getSourceManager();
}
+ const SourceManager &getSourceManager() const {
+ return getBugReporter().getSourceManager();
+ }
Preprocessor &getPreprocessor() { return getBugReporter().getPreprocessor(); }
+ const Preprocessor &getPreprocessor() const {
+ return getBugReporter().getPreprocessor();
+ }
SValBuilder &getSValBuilder() {
return Eng.getSValBuilder();
}
+ const SValBuilder &getSValBuilder() const { return Eng.getSValBuilder(); }
SymbolManager &getSymbolManager() {
return getSValBuilder().getSymbolManager();
}
+ const SymbolManager &getSymbolManager() const {
+ return getSValBuilder().getSymbolManager();
+ }
ProgramStateManager &getStateManager() {
return Eng.getStateManager();
}
+ const ProgramStateManager &getStateManager() const {
+ return Eng.getStateManager();
+ }
AnalysisDeclContext *getCurrentAnalysisDeclContext() const {
return Pred->getLocationContext()->getAnalysisDeclContext();
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index fbb3434..d184986cd 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,7 @@ public:
ASTContext &getContext() const { return AMgr.getASTContext(); }
AnalysisManager &getAnalysisManager() { return AMgr; }
+ const AnalysisManager &getAnalysisManager() const { return AMgr; }
AnalysisDeclContextManager &getAnalysisDeclContextManager() {
return AMgr.getAnalysisDeclContextManager();
@@ -206,8 +207,10 @@ public:
}
SValBuilder &getSValBuilder() { return svalBuilder; }
+ const SValBuilder &getSValBuilder() const { return svalBuilder; }
BugReporter &getBugReporter() { return BR; }
+ const BugReporter &getBugReporter() const { return BR; }
cross_tu::CrossTranslationUnitContext *
getCrossTranslationUnitContext() {
@@ -416,12 +419,19 @@ public:
unsigned int Space, bool IsDot) const;
ProgramStateManager &getStateManager() { return StateMgr; }
+ const ProgramStateManager &getStateManager() const { return StateMgr; }
StoreManager &getStoreManager() { return StateMgr.getStoreManager(); }
+ const StoreManager &getStoreManager() const {
+ return StateMgr.getStoreManager();
+ }
ConstraintManager &getConstraintManager() {
return StateMgr.getConstraintManager();
}
+ const ConstraintManager &getConstraintManager() const {
+ return StateMgr.getConstraintManager();
+ }
// FIXME: Remove when we migrate over to just using SValBuilder.
BasicValueFactory &getBasicVals() {
@@ -429,6 +439,7 @@ public:
}
SymbolManager &getSymbolManager() { return SymMgr; }
+ const SymbolManager &getSymbolManager() const { return SymMgr; }
MemRegionManager &getRegionManager() { return MRMgr; }
DataTag::Factory &getDataTags() { return Engine.getDataTags(); }
@@ -660,7 +671,7 @@ private:
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit = false,
+ SVal location, SVal Val, bool AtDeclInit = false,
const ProgramPoint *PP = nullptr);
ProgramStateRef
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 5271453..12487a3 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -572,7 +572,11 @@ public:
CallEventManager &getCallEventManager() { return *CallEventMgr; }
StoreManager &getStoreManager() { return *StoreMgr; }
+ const StoreManager &getStoreManager() const { return *StoreMgr; }
ConstraintManager &getConstraintManager() { return *ConstraintMgr; }
+ const ConstraintManager &getConstraintManager() const {
+ return *ConstraintMgr;
+ }
ExprEngine &getOwningEngine() { return *Eng; }
ProgramStateRef
diff --git a/clang/include/clang/Tooling/Refactoring/Lookup.h b/clang/include/clang/Tooling/Refactoring/Lookup.h
index dcb40b7e..fe0df86 100644
--- a/clang/include/clang/Tooling/Refactoring/Lookup.h
+++ b/clang/include/clang/Tooling/Refactoring/Lookup.h
@@ -38,8 +38,7 @@ namespace tooling {
/// \param ReplacementString The replacement nested name. Must be fully
/// qualified including a leading "::".
/// \returns The new name to be inserted in place of the current nested name.
-std::string replaceNestedName(const NestedNameSpecifier *Use,
- SourceLocation UseLoc,
+std::string replaceNestedName(NestedNameSpecifier Use, SourceLocation UseLoc,
const DeclContext *UseContext,
const NamedDecl *FromDecl,
StringRef ReplacementString);
diff --git a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
index 271232e..319569f 100644
--- a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
+++ b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
@@ -108,19 +108,21 @@ public:
bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
const SourceLocation TypeEndLoc =
Lexer::getLocForEndOfToken(TL.getBeginLoc(), 0, SM, LangOpts);
- return visit(TL.getTypedefNameDecl(), TL.getBeginLoc(), TypeEndLoc);
+ return visit(TL.getDecl(), TL.getBeginLoc(), TypeEndLoc);
}
- bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) {
// The base visitor will visit NNSL prefixes, so we should only look at
// the current NNS.
- if (NNS) {
- const auto *ND = dyn_cast_if_present<NamespaceDecl>(
- NNS.getNestedNameSpecifier()->getAsNamespace());
- if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc()))
+ if (NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier();
+ Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) {
+ const auto *ND = dyn_cast<NamespaceDecl>(
+ Qualifier.getAsNamespaceAndPrefix().Namespace);
+ if (!visit(ND, QualifierLoc.getLocalBeginLoc(),
+ QualifierLoc.getLocalEndLoc()))
return false;
}
- return BaseType::TraverseNestedNameSpecifierLoc(NNS);
+ return BaseType::TraverseNestedNameSpecifierLoc(QualifierLoc);
}
bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
diff --git a/clang/include/module.modulemap b/clang/include/module.modulemap
index 42ee34f..c553526 100644
--- a/clang/include/module.modulemap
+++ b/clang/include/module.modulemap
@@ -37,6 +37,7 @@ module Clang_Basic {
umbrella "clang/Basic"
textual header "clang/Basic/AArch64ACLETypes.def"
+ textual header "clang/Basic/ABIVersions.def"
textual header "clang/Basic/AMDGPUTypes.def"
textual header "clang/Basic/BuiltinHeaders.def"
textual header "clang/Basic/BuiltinsAArch64.def"