Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

600 lines
19 KiB
C++
Raw Normal View History

//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "clang/AST/NSAPI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/StringSwitch.h"
#include <optional>
using namespace clang;
NSAPI::NSAPI(ASTContext &ctx)
: Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
NSUTF8StringEncodingId(nullptr) {}
IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
static const char *ClassName[NumClassIds] = {
"NSObject",
"NSString",
"NSArray",
"NSMutableArray",
"NSDictionary",
"NSMutableDictionary",
"NSNumber",
"NSMutableSet",
"NSMutableOrderedSet",
"NSValue"
};
if (!ClassIds[K])
return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
return ClassIds[K];
}
Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
if (NSStringSelectors[MK].isNull()) {
Selector Sel;
switch (MK) {
case NSStr_stringWithString:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
break;
case NSStr_stringWithUTF8String:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("stringWithUTF8String"));
break;
case NSStr_initWithUTF8String:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithUTF8String"));
break;
case NSStr_stringWithCStringEncoding: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"),
&Ctx.Idents.get("encoding")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSStr_stringWithCString:
Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
break;
case NSStr_initWithString:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
break;
}
return (NSStringSelectors[MK] = Sel);
}
return NSStringSelectors[MK];
}
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
if (NSArraySelectors[MK].isNull()) {
Selector Sel;
switch (MK) {
case NSArr_array:
Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
break;
case NSArr_arrayWithArray:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
break;
case NSArr_arrayWithObject:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
break;
case NSArr_arrayWithObjects:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
break;
case NSArr_arrayWithObjectsCount: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"),
&Ctx.Idents.get("count")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSArr_initWithArray:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
break;
case NSArr_initWithObjects:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
break;
case NSArr_objectAtIndex:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
break;
case NSMutableArr_replaceObjectAtIndex: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableArr_addObject:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
break;
case NSMutableArr_insertObjectAtIndex: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableArr_setObjectAtIndexedSubscript: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
}
return (NSArraySelectors[MK] = Sel);
}
return NSArraySelectors[MK];
}
std::optional<NSAPI::NSArrayMethodKind>
NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
return std::nullopt;
}
Selector NSAPI::getNSDictionarySelector(
NSDictionaryMethodKind MK) const {
if (NSDictionarySelectors[MK].isNull()) {
Selector Sel;
switch (MK) {
case NSDict_dictionary:
Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
break;
case NSDict_dictionaryWithDictionary:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("dictionaryWithDictionary"));
break;
case NSDict_dictionaryWithObjectForKey: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_dictionaryWithObjectsForKeys: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_dictionaryWithObjectsForKeysCount: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"),
&Ctx.Idents.get("count")};
Sel = Ctx.Selectors.getSelector(3, KeyIdents);
break;
}
case NSDict_dictionaryWithObjectsAndKeys:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
break;
case NSDict_initWithDictionary:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithDictionary"));
break;
case NSDict_initWithObjectsAndKeys:
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
case NSDict_initWithObjectsForKeys: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"),
&Ctx.Idents.get("forKeys")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
case NSMutableDict_setObjectForKey: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableDict_setObjectForKeyedSubscript: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSMutableDict_setValueForKey: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"),
&Ctx.Idents.get("forKey")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
}
return (NSDictionarySelectors[MK] = Sel);
}
return NSDictionarySelectors[MK];
}
std::optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
if (Sel == getNSDictionarySelector(MK))
return MK;
}
return std::nullopt;
}
Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
if (NSSetSelectors[MK].isNull()) {
Selector Sel;
switch (MK) {
case NSMutableSet_addObject:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
break;
case NSOrderedSet_insertObjectAtIndex: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_setObjectAtIndex: {
const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
&Ctx.Idents.get("atIndex")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_setObjectAtIndexedSubscript: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
case NSOrderedSet_replaceObjectAtIndexWithObject: {
const IdentifierInfo *KeyIdents[] = {
&Ctx.Idents.get("replaceObjectAtIndex"),
&Ctx.Idents.get("withObject")};
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
break;
}
}
return (NSSetSelectors[MK] = Sel);
}
return NSSetSelectors[MK];
}
std::optional<NSAPI::NSSetMethodKind> NSAPI::getNSSetMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSSetMethods; ++i) {
NSSetMethodKind MK = NSSetMethodKind(i);
if (Sel == getNSSetSelector(MK))
return MK;
}
return std::nullopt;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
bool Instance) const {
static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
"numberWithChar",
"numberWithUnsignedChar",
"numberWithShort",
"numberWithUnsignedShort",
"numberWithInt",
"numberWithUnsignedInt",
"numberWithLong",
"numberWithUnsignedLong",
"numberWithLongLong",
"numberWithUnsignedLongLong",
"numberWithFloat",
"numberWithDouble",
"numberWithBool",
"numberWithInteger",
"numberWithUnsignedInteger"
};
static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
"initWithChar",
"initWithUnsignedChar",
"initWithShort",
"initWithUnsignedShort",
"initWithInt",
"initWithUnsignedInt",
"initWithLong",
"initWithUnsignedLong",
"initWithLongLong",
"initWithUnsignedLongLong",
"initWithFloat",
"initWithDouble",
"initWithBool",
"initWithInteger",
"initWithUnsignedInteger"
};
Selector *Sels;
const char **Names;
if (Instance) {
Sels = NSNumberInstanceSelectors;
Names = InstanceSelectorName;
} else {
Sels = NSNumberClassSelectors;
Names = ClassSelectorName;
}
if (Sels[MK].isNull())
Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
return Sels[MK];
}
std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
if (isNSNumberLiteralSelector(MK, Sel))
return MK;
}
return std::nullopt;
}
std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
return std::nullopt;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
QualType TDTTy = QualType(TDT, 0);
if (isObjCBOOLType(TDTTy))
return NSAPI::NSNumberWithBool;
if (isObjCNSIntegerType(TDTTy))
return NSAPI::NSNumberWithInteger;
if (isObjCNSUIntegerType(TDTTy))
return NSAPI::NSNumberWithUnsignedInteger;
}
switch (BT->getKind()) {
case BuiltinType::Char_S:
case BuiltinType::SChar:
return NSAPI::NSNumberWithChar;
case BuiltinType::Char_U:
case BuiltinType::UChar:
return NSAPI::NSNumberWithUnsignedChar;
case BuiltinType::Short:
return NSAPI::NSNumberWithShort;
case BuiltinType::UShort:
return NSAPI::NSNumberWithUnsignedShort;
case BuiltinType::Int:
return NSAPI::NSNumberWithInt;
case BuiltinType::UInt:
return NSAPI::NSNumberWithUnsignedInt;
case BuiltinType::Long:
return NSAPI::NSNumberWithLong;
case BuiltinType::ULong:
return NSAPI::NSNumberWithUnsignedLong;
case BuiltinType::LongLong:
return NSAPI::NSNumberWithLongLong;
case BuiltinType::ULongLong:
return NSAPI::NSNumberWithUnsignedLongLong;
case BuiltinType::Float:
return NSAPI::NSNumberWithFloat;
case BuiltinType::Double:
return NSAPI::NSNumberWithDouble;
case BuiltinType::Bool:
return NSAPI::NSNumberWithBool;
case BuiltinType::Void:
case BuiltinType::WChar_U:
case BuiltinType::WChar_S:
case BuiltinType::Char8:
case BuiltinType::Char16:
case BuiltinType::Char32:
case BuiltinType::Int128:
case BuiltinType::LongDouble:
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
case BuiltinType::UShortAccum:
case BuiltinType::UAccum:
case BuiltinType::ULongAccum:
[Fixed Point Arithmetic] Addition of the remaining fixed point types and their saturated equivalents This diff includes changes for the remaining _Fract and _Sat fixed point types. ``` signed short _Fract s_short_fract; signed _Fract s_fract; signed long _Fract s_long_fract; unsigned short _Fract u_short_fract; unsigned _Fract u_fract; unsigned long _Fract u_long_fract; // Aliased fixed point types short _Accum short_accum; _Accum accum; long _Accum long_accum; short _Fract short_fract; _Fract fract; long _Fract long_fract; // Saturated fixed point types _Sat signed short _Accum sat_s_short_accum; _Sat signed _Accum sat_s_accum; _Sat signed long _Accum sat_s_long_accum; _Sat unsigned short _Accum sat_u_short_accum; _Sat unsigned _Accum sat_u_accum; _Sat unsigned long _Accum sat_u_long_accum; _Sat signed short _Fract sat_s_short_fract; _Sat signed _Fract sat_s_fract; _Sat signed long _Fract sat_s_long_fract; _Sat unsigned short _Fract sat_u_short_fract; _Sat unsigned _Fract sat_u_fract; _Sat unsigned long _Fract sat_u_long_fract; // Aliased saturated fixed point types _Sat short _Accum sat_short_accum; _Sat _Accum sat_accum; _Sat long _Accum sat_long_accum; _Sat short _Fract sat_short_fract; _Sat _Fract sat_fract; _Sat long _Fract sat_long_fract; ``` This diff only allows for declaration of these fixed point types. Assignment and other operations done on fixed point types according to http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf will be added in future patches. Differential Revision: https://reviews.llvm.org/D46911 llvm-svn: 334718
2018-06-14 14:53:51 +00:00
case BuiltinType::ShortFract:
case BuiltinType::Fract:
case BuiltinType::LongFract:
case BuiltinType::UShortFract:
case BuiltinType::UFract:
case BuiltinType::ULongFract:
case BuiltinType::SatShortAccum:
case BuiltinType::SatAccum:
case BuiltinType::SatLongAccum:
case BuiltinType::SatUShortAccum:
case BuiltinType::SatUAccum:
case BuiltinType::SatULongAccum:
case BuiltinType::SatShortFract:
case BuiltinType::SatFract:
case BuiltinType::SatLongFract:
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
case BuiltinType::UInt128:
case BuiltinType::Float16:
case BuiltinType::Float128:
case BuiltinType::Ibm128:
case BuiltinType::NullPtr:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCId:
case BuiltinType::ObjCSel:
[OpenCL] Complete image types support. I. Current implementation of images is not conformant to spec in the following points: 1. It makes no distinction with respect to access qualifiers and therefore allows to use images with different access type interchangeably. The following code would compile just fine: void write_image(write_only image2d_t img); kernel void foo(read_only image2d_t img) { write_image(img); } // Accepted code which is disallowed according to s6.13.14. 2. It discards access qualifier on generated code, which leads to generated code for the above example: call void @write_image(%opencl.image2d_t* %img); In OpenCL2.0 however we can have different calls into write_image with read_only and wite_only images. Also generally following compiler steps have no easy way to take different path depending on the image access: linking to the right implementation of image types, performing IR opts and backend codegen differently. 3. Image types are language keywords and can't be redeclared s6.1.9, which can happen currently as they are just typedef names. 4. Default access qualifier read_only is to be added if not provided explicitly. II. This patch corrects the above points as follows: 1. All images are encapsulated into a separate .def file that is inserted in different points where image handling is required. This avoid a lot of code repetition as all images are handled the same way in the code with no distinction of their exact type. 2. The Cartesian product of image types and image access qualifiers is added to the builtin types. This simplifies a lot handling of access type mismatch as no operations are allowed by default on distinct Builtin types. Also spec intended access qualifier as special type qualifier that are combined with an image type to form a distinct type (see statement above - images can't be created w/o access qualifiers). 3. Improves testing of images in Clang. Author: Anastasia Stulova Reviewers: bader, mgrang. Subscribers: pxli168, pekka.jaaskelainen, yaxunl. Differential Revision: http://reviews.llvm.org/D17821 llvm-svn: 265783
2016-04-08 13:40:33 +00:00
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
Add SVE opaque built-in types This patch adds the SVE built-in types defined by the Procedure Call Standard for the Arm Architecture: https://developer.arm.com/docs/100986/0000 It handles the types in all relevant places that deal with built-in types. At the moment, some of these places bail out with an error, including: (1) trying to generate LLVM IR for the types (2) trying to generate debug info for the types (3) trying to mangle the types using the Microsoft C++ ABI (4) trying to @encode the types in Objective C (1) and (2) are fixed by follow-on patches but (unlike this patch) they deal mostly with target-specific LLVM details, so seemed like a logically separate change. There is currently no spec for (3) and (4), so reporting an error seems like the correct behaviour for now. The intention is that the types will become sizeless types: http://lists.llvm.org/pipermail/cfe-dev/2019-June/062523.html The main purpose of the sizeless type extension is to diagnose impossible or dangerous uses of the types, such as any that would require sizeof to have a meaningful defined value. Until then, the patch sets the alignments of the types to the values specified in the link above. It also sets the sizes of the types to zero, which is chosen to be consistently wrong and shouldn't affect correctly-written code (i.e. code that would compile even with the sizeless type extension). The patch adds the common subset of functionality needed to test the sizeless type extension on the one hand and to provide SVE intrinsic functions on the other. After this patch, the two pieces of work are essentially independent. The patch is based on one by Graham Hunter: https://reviews.llvm.org/D59245 Differential Revision: https://reviews.llvm.org/D62960 llvm-svn: 368413
2019-08-09 08:52:54 +00:00
#define SVE_TYPE(Name, Id, SingletonId) \
case BuiltinType::Id:
#include "clang/Basic/AArch64SVEACLETypes.def"
#define PPC_VECTOR_TYPE(Name, Id, Size) \
case BuiltinType::Id:
#include "clang/Basic/PPCTypes.def"
#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/RISCVVTypes.def"
#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/WebAssemblyReferenceTypes.def"
#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
#include "clang/Basic/AMDGPUTypes.def"
[HLSL] Implement intangible AST type (#97362) HLSL has a set of intangible types which are described in in the [draft HLSL Specification (**[Basic.types]**)](https://microsoft.github.io/hlsl-specs/specs/hlsl.pdf): There are special implementation-defined types such as handle types, which fall into a category of standard intangible types. Intangible types are types that have no defined object representation or value representation, as such the size is unknown at compile time. A class type T is an intangible class type if it contains an base classes or members of intangible class type, standard intangible type, or arrays of such types. Standard intangible types and intangible class types are collectively called intangible types([9](https://microsoft.github.io/hlsl-specs/specs/hlsl.html#Intangible)). This PR implements one standard intangible type `__hlsl_resource_t` and sets up the infrastructure that will make it easier to add more in the future, such as samplers or raytracing payload handles. The HLSL intangible types are declared in `clang/include/clang/Basic/HLSLIntangibleTypes.def` and this file is included with related macro definition in most places that require edits when a new type is added. The new types are added as keywords and not typedefs to make sure they cannot be redeclared, and they can only be declared in builtin implicit headers. The `__hlsl_resource_t` type represents a handle to a memory resource and it is going to be used in builtin HLSL buffer types like this: template <typename T> class RWBuffer { [[hlsl::contained_type(T)]] [[hlsl::is_rov(false)]] [[hlsl::resource_class(uav)]] __hlsl_resource_t Handle; }; Part 1/3 of llvm/llvm-project#90631. --------- Co-authored-by: Justin Bogner <mail@justinbogner.com>
2024-08-05 10:50:34 -07:00
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/HLSLIntangibleTypes.def"
case BuiltinType::BoundMember:
[clang] Distinguish unresolved templates in UnresolvedLookupExpr (#89019) This patch revolves around the misuse of UnresolvedLookupExpr in BuildTemplateIdExpr. Basically, we build up an UnresolvedLookupExpr not only for function overloads but for "unresolved" templates wherever we need an expression for template decls. For example, a dependent VarTemplateDecl can be wrapped with such an expression before template instantiation. (See https://github.com/llvm/llvm-project/commit/617007240cbfb97c8ccf6d61b0c4ca0bb62d43c9) Also, one important thing is that UnresolvedLookupExpr uses a "canonical" QualType to describe the containing unresolved decls: a DependentTy is for dependent expressions and an OverloadTy otherwise. Therefore, this modeling for non-dependent templates leaves a problem in that the expression is marked and perceived as if describing overload functions. The consumer then expects functions for every such expression, although the fact is the reverse. Hence, we run into crashes. As to the patch, I added a new canonical type "UnresolvedTemplateTy" to model these cases. Given that we have been using this model (intentionally or accidentally) and it is pretty baked in throughout the code, I think extending the role of UnresolvedLookupExpr is reasonable. Further, I added some diagnostics for the direct occurrence of these expressions, which are supposed to be ill-formed. As a bonus, this patch also fixes some typos in the diagnostics and creates RecoveryExprs rather than nothing in the hope of a better error-recovery for clangd. Fixes https://github.com/llvm/llvm-project/issues/88832 Fixes https://github.com/llvm/llvm-project/issues/63243 Fixes https://github.com/llvm/llvm-project/issues/48673
2024-05-05 11:38:49 +08:00
case BuiltinType::UnresolvedTemplate:
case BuiltinType::Dependent:
case BuiltinType::Overload:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
case BuiltinType::Half:
case BuiltinType::PseudoObject:
case BuiltinType::BuiltinFn:
case BuiltinType::IncompleteMatrixIdx:
case BuiltinType::ArraySection:
case BuiltinType::OMPArrayShaping:
case BuiltinType::OMPIterator:
case BuiltinType::BFloat16:
break;
}
return std::nullopt;
}
/// Returns true if \param T is a typedef of "BOOL" in objective-c.
bool NSAPI::isObjCBOOLType(QualType T) const {
return isObjCTypedef(T, "BOOL", BOOLId);
}
/// Returns true if \param T is a typedef of "NSInteger" in objective-c.
bool NSAPI::isObjCNSIntegerType(QualType T) const {
return isObjCTypedef(T, "NSInteger", NSIntegerId);
}
/// Returns true if \param T is a typedef of "NSUInteger" in objective-c.
bool NSAPI::isObjCNSUIntegerType(QualType T) const {
return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
}
StringRef NSAPI::GetNSIntegralKind(QualType T) const {
if (!Ctx.getLangOpts().ObjC || T.isNull())
return StringRef();
while (const TypedefType *TDT = T->getAs<TypedefType>()) {
StringRef NSIntegralResust =
llvm::StringSwitch<StringRef>(
TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())
.Case("int8_t", "int8_t")
.Case("int16_t", "int16_t")
.Case("int32_t", "int32_t")
.Case("NSInteger", "NSInteger")
.Case("int64_t", "int64_t")
.Case("uint8_t", "uint8_t")
.Case("uint16_t", "uint16_t")
.Case("uint32_t", "uint32_t")
.Case("NSUInteger", "NSUInteger")
.Case("uint64_t", "uint64_t")
.Default(StringRef());
if (!NSIntegralResust.empty())
return NSIntegralResust;
T = TDT->desugar();
}
return StringRef();
}
bool NSAPI::isMacroDefined(StringRef Id) const {
// FIXME: Check whether the relevant module macros are visible.
return Ctx.Idents.get(Id).hasMacroDefinition();
}
bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,
NSClassIdKindKind NSClassKind) const {
if (!InterfaceDecl) {
return false;
}
IdentifierInfo *NSClassID = getNSClassId(NSClassKind);
bool IsSubclass = false;
do {
IsSubclass = NSClassID == InterfaceDecl->getIdentifier();
if (IsSubclass) {
break;
}
} while ((InterfaceDecl = InterfaceDecl->getSuperClass()));
return IsSubclass;
}
bool NSAPI::isObjCTypedef(QualType T,
StringRef name, IdentifierInfo *&II) const {
if (!Ctx.getLangOpts().ObjC)
return false;
if (T.isNull())
return false;
if (!II)
II = &Ctx.Idents.get(name);
while (const TypedefType *TDT = T->getAs<TypedefType>()) {
if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
return true;
T = TDT->desugar();
}
return false;
}
bool NSAPI::isObjCEnumerator(const Expr *E,
StringRef name, IdentifierInfo *&II) const {
if (!Ctx.getLangOpts().ObjC)
return false;
if (!E)
return false;
if (!II)
II = &Ctx.Idents.get(name);
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
if (const EnumConstantDecl *
EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
return EnumD->getIdentifier() == II;
return false;
}
Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
Selector &Sel) const {
if (Sel.isNull()) {
SmallVector<const IdentifierInfo *, 4> Idents;
for (ArrayRef<StringRef>::const_iterator
I = Ids.begin(), E = Ids.end(); I != E; ++I)
Idents.push_back(&Ctx.Idents.get(*I));
Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
}
return Sel;
}
Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {
if (Sel.isNull()) {
const IdentifierInfo *Ident = &Ctx.Idents.get(Id);
Sel = Ctx.Selectors.getSelector(0, &Ident);
}
return Sel;
}