2006-11-10 14:34:16 +08:00
|
|
|
//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 03:59:25 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2006-11-10 14:34:16 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the ASTContext interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-08-08 04:55:28 +08:00
|
|
|
#include "clang/AST/DeclCXX.h"
|
2007-10-02 03:00:59 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2009-02-05 03:02:06 +08:00
|
|
|
#include "clang/AST/DeclTemplate.h"
|
2009-08-19 09:27:32 +08:00
|
|
|
#include "clang/AST/TypeLoc.h"
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/AST/Expr.h"
|
2009-04-10 06:27:44 +08:00
|
|
|
#include "clang/AST/ExternalASTSource.h"
|
2009-07-19 03:43:29 +08:00
|
|
|
#include "clang/AST/RecordLayout.h"
|
2009-06-14 09:54:56 +08:00
|
|
|
#include "clang/Basic/Builtins.h"
|
2009-03-28 11:45:20 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2007-05-21 07:50:58 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2007-10-29 13:01:08 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2009-01-18 14:42:49 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2009-03-28 12:27:18 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2009-07-19 05:19:52 +08:00
|
|
|
#include "RecordLayoutBuilder.h"
|
|
|
|
|
2006-11-10 14:34:16 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2007-04-28 05:51:21 +08:00
|
|
|
enum FloatingRank {
|
|
|
|
FloatRank, DoubleRank, LongDoubleRank
|
|
|
|
};
|
|
|
|
|
2008-10-06 01:34:18 +08:00
|
|
|
ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
|
|
|
|
TargetInfo &t,
|
2008-08-11 12:54:23 +08:00
|
|
|
IdentifierTable &idents, SelectorTable &sels,
|
2009-06-14 09:54:56 +08:00
|
|
|
Builtin::Context &builtins,
|
2009-09-09 23:08:12 +08:00
|
|
|
bool FreeMem, unsigned size_reserve) :
|
|
|
|
GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0),
|
2009-07-28 10:25:19 +08:00
|
|
|
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
|
2009-10-20 10:12:22 +08:00
|
|
|
sigjmp_bufDecl(0), BlockDescriptorType(0), SourceMgr(SM), LangOpts(LOpts),
|
2009-09-09 23:08:12 +08:00
|
|
|
LoadedExternalComments(false), FreeMemory(FreeMem), Target(t),
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
Idents(idents), Selectors(sels),
|
2009-09-09 23:08:12 +08:00
|
|
|
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
|
2009-08-18 00:35:33 +08:00
|
|
|
ObjCIdRedefinitionType = QualType();
|
|
|
|
ObjCClassRedefinitionType = QualType();
|
2009-09-09 23:08:12 +08:00
|
|
|
if (size_reserve > 0) Types.reserve(size_reserve);
|
2008-08-11 12:54:23 +08:00
|
|
|
TUDecl = TranslationUnitDecl::Create(*this);
|
2009-07-11 07:34:53 +08:00
|
|
|
InitBuiltinTypes();
|
2008-08-11 12:54:23 +08:00
|
|
|
}
|
|
|
|
|
2006-11-12 08:53:46 +08:00
|
|
|
ASTContext::~ASTContext() {
|
|
|
|
// Deallocate all the types.
|
|
|
|
while (!Types.empty()) {
|
2008-05-22 00:38:54 +08:00
|
|
|
Types.back()->Destroy(*this);
|
2006-11-12 08:53:46 +08:00
|
|
|
Types.pop_back();
|
|
|
|
}
|
2008-05-27 11:08:09 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
{
|
|
|
|
llvm::FoldingSet<ExtQuals>::iterator
|
|
|
|
I = ExtQualNodes.begin(), E = ExtQualNodes.end();
|
|
|
|
while (I != E)
|
|
|
|
Deallocate(&*I++);
|
|
|
|
}
|
|
|
|
|
2008-12-18 06:30:25 +08:00
|
|
|
{
|
|
|
|
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator
|
|
|
|
I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end();
|
|
|
|
while (I != E) {
|
|
|
|
ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
|
|
|
|
delete R;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2009-05-03 18:38:35 +08:00
|
|
|
llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>::iterator
|
|
|
|
I = ObjCLayouts.begin(), E = ObjCLayouts.end();
|
2008-12-18 06:30:25 +08:00
|
|
|
while (I != E) {
|
|
|
|
ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second);
|
|
|
|
delete R;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-27 07:50:42 +08:00
|
|
|
// Destroy nested-name-specifiers.
|
2009-03-28 07:54:10 +08:00
|
|
|
for (llvm::FoldingSet<NestedNameSpecifier>::iterator
|
|
|
|
NNS = NestedNameSpecifiers.begin(),
|
2009-09-09 23:08:12 +08:00
|
|
|
NNSEnd = NestedNameSpecifiers.end();
|
|
|
|
NNS != NNSEnd;
|
2009-03-28 07:54:10 +08:00
|
|
|
/* Increment in loop */)
|
|
|
|
(*NNS++).Destroy(*this);
|
2009-03-27 07:50:42 +08:00
|
|
|
|
|
|
|
if (GlobalNestedNameSpecifier)
|
|
|
|
GlobalNestedNameSpecifier->Destroy(*this);
|
|
|
|
|
2008-05-27 11:08:09 +08:00
|
|
|
TUDecl->Destroy(*this);
|
2006-11-12 08:53:46 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2009-04-10 06:27:44 +08:00
|
|
|
ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) {
|
|
|
|
ExternalSource.reset(Source.take());
|
|
|
|
}
|
|
|
|
|
2007-01-26 09:27:23 +08:00
|
|
|
void ASTContext::PrintStats() const {
|
|
|
|
fprintf(stderr, "*** AST Context Stats:\n");
|
|
|
|
fprintf(stderr, " %d types total.\n", (int)Types.size());
|
2009-03-17 07:22:08 +08:00
|
|
|
|
2009-05-26 22:40:08 +08:00
|
|
|
unsigned counts[] = {
|
2009-09-09 23:08:12 +08:00
|
|
|
#define TYPE(Name, Parent) 0,
|
2009-05-26 22:40:08 +08:00
|
|
|
#define ABSTRACT_TYPE(Name, Parent)
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
|
|
|
0 // Extra
|
|
|
|
};
|
2009-04-08 01:20:56 +08:00
|
|
|
|
2007-01-26 09:27:23 +08:00
|
|
|
for (unsigned i = 0, e = Types.size(); i != e; ++i) {
|
|
|
|
Type *T = Types[i];
|
2009-05-26 22:40:08 +08:00
|
|
|
counts[(unsigned)T->getTypeClass()]++;
|
2007-01-26 09:27:23 +08:00
|
|
|
}
|
|
|
|
|
2009-05-26 22:40:08 +08:00
|
|
|
unsigned Idx = 0;
|
|
|
|
unsigned TotalBytes = 0;
|
|
|
|
#define TYPE(Name, Parent) \
|
|
|
|
if (counts[Idx]) \
|
|
|
|
fprintf(stderr, " %d %s types\n", (int)counts[Idx], #Name); \
|
|
|
|
TotalBytes += counts[Idx] * sizeof(Name##Type); \
|
|
|
|
++Idx;
|
|
|
|
#define ABSTRACT_TYPE(Name, Parent)
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-26 22:40:08 +08:00
|
|
|
fprintf(stderr, "Total bytes = %d\n", int(TotalBytes));
|
2009-04-10 06:27:44 +08:00
|
|
|
|
|
|
|
if (ExternalSource.get()) {
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
ExternalSource->PrintStats();
|
|
|
|
}
|
2007-01-26 09:27:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-06 06:36:20 +08:00
|
|
|
void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) {
|
2009-09-25 07:30:46 +08:00
|
|
|
BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
|
|
|
|
R = QualType(Ty, 0);
|
|
|
|
Types.push_back(Ty);
|
2006-11-12 08:53:46 +08:00
|
|
|
}
|
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
void ASTContext::InitBuiltinTypes() {
|
|
|
|
assert(VoidTy.isNull() && "Context reinitialized?");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p19.
|
2006-12-03 10:57:32 +08:00
|
|
|
InitBuiltinType(VoidTy, BuiltinType::Void);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p2.
|
2006-12-03 10:57:32 +08:00
|
|
|
InitBuiltinType(BoolTy, BuiltinType::Bool);
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p3.
|
2009-06-05 15:05:05 +08:00
|
|
|
if (LangOpts.CharIsSigned)
|
2007-06-03 15:25:34 +08:00
|
|
|
InitBuiltinType(CharTy, BuiltinType::Char_S);
|
|
|
|
else
|
|
|
|
InitBuiltinType(CharTy, BuiltinType::Char_U);
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p4.
|
2006-12-03 10:57:32 +08:00
|
|
|
InitBuiltinType(SignedCharTy, BuiltinType::SChar);
|
|
|
|
InitBuiltinType(ShortTy, BuiltinType::Short);
|
|
|
|
InitBuiltinType(IntTy, BuiltinType::Int);
|
|
|
|
InitBuiltinType(LongTy, BuiltinType::Long);
|
|
|
|
InitBuiltinType(LongLongTy, BuiltinType::LongLong);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p6.
|
2006-12-03 10:57:32 +08:00
|
|
|
InitBuiltinType(UnsignedCharTy, BuiltinType::UChar);
|
|
|
|
InitBuiltinType(UnsignedShortTy, BuiltinType::UShort);
|
|
|
|
InitBuiltinType(UnsignedIntTy, BuiltinType::UInt);
|
|
|
|
InitBuiltinType(UnsignedLongTy, BuiltinType::ULong);
|
|
|
|
InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p10.
|
2006-12-03 10:57:32 +08:00
|
|
|
InitBuiltinType(FloatTy, BuiltinType::Float);
|
|
|
|
InitBuiltinType(DoubleTy, BuiltinType::Double);
|
|
|
|
InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble);
|
2008-08-10 00:51:54 +08:00
|
|
|
|
2009-04-30 10:43:43 +08:00
|
|
|
// GNU extension, 128-bit integers.
|
|
|
|
InitBuiltinType(Int128Ty, BuiltinType::Int128);
|
|
|
|
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
|
|
|
|
|
2009-02-27 07:43:47 +08:00
|
|
|
if (LangOpts.CPlusPlus) // C++ 3.9.1p5
|
|
|
|
InitBuiltinType(WCharTy, BuiltinType::WChar);
|
|
|
|
else // C99
|
|
|
|
WCharTy = getFromTargetType(Target.getWCharType());
|
2008-08-10 00:51:54 +08:00
|
|
|
|
2009-07-14 14:30:34 +08:00
|
|
|
if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++
|
|
|
|
InitBuiltinType(Char16Ty, BuiltinType::Char16);
|
|
|
|
else // C99
|
|
|
|
Char16Ty = getFromTargetType(Target.getChar16Type());
|
|
|
|
|
|
|
|
if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++
|
|
|
|
InitBuiltinType(Char32Ty, BuiltinType::Char32);
|
|
|
|
else // C99
|
|
|
|
Char32Ty = getFromTargetType(Target.getChar32Type());
|
|
|
|
|
2008-10-22 00:13:35 +08:00
|
|
|
// Placeholder type for functions.
|
2008-12-06 07:32:09 +08:00
|
|
|
InitBuiltinType(OverloadTy, BuiltinType::Overload);
|
|
|
|
|
|
|
|
// Placeholder type for type-dependent expressions whose type is
|
|
|
|
// completely unknown. No code should ever check a type against
|
|
|
|
// DependentTy and users should never see it; however, it is here to
|
|
|
|
// help diagnose failures to properly check for type-dependent
|
|
|
|
// expressions.
|
|
|
|
InitBuiltinType(DependentTy, BuiltinType::Dependent);
|
2008-10-22 00:13:35 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Placeholder type for C++0x auto declarations whose real type has
|
2009-06-27 02:41:36 +08:00
|
|
|
// not yet been deduced.
|
|
|
|
InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
// C99 6.2.5p11.
|
2007-06-23 04:56:16 +08:00
|
|
|
FloatComplexTy = getComplexType(FloatTy);
|
|
|
|
DoubleComplexTy = getComplexType(DoubleTy);
|
|
|
|
LongDoubleComplexTy = getComplexType(LongDoubleTy);
|
2008-10-22 00:13:35 +08:00
|
|
|
|
2007-10-15 22:41:52 +08:00
|
|
|
BuiltinVaListType = QualType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-16 02:40:39 +08:00
|
|
|
// "Builtin" typedefs set by Sema::ActOnTranslationUnitScope().
|
|
|
|
ObjCIdTypedefType = QualType();
|
|
|
|
ObjCClassTypedefType = QualType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-16 02:40:39 +08:00
|
|
|
// Builtin types for 'id' and 'Class'.
|
|
|
|
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
|
|
|
|
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
|
2009-07-11 07:34:53 +08:00
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCConstantStringType = QualType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-30 06:57:28 +08:00
|
|
|
// void * type
|
|
|
|
VoidPtrTy = getPointerType(VoidTy);
|
2009-05-11 02:38:11 +08:00
|
|
|
|
|
|
|
// nullptr type (C++0x 2.14.7)
|
|
|
|
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
|
2006-11-12 08:37:36 +08:00
|
|
|
}
|
|
|
|
|
2009-10-08 15:24:58 +08:00
|
|
|
MemberSpecializationInfo *
|
2009-10-15 04:14:33 +08:00
|
|
|
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
|
2009-07-25 04:34:43 +08:00
|
|
|
assert(Var->isStaticDataMember() && "Not a static data member");
|
2009-10-15 04:14:33 +08:00
|
|
|
llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos
|
2009-07-25 04:34:43 +08:00
|
|
|
= InstantiatedFromStaticDataMember.find(Var);
|
|
|
|
if (Pos == InstantiatedFromStaticDataMember.end())
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-25 04:34:43 +08:00
|
|
|
return Pos->second;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void
|
2009-10-08 15:24:58 +08:00
|
|
|
ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
|
|
|
TemplateSpecializationKind TSK) {
|
2009-07-25 04:34:43 +08:00
|
|
|
assert(Inst->isStaticDataMember() && "Not a static data member");
|
|
|
|
assert(Tmpl->isStaticDataMember() && "Not a static data member");
|
|
|
|
assert(!InstantiatedFromStaticDataMember[Inst] &&
|
|
|
|
"Already noted what static data member was instantiated from");
|
2009-10-08 15:24:58 +08:00
|
|
|
InstantiatedFromStaticDataMember[Inst]
|
|
|
|
= new (*this) MemberSpecializationInfo(Tmpl, TSK);
|
2009-07-25 04:34:43 +08:00
|
|
|
}
|
|
|
|
|
2009-08-30 03:37:28 +08:00
|
|
|
UnresolvedUsingDecl *
|
|
|
|
ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos
|
2009-08-30 03:37:28 +08:00
|
|
|
= InstantiatedFromUnresolvedUsingDecl.find(UUD);
|
|
|
|
if (Pos == InstantiatedFromUnresolvedUsingDecl.end())
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-30 03:37:28 +08:00
|
|
|
return Pos->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
|
|
|
|
UnresolvedUsingDecl *UUD) {
|
|
|
|
assert(!InstantiatedFromUnresolvedUsingDecl[UD] &&
|
|
|
|
"Already noted what using decl what instantiated from");
|
|
|
|
InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
|
|
|
|
}
|
|
|
|
|
2009-09-01 12:26:58 +08:00
|
|
|
FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
|
|
|
|
llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos
|
|
|
|
= InstantiatedFromUnnamedFieldDecl.find(Field);
|
|
|
|
if (Pos == InstantiatedFromUnnamedFieldDecl.end())
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-01 12:26:58 +08:00
|
|
|
return Pos->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
|
|
|
|
FieldDecl *Tmpl) {
|
|
|
|
assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
|
|
|
|
assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
|
|
|
|
assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
|
|
|
|
"Already noted what unnamed field was instantiated from");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-01 12:26:58 +08:00
|
|
|
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
|
|
|
|
}
|
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
namespace {
|
2009-09-09 23:08:12 +08:00
|
|
|
class BeforeInTranslationUnit
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
: std::binary_function<SourceRange, SourceRange, bool> {
|
|
|
|
SourceManager *SourceMgr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
public:
|
|
|
|
explicit BeforeInTranslationUnit(SourceManager *SM) : SourceMgr(SM) { }
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
bool operator()(SourceRange X, SourceRange Y) {
|
|
|
|
return SourceMgr->isBeforeInTranslationUnit(X.getBegin(), Y.getBegin());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Determine whether the given comment is a Doxygen-style comment.
|
|
|
|
///
|
|
|
|
/// \param Start the start of the comment text.
|
|
|
|
///
|
|
|
|
/// \param End the end of the comment text.
|
|
|
|
///
|
|
|
|
/// \param Member whether we want to check whether this is a member comment
|
|
|
|
/// (which requires a < after the Doxygen-comment delimiter). Otherwise,
|
|
|
|
/// we only return true when we find a non-member comment.
|
2009-09-09 23:08:12 +08:00
|
|
|
static bool
|
|
|
|
isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment,
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
bool Member = false) {
|
2009-09-09 23:08:12 +08:00
|
|
|
const char *BufferStart
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first;
|
|
|
|
const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin());
|
|
|
|
const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
if (End - Start < 4)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
assert(Start[0] == '/' && "Not a comment?");
|
|
|
|
if (Start[1] == '*' && !(Start[2] == '!' || Start[2] == '*'))
|
|
|
|
return false;
|
|
|
|
if (Start[1] == '/' && !(Start[2] == '!' || Start[2] == '/'))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return (Start[3] == '<') == Member;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Retrieve the comment associated with the given declaration, if
|
2009-09-09 23:08:12 +08:00
|
|
|
/// it has one.
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
const char *ASTContext::getCommentForDecl(const Decl *D) {
|
|
|
|
if (!D)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Check whether we have cached a comment string for this declaration
|
|
|
|
// already.
|
2009-09-09 23:08:12 +08:00
|
|
|
llvm::DenseMap<const Decl *, std::string>::iterator Pos
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= DeclComments.find(D);
|
|
|
|
if (Pos != DeclComments.end())
|
|
|
|
return Pos->second.c_str();
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// If we have an external AST source and have not yet loaded comments from
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// that source, do so now.
|
|
|
|
if (ExternalSource && !LoadedExternalComments) {
|
|
|
|
std::vector<SourceRange> LoadedComments;
|
|
|
|
ExternalSource->ReadComments(LoadedComments);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
if (!LoadedComments.empty())
|
|
|
|
Comments.insert(Comments.begin(), LoadedComments.begin(),
|
|
|
|
LoadedComments.end());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
LoadedExternalComments = true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// If there are no comments anywhere, we won't find anything.
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
if (Comments.empty())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// If the declaration doesn't map directly to a location in a file, we
|
|
|
|
// can't find the comment.
|
|
|
|
SourceLocation DeclStartLoc = D->getLocStart();
|
|
|
|
if (DeclStartLoc.isInvalid() || !DeclStartLoc.isFileID())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Find the comment that occurs just before this declaration.
|
|
|
|
std::vector<SourceRange>::iterator LastComment
|
2009-09-09 23:08:12 +08:00
|
|
|
= std::lower_bound(Comments.begin(), Comments.end(),
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
SourceRange(DeclStartLoc),
|
|
|
|
BeforeInTranslationUnit(&SourceMgr));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Decompose the location for the start of the declaration and find the
|
|
|
|
// beginning of the file buffer.
|
2009-09-09 23:08:12 +08:00
|
|
|
std::pair<FileID, unsigned> DeclStartDecomp
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getDecomposedLoc(DeclStartLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
const char *FileBufferStart
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getBufferData(DeclStartDecomp.first).first;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// First check whether we have a comment for a member.
|
|
|
|
if (LastComment != Comments.end() &&
|
|
|
|
!isa<TagDecl>(D) && !isa<NamespaceDecl>(D) &&
|
|
|
|
isDoxygenComment(SourceMgr, *LastComment, true)) {
|
|
|
|
std::pair<FileID, unsigned> LastCommentEndDecomp
|
|
|
|
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
|
|
|
|
if (DeclStartDecomp.first == LastCommentEndDecomp.first &&
|
|
|
|
SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second)
|
2009-09-09 23:08:12 +08:00
|
|
|
== SourceMgr.getLineNumber(LastCommentEndDecomp.first,
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
LastCommentEndDecomp.second)) {
|
|
|
|
// The Doxygen member comment comes after the declaration starts and
|
|
|
|
// is on the same line and in the same file as the declaration. This
|
|
|
|
// is the comment we want.
|
|
|
|
std::string &Result = DeclComments[D];
|
2009-09-09 23:08:12 +08:00
|
|
|
Result.append(FileBufferStart +
|
|
|
|
SourceMgr.getFileOffset(LastComment->getBegin()),
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
FileBufferStart + LastCommentEndDecomp.second + 1);
|
|
|
|
return Result.c_str();
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
if (LastComment == Comments.begin())
|
|
|
|
return 0;
|
|
|
|
--LastComment;
|
|
|
|
|
|
|
|
// Decompose the end of the comment.
|
|
|
|
std::pair<FileID, unsigned> LastCommentEndDecomp
|
|
|
|
= SourceMgr.getDecomposedLoc(LastComment->getEnd());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// If the comment and the declaration aren't in the same file, then they
|
|
|
|
// aren't related.
|
|
|
|
if (DeclStartDecomp.first != LastCommentEndDecomp.first)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Check that we actually have a Doxygen comment.
|
|
|
|
if (!isDoxygenComment(SourceMgr, *LastComment))
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Compute the starting line for the declaration and for the end of the
|
|
|
|
// comment (this is expensive).
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned DeclStartLine
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second);
|
|
|
|
unsigned CommentEndLine
|
2009-09-09 23:08:12 +08:00
|
|
|
= SourceMgr.getLineNumber(LastCommentEndDecomp.first,
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
LastCommentEndDecomp.second);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// If the comment does not end on the line prior to the declaration, then
|
|
|
|
// the comment is not associated with the declaration at all.
|
|
|
|
if (CommentEndLine + 1 != DeclStartLine)
|
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// We have a comment, but there may be more comments on the previous lines.
|
|
|
|
// Keep looking so long as the comments are still Doxygen comments and are
|
|
|
|
// still adjacent.
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned ExpectedLine
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1;
|
|
|
|
std::vector<SourceRange>::iterator FirstComment = LastComment;
|
|
|
|
while (FirstComment != Comments.begin()) {
|
|
|
|
// Look at the previous comment
|
|
|
|
--FirstComment;
|
|
|
|
std::pair<FileID, unsigned> Decomp
|
|
|
|
= SourceMgr.getDecomposedLoc(FirstComment->getEnd());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// If this previous comment is in a different file, we're done.
|
|
|
|
if (Decomp.first != DeclStartDecomp.first) {
|
|
|
|
++FirstComment;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// If this comment is not a Doxygen comment, we're done.
|
|
|
|
if (!isDoxygenComment(SourceMgr, *FirstComment)) {
|
|
|
|
++FirstComment;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// If the line number is not what we expected, we're done.
|
|
|
|
unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second);
|
|
|
|
if (Line != ExpectedLine) {
|
|
|
|
++FirstComment;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Set the next expected line number.
|
2009-09-09 23:08:12 +08:00
|
|
|
ExpectedLine
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
= SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// The iterator range [FirstComment, LastComment] contains all of the
|
|
|
|
// BCPL comments that, together, are associated with this declaration.
|
|
|
|
// Form a single comment block string for this declaration that concatenates
|
|
|
|
// all of these comments.
|
|
|
|
std::string &Result = DeclComments[D];
|
|
|
|
while (FirstComment != LastComment) {
|
|
|
|
std::pair<FileID, unsigned> DecompStart
|
|
|
|
= SourceMgr.getDecomposedLoc(FirstComment->getBegin());
|
|
|
|
std::pair<FileID, unsigned> DecompEnd
|
|
|
|
= SourceMgr.getDecomposedLoc(FirstComment->getEnd());
|
|
|
|
Result.append(FileBufferStart + DecompStart.second,
|
|
|
|
FileBufferStart + DecompEnd.second + 1);
|
|
|
|
++FirstComment;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
// Append the last comment line.
|
2009-09-09 23:08:12 +08:00
|
|
|
Result.append(FileBufferStart +
|
|
|
|
SourceMgr.getFileOffset(LastComment->getBegin()),
|
Add support for retrieving the Doxygen comment associated with a given
declaration in the AST.
The new ASTContext::getCommentForDecl function searches for a comment
that is attached to the given declaration, and returns that comment,
which may be composed of several comment blocks.
Comments are always available in an AST. However, to avoid harming
performance, we don't actually parse the comments. Rather, we keep the
source ranges of all of the comments within a large, sorted vector,
then lazily extract comments via a binary search in that vector only
when needed (which never occurs in a "normal" compile).
Comments are written to a precompiled header/AST file as a blob of
source ranges. That blob is only lazily loaded when one requests a
comment for a declaration (this never occurs in a "normal" compile).
The indexer testbed now supports comment extraction. When the
-point-at location points to a declaration with a Doxygen-style
comment, the indexer testbed prints the associated comment
block(s). See test/Index/comments.c for an example.
Some notes:
- We don't actually attempt to parse the comment blocks themselves,
beyond identifying them as Doxygen comment blocks to associate them
with a declaration.
- We won't find comment blocks that aren't adjacent to the
declaration, because we start our search based on the location of
the declaration.
- We don't go through the necessary hops to find, for example,
whether some redeclaration of a declaration has comments when our
current declaration does not. Similarly, we don't attempt to
associate a \param Foo marker in a function body comment with the
parameter named Foo (although that is certainly possible).
- Verification of my "no performance impact" claims is still "to be
done".
llvm-svn: 74704
2009-07-03 01:08:52 +08:00
|
|
|
FileBufferStart + LastCommentEndDecomp.second + 1);
|
|
|
|
return Result.c_str();
|
|
|
|
}
|
|
|
|
|
2007-07-19 01:52:12 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Sizing and Analysis
|
|
|
|
//===----------------------------------------------------------------------===//
|
2007-07-14 06:13:22 +08:00
|
|
|
|
2008-07-01 02:32:54 +08:00
|
|
|
/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
|
|
|
|
/// scalar floating point type.
|
|
|
|
const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
|
2009-09-22 07:43:11 +08:00
|
|
|
const BuiltinType *BT = T->getAs<BuiltinType>();
|
2008-07-01 02:32:54 +08:00
|
|
|
assert(BT && "Not a floating point type!");
|
|
|
|
switch (BT->getKind()) {
|
|
|
|
default: assert(0 && "Not a floating point type!");
|
|
|
|
case BuiltinType::Float: return Target.getFloatFormat();
|
|
|
|
case BuiltinType::Double: return Target.getDoubleFormat();
|
|
|
|
case BuiltinType::LongDouble: return Target.getLongDoubleFormat();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-22 10:43:44 +08:00
|
|
|
/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
|
2009-01-25 05:53:27 +08:00
|
|
|
/// specified decl. Note that bitfields do not have a valid alignment, so
|
|
|
|
/// this method will assert on them.
|
2009-02-18 06:16:19 +08:00
|
|
|
unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
|
2009-02-22 10:56:25 +08:00
|
|
|
unsigned Align = Target.getCharWidth();
|
|
|
|
|
2009-06-30 10:34:44 +08:00
|
|
|
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
|
2009-02-22 10:56:25 +08:00
|
|
|
Align = std::max(Align, AA->getAlignment());
|
|
|
|
|
2009-01-25 05:53:27 +08:00
|
|
|
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
|
|
|
|
QualType T = VD->getType();
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
|
2009-04-10 12:47:03 +08:00
|
|
|
unsigned AS = RT->getPointeeType().getAddressSpace();
|
2009-04-10 12:52:36 +08:00
|
|
|
Align = Target.getPointerAlign(AS);
|
2009-04-10 12:47:03 +08:00
|
|
|
} else if (!T->isIncompleteType() && !T->isFunctionType()) {
|
|
|
|
// Incomplete or function types default to 1.
|
2009-02-22 10:56:25 +08:00
|
|
|
while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
|
|
|
|
T = cast<ArrayType>(T)->getElementType();
|
|
|
|
|
|
|
|
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
|
|
|
|
}
|
2009-01-25 05:53:27 +08:00
|
|
|
}
|
2009-02-22 10:56:25 +08:00
|
|
|
|
|
|
|
return Align / Target.getCharWidth();
|
2009-01-25 05:53:27 +08:00
|
|
|
}
|
2008-07-01 02:32:54 +08:00
|
|
|
|
2007-07-14 06:13:22 +08:00
|
|
|
/// getTypeSize - Return the size of the specified type, in bits. This method
|
|
|
|
/// does not work on incomplete types.
|
2009-09-25 03:53:00 +08:00
|
|
|
///
|
|
|
|
/// FIXME: Pointers into different addr spaces could have different sizes and
|
|
|
|
/// alignment requirements: getPointerInfo should take an AddrSpace, this
|
|
|
|
/// should take a QualType, &c.
|
2007-07-14 09:29:45 +08:00
|
|
|
std::pair<uint64_t, unsigned>
|
2008-11-08 13:48:37 +08:00
|
|
|
ASTContext::getTypeInfo(const Type *T) {
|
2009-02-28 02:32:39 +08:00
|
|
|
uint64_t Width=0;
|
|
|
|
unsigned Align=8;
|
2007-07-14 06:13:22 +08:00
|
|
|
switch (T->getTypeClass()) {
|
2009-02-27 07:50:07 +08:00
|
|
|
#define TYPE(Class, Base)
|
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
2009-05-01 01:32:17 +08:00
|
|
|
#define NON_CANONICAL_TYPE(Class, Base)
|
2009-02-27 07:50:07 +08:00
|
|
|
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
2009-05-01 01:32:17 +08:00
|
|
|
assert(false && "Should not see dependent types");
|
2009-02-27 07:50:07 +08:00
|
|
|
break;
|
|
|
|
|
2009-09-30 03:42:55 +08:00
|
|
|
case Type::ObjCProtocolList:
|
|
|
|
assert(false && "Should not see protocol list types");
|
|
|
|
break;
|
|
|
|
|
2007-07-19 02:26:58 +08:00
|
|
|
case Type::FunctionNoProto:
|
|
|
|
case Type::FunctionProto:
|
2009-05-01 01:32:17 +08:00
|
|
|
// GCC extension: alignof(function) = 32 bits
|
|
|
|
Width = 0;
|
|
|
|
Align = 32;
|
|
|
|
break;
|
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
case Type::IncompleteArray:
|
2007-08-30 09:06:46 +08:00
|
|
|
case Type::VariableArray:
|
2009-05-01 01:32:17 +08:00
|
|
|
Width = 0;
|
|
|
|
Align = getTypeAlign(cast<ArrayType>(T)->getElementType());
|
|
|
|
break;
|
|
|
|
|
2007-08-30 09:06:46 +08:00
|
|
|
case Type::ConstantArray: {
|
2008-11-08 13:48:37 +08:00
|
|
|
const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-06 02:54:05 +08:00
|
|
|
std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType());
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = EltInfo.first*CAT->getSize().getZExtValue();
|
2007-07-20 06:06:24 +08:00
|
|
|
Align = EltInfo.second;
|
|
|
|
break;
|
2007-12-29 13:10:55 +08:00
|
|
|
}
|
2008-04-19 07:10:10 +08:00
|
|
|
case Type::ExtVector:
|
2007-07-20 06:06:24 +08:00
|
|
|
case Type::Vector: {
|
2009-09-09 23:08:12 +08:00
|
|
|
std::pair<uint64_t, unsigned> EltInfo =
|
2008-03-06 02:54:05 +08:00
|
|
|
getTypeInfo(cast<VectorType>(T)->getElementType());
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = EltInfo.first*cast<VectorType>(T)->getNumElements();
|
2008-05-30 17:31:38 +08:00
|
|
|
Align = Width;
|
2009-01-18 14:42:49 +08:00
|
|
|
// If the alignment is not a power of 2, round up to the next power of 2.
|
|
|
|
// This happens for non-power-of-2 length vectors.
|
|
|
|
// FIXME: this should probably be a target property.
|
|
|
|
Align = 1 << llvm::Log2_32_Ceil(Align);
|
2007-07-20 06:06:24 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-07-19 02:26:58 +08:00
|
|
|
|
2008-03-08 16:52:55 +08:00
|
|
|
case Type::Builtin:
|
2007-07-14 06:13:22 +08:00
|
|
|
switch (cast<BuiltinType>(T)->getKind()) {
|
2007-07-14 06:27:08 +08:00
|
|
|
default: assert(0 && "Unknown builtin type!");
|
2007-07-14 09:29:45 +08:00
|
|
|
case BuiltinType::Void:
|
2009-05-01 01:32:17 +08:00
|
|
|
// GCC extension: alignof(void) = 8 bits.
|
|
|
|
Width = 0;
|
|
|
|
Align = 8;
|
|
|
|
break;
|
|
|
|
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::Bool:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getBoolWidth();
|
|
|
|
Align = Target.getBoolAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2007-07-14 06:27:08 +08:00
|
|
|
case BuiltinType::Char_S:
|
|
|
|
case BuiltinType::Char_U:
|
|
|
|
case BuiltinType::UChar:
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::SChar:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getCharWidth();
|
|
|
|
Align = Target.getCharAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2008-08-10 00:51:54 +08:00
|
|
|
case BuiltinType::WChar:
|
|
|
|
Width = Target.getWCharWidth();
|
|
|
|
Align = Target.getWCharAlign();
|
|
|
|
break;
|
2009-07-14 14:30:34 +08:00
|
|
|
case BuiltinType::Char16:
|
|
|
|
Width = Target.getChar16Width();
|
|
|
|
Align = Target.getChar16Align();
|
|
|
|
break;
|
|
|
|
case BuiltinType::Char32:
|
|
|
|
Width = Target.getChar32Width();
|
|
|
|
Align = Target.getChar32Align();
|
|
|
|
break;
|
2007-07-14 06:27:08 +08:00
|
|
|
case BuiltinType::UShort:
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::Short:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getShortWidth();
|
|
|
|
Align = Target.getShortAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2007-07-14 06:27:08 +08:00
|
|
|
case BuiltinType::UInt:
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::Int:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getIntWidth();
|
|
|
|
Align = Target.getIntAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2007-07-14 06:27:08 +08:00
|
|
|
case BuiltinType::ULong:
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::Long:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getLongWidth();
|
|
|
|
Align = Target.getLongAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2007-07-14 06:27:08 +08:00
|
|
|
case BuiltinType::ULongLong:
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::LongLong:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getLongLongWidth();
|
|
|
|
Align = Target.getLongLongAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2009-04-30 10:55:13 +08:00
|
|
|
case BuiltinType::Int128:
|
|
|
|
case BuiltinType::UInt128:
|
|
|
|
Width = 128;
|
|
|
|
Align = 128; // int128_t is 128-bit aligned on all targets.
|
|
|
|
break;
|
2007-12-20 03:23:28 +08:00
|
|
|
case BuiltinType::Float:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getFloatWidth();
|
|
|
|
Align = Target.getFloatAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
|
|
|
case BuiltinType::Double:
|
2008-04-07 15:01:58 +08:00
|
|
|
Width = Target.getDoubleWidth();
|
|
|
|
Align = Target.getDoubleAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
|
|
|
case BuiltinType::LongDouble:
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = Target.getLongDoubleWidth();
|
|
|
|
Align = Target.getLongDoubleAlign();
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2009-05-11 02:38:11 +08:00
|
|
|
case BuiltinType::NullPtr:
|
|
|
|
Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
|
|
|
|
Align = Target.getPointerAlign(0); // == sizeof(void*)
|
2009-05-28 03:34:06 +08:00
|
|
|
break;
|
2007-07-14 06:13:22 +08:00
|
|
|
}
|
2007-07-16 07:46:53 +08:00
|
|
|
break;
|
2009-02-13 10:31:07 +08:00
|
|
|
case Type::FixedWidthInt:
|
|
|
|
// FIXME: This isn't precisely correct; the width/alignment should depend
|
|
|
|
// on the available types for the target
|
|
|
|
Width = cast<FixedWidthIntType>(T)->getWidth();
|
2009-02-16 05:20:13 +08:00
|
|
|
Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8);
|
2009-02-13 10:31:07 +08:00
|
|
|
Align = Width;
|
|
|
|
break;
|
2009-06-18 06:40:22 +08:00
|
|
|
case Type::ObjCObjectPointer:
|
2008-04-07 15:01:58 +08:00
|
|
|
Width = Target.getPointerWidth(0);
|
2008-03-08 16:34:58 +08:00
|
|
|
Align = Target.getPointerAlign(0);
|
2007-12-20 03:23:28 +08:00
|
|
|
break;
|
2008-09-24 23:05:44 +08:00
|
|
|
case Type::BlockPointer: {
|
|
|
|
unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
|
|
|
|
Width = Target.getPointerWidth(AS);
|
|
|
|
Align = Target.getPointerAlign(AS);
|
|
|
|
break;
|
|
|
|
}
|
2008-03-08 16:34:58 +08:00
|
|
|
case Type::Pointer: {
|
|
|
|
unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
|
2008-04-07 15:01:58 +08:00
|
|
|
Width = Target.getPointerWidth(AS);
|
2008-03-08 16:34:58 +08:00
|
|
|
Align = Target.getPointerAlign(AS);
|
|
|
|
break;
|
|
|
|
}
|
2009-03-17 07:22:08 +08:00
|
|
|
case Type::LValueReference:
|
|
|
|
case Type::RValueReference:
|
2007-07-14 06:16:13 +08:00
|
|
|
// "When applied to a reference or a reference type, the result is the size
|
2007-07-19 02:26:58 +08:00
|
|
|
// of the referenced type." C++98 5.3.3p2: expr.sizeof.
|
2007-12-20 03:23:28 +08:00
|
|
|
// FIXME: This is wrong for struct layout: a reference in a struct has
|
|
|
|
// pointer size.
|
2008-04-03 01:35:06 +08:00
|
|
|
return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
|
2009-01-25 05:16:55 +08:00
|
|
|
case Type::MemberPointer: {
|
2009-05-17 10:06:04 +08:00
|
|
|
// FIXME: This is ABI dependent. We use the Itanium C++ ABI.
|
|
|
|
// http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
|
|
|
|
// If we ever want to support other ABIs this needs to be abstracted.
|
|
|
|
|
2009-01-25 05:16:55 +08:00
|
|
|
QualType Pointee = cast<MemberPointerType>(T)->getPointeeType();
|
2009-09-09 23:08:12 +08:00
|
|
|
std::pair<uint64_t, unsigned> PtrDiffInfo =
|
2009-05-17 10:06:04 +08:00
|
|
|
getTypeInfo(getPointerDiffType());
|
|
|
|
Width = PtrDiffInfo.first;
|
2009-01-25 05:16:55 +08:00
|
|
|
if (Pointee->isFunctionType())
|
|
|
|
Width *= 2;
|
2009-05-17 10:06:04 +08:00
|
|
|
Align = PtrDiffInfo.second;
|
|
|
|
break;
|
2009-01-25 05:16:55 +08:00
|
|
|
}
|
2007-07-19 02:26:58 +08:00
|
|
|
case Type::Complex: {
|
|
|
|
// Complex types have the same alignment as their elements, but twice the
|
|
|
|
// size.
|
2009-09-09 23:08:12 +08:00
|
|
|
std::pair<uint64_t, unsigned> EltInfo =
|
2008-03-06 02:54:05 +08:00
|
|
|
getTypeInfo(cast<ComplexType>(T)->getElementType());
|
2008-03-08 16:52:55 +08:00
|
|
|
Width = EltInfo.first*2;
|
2007-07-19 02:26:58 +08:00
|
|
|
Align = EltInfo.second;
|
|
|
|
break;
|
|
|
|
}
|
2008-06-05 05:54:36 +08:00
|
|
|
case Type::ObjCInterface: {
|
2008-11-08 13:48:37 +08:00
|
|
|
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
|
2008-06-05 05:54:36 +08:00
|
|
|
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
|
|
|
|
Width = Layout.getSize();
|
|
|
|
Align = Layout.getAlignment();
|
|
|
|
break;
|
|
|
|
}
|
2009-02-27 07:50:07 +08:00
|
|
|
case Type::Record:
|
|
|
|
case Type::Enum: {
|
2008-11-08 13:48:37 +08:00
|
|
|
const TagType *TT = cast<TagType>(T);
|
|
|
|
|
|
|
|
if (TT->getDecl()->isInvalidDecl()) {
|
2008-08-10 05:35:13 +08:00
|
|
|
Width = 1;
|
|
|
|
Align = 1;
|
|
|
|
break;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-11-08 13:48:37 +08:00
|
|
|
if (const EnumType *ET = dyn_cast<EnumType>(TT))
|
2008-04-07 06:05:18 +08:00
|
|
|
return getTypeInfo(ET->getDecl()->getIntegerType());
|
|
|
|
|
2008-11-08 13:48:37 +08:00
|
|
|
const RecordType *RT = cast<RecordType>(TT);
|
2008-04-07 06:05:18 +08:00
|
|
|
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl());
|
|
|
|
Width = Layout.getSize();
|
|
|
|
Align = Layout.getAlignment();
|
2007-07-24 06:46:22 +08:00
|
|
|
break;
|
2007-07-14 06:13:22 +08:00
|
|
|
}
|
2009-03-31 06:58:21 +08:00
|
|
|
|
2009-10-18 17:09:24 +08:00
|
|
|
case Type::SubstTemplateTypeParm: {
|
|
|
|
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
|
|
|
|
getReplacementType().getTypePtr());
|
|
|
|
}
|
|
|
|
|
2009-09-05 08:15:47 +08:00
|
|
|
case Type::Elaborated: {
|
|
|
|
return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr());
|
|
|
|
}
|
|
|
|
|
2009-05-01 01:32:17 +08:00
|
|
|
case Type::Typedef: {
|
|
|
|
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
|
2009-06-30 10:34:44 +08:00
|
|
|
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
|
2009-05-01 01:32:17 +08:00
|
|
|
Align = Aligned->getAlignment();
|
|
|
|
Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr());
|
|
|
|
} else
|
|
|
|
return getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
|
2009-03-31 06:58:21 +08:00
|
|
|
break;
|
2008-04-07 06:05:18 +08:00
|
|
|
}
|
2009-05-01 01:32:17 +08:00
|
|
|
|
|
|
|
case Type::TypeOfExpr:
|
|
|
|
return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType()
|
|
|
|
.getTypePtr());
|
|
|
|
|
|
|
|
case Type::TypeOf:
|
|
|
|
return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
|
|
|
|
|
2009-06-25 03:06:50 +08:00
|
|
|
case Type::Decltype:
|
|
|
|
return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
|
|
|
|
.getTypePtr());
|
|
|
|
|
2009-05-01 01:32:17 +08:00
|
|
|
case Type::QualifiedName:
|
|
|
|
return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-01 01:32:17 +08:00
|
|
|
case Type::TemplateSpecialization:
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(getCanonicalType(T) != T &&
|
2009-05-01 01:32:17 +08:00
|
|
|
"Cannot request the size of a dependent type");
|
|
|
|
// FIXME: this is likely to be wrong once we support template
|
|
|
|
// aliases, since a template alias could refer to a typedef that
|
|
|
|
// has an __aligned__ attribute on it.
|
|
|
|
return getTypeInfo(getCanonicalType(T));
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-19 01:52:12 +08:00
|
|
|
assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
|
2008-03-08 16:52:55 +08:00
|
|
|
return std::make_pair(Width, Align);
|
2007-07-14 06:13:22 +08:00
|
|
|
}
|
|
|
|
|
2009-01-28 02:08:34 +08:00
|
|
|
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
|
|
|
|
/// type for the current target in bits. This can be different than the ABI
|
|
|
|
/// alignment in cases where it is beneficial for performance to overalign
|
|
|
|
/// a data type.
|
|
|
|
unsigned ASTContext::getPreferredTypeAlign(const Type *T) {
|
|
|
|
unsigned ABIAlign = getTypeAlign(T);
|
2009-05-26 05:27:19 +08:00
|
|
|
|
|
|
|
// Double and long long should be naturally aligned if possible.
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ComplexType* CT = T->getAs<ComplexType>())
|
2009-05-26 05:27:19 +08:00
|
|
|
T = CT->getElementType().getTypePtr();
|
|
|
|
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
|
|
|
|
T->isSpecificBuiltinType(BuiltinType::LongLong))
|
|
|
|
return std::max(ABIAlign, (unsigned)getTypeSize(T));
|
|
|
|
|
2009-01-28 02:08:34 +08:00
|
|
|
return ABIAlign;
|
|
|
|
}
|
|
|
|
|
2009-04-23 01:43:55 +08:00
|
|
|
static void CollectLocalObjCIvars(ASTContext *Ctx,
|
|
|
|
const ObjCInterfaceDecl *OI,
|
|
|
|
llvm::SmallVectorImpl<FieldDecl*> &Fields) {
|
2008-12-18 05:40:49 +08:00
|
|
|
for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
|
|
|
|
E = OI->ivar_end(); I != E; ++I) {
|
2009-03-31 16:48:01 +08:00
|
|
|
ObjCIvarDecl *IVDecl = *I;
|
2008-12-18 05:40:49 +08:00
|
|
|
if (!IVDecl->isInvalidDecl())
|
|
|
|
Fields.push_back(cast<FieldDecl>(IVDecl));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-23 01:43:55 +08:00
|
|
|
void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI,
|
|
|
|
llvm::SmallVectorImpl<FieldDecl*> &Fields) {
|
|
|
|
if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass())
|
|
|
|
CollectObjCIvars(SuperClass, Fields);
|
|
|
|
CollectLocalObjCIvars(this, OI, Fields);
|
|
|
|
}
|
|
|
|
|
2009-06-04 09:19:09 +08:00
|
|
|
/// ShallowCollectObjCIvars -
|
|
|
|
/// Collect all ivars, including those synthesized, in the current class.
|
|
|
|
///
|
|
|
|
void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
|
|
|
|
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars,
|
|
|
|
bool CollectSynthesized) {
|
|
|
|
for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(),
|
|
|
|
E = OI->ivar_end(); I != E; ++I) {
|
|
|
|
Ivars.push_back(*I);
|
|
|
|
}
|
|
|
|
if (CollectSynthesized)
|
|
|
|
CollectSynthesizedIvars(OI, Ivars);
|
|
|
|
}
|
|
|
|
|
2009-05-13 02:14:29 +08:00
|
|
|
void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD,
|
|
|
|
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
|
2009-06-30 10:36:12 +08:00
|
|
|
for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
|
|
|
|
E = PD->prop_end(); I != E; ++I)
|
2009-05-13 02:14:29 +08:00
|
|
|
if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
|
|
|
|
Ivars.push_back(Ivar);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-13 02:14:29 +08:00
|
|
|
// Also look into nested protocols.
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
|
|
|
|
E = PD->protocol_end(); P != E; ++P)
|
|
|
|
CollectProtocolSynthesizedIvars(*P, Ivars);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CollectSynthesizedIvars -
|
|
|
|
/// This routine collect synthesized ivars for the designated class.
|
|
|
|
///
|
|
|
|
void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI,
|
|
|
|
llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
|
2009-06-30 10:36:12 +08:00
|
|
|
for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
|
|
|
|
E = OI->prop_end(); I != E; ++I) {
|
2009-05-13 02:14:29 +08:00
|
|
|
if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl())
|
|
|
|
Ivars.push_back(Ivar);
|
|
|
|
}
|
|
|
|
// Also look into interface's protocol list for properties declared
|
|
|
|
// in the protocol and whose ivars are synthesized.
|
|
|
|
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
|
|
|
|
PE = OI->protocol_end(); P != PE; ++P) {
|
|
|
|
ObjCProtocolDecl *PD = (*P);
|
|
|
|
CollectProtocolSynthesizedIvars(PD, Ivars);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-04 09:19:09 +08:00
|
|
|
unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) {
|
|
|
|
unsigned count = 0;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(),
|
|
|
|
E = PD->prop_end(); I != E; ++I)
|
2009-06-04 09:19:09 +08:00
|
|
|
if ((*I)->getPropertyIvarDecl())
|
|
|
|
++count;
|
|
|
|
|
|
|
|
// Also look into nested protocols.
|
|
|
|
for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(),
|
|
|
|
E = PD->protocol_end(); P != E; ++P)
|
|
|
|
count += CountProtocolSynthesizedIvars(*P);
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) {
|
2009-06-04 09:19:09 +08:00
|
|
|
unsigned count = 0;
|
2009-06-30 10:36:12 +08:00
|
|
|
for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(),
|
|
|
|
E = OI->prop_end(); I != E; ++I) {
|
2009-06-04 09:19:09 +08:00
|
|
|
if ((*I)->getPropertyIvarDecl())
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
// Also look into interface's protocol list for properties declared
|
|
|
|
// in the protocol and whose ivars are synthesized.
|
|
|
|
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
|
|
|
|
PE = OI->protocol_end(); P != PE; ++P) {
|
|
|
|
ObjCProtocolDecl *PD = (*P);
|
|
|
|
count += CountProtocolSynthesizedIvars(PD);
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2009-07-21 08:05:53 +08:00
|
|
|
/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists.
|
|
|
|
ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) {
|
|
|
|
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator
|
|
|
|
I = ObjCImpls.find(D);
|
|
|
|
if (I != ObjCImpls.end())
|
|
|
|
return cast<ObjCImplementationDecl>(I->second);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists.
|
|
|
|
ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) {
|
|
|
|
llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator
|
|
|
|
I = ObjCImpls.find(D);
|
|
|
|
if (I != ObjCImpls.end())
|
|
|
|
return cast<ObjCCategoryImplDecl>(I->second);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Set the implementation of ObjCInterfaceDecl.
|
|
|
|
void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD,
|
|
|
|
ObjCImplementationDecl *ImplD) {
|
|
|
|
assert(IFaceD && ImplD && "Passed null params");
|
|
|
|
ObjCImpls[IFaceD] = ImplD;
|
|
|
|
}
|
|
|
|
/// \brief Set the implementation of ObjCCategoryDecl.
|
|
|
|
void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
|
|
|
|
ObjCCategoryImplDecl *ImplD) {
|
|
|
|
assert(CatD && ImplD && "Passed null params");
|
|
|
|
ObjCImpls[CatD] = ImplD;
|
|
|
|
}
|
|
|
|
|
2009-08-19 09:27:32 +08:00
|
|
|
/// \brief Allocate an uninitialized DeclaratorInfo.
|
|
|
|
///
|
|
|
|
/// The caller should initialize the memory held by DeclaratorInfo using
|
|
|
|
/// the TypeLoc wrappers.
|
|
|
|
///
|
|
|
|
/// \param T the type that will be the basis for type source info. This type
|
|
|
|
/// should refer to how the declarator was written in source code, not to
|
|
|
|
/// what type semantic analysis resolved the declarator to.
|
|
|
|
DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) {
|
|
|
|
unsigned DataSize = TypeLoc::getFullDataSizeForType(T);
|
|
|
|
DeclaratorInfo *DInfo =
|
|
|
|
(DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8);
|
|
|
|
new (DInfo) DeclaratorInfo(T);
|
|
|
|
return DInfo;
|
|
|
|
}
|
|
|
|
|
2009-05-03 18:38:35 +08:00
|
|
|
/// getInterfaceLayoutImpl - Get or compute information about the
|
|
|
|
/// layout of the given interface.
|
|
|
|
///
|
|
|
|
/// \param Impl - If given, also include the layout of the interface's
|
|
|
|
/// implementation. This may differ by including synthesized ivars.
|
2008-06-05 05:54:36 +08:00
|
|
|
const ASTRecordLayout &
|
2009-05-03 18:38:35 +08:00
|
|
|
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
|
|
|
|
const ObjCImplementationDecl *Impl) {
|
2009-05-03 21:15:50 +08:00
|
|
|
assert(!D->isForwardDecl() && "Invalid interface decl!");
|
|
|
|
|
2008-06-05 05:54:36 +08:00
|
|
|
// Look up this layout, if already laid out, return what we have.
|
2009-09-09 23:08:12 +08:00
|
|
|
ObjCContainerDecl *Key =
|
2009-05-03 19:41:43 +08:00
|
|
|
Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D;
|
|
|
|
if (const ASTRecordLayout *Entry = ObjCLayouts[Key])
|
|
|
|
return *Entry;
|
2008-06-05 05:54:36 +08:00
|
|
|
|
2009-05-03 19:16:44 +08:00
|
|
|
// Add in synthesized ivar count if laying out an implementation.
|
|
|
|
if (Impl) {
|
2009-07-19 05:19:52 +08:00
|
|
|
unsigned FieldCount = D->ivar_size();
|
2009-06-04 09:19:09 +08:00
|
|
|
unsigned SynthCount = CountSynthesizedIvars(D);
|
|
|
|
FieldCount += SynthCount;
|
2009-05-03 19:41:43 +08:00
|
|
|
// If there aren't any sythesized ivars then reuse the interface
|
2009-05-03 19:16:44 +08:00
|
|
|
// entry. Note we can't cache this because we simply free all
|
|
|
|
// entries later; however we shouldn't look up implementations
|
|
|
|
// frequently.
|
2009-06-04 09:19:09 +08:00
|
|
|
if (SynthCount == 0)
|
2009-05-03 19:16:44 +08:00
|
|
|
return getObjCLayout(D, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
const ASTRecordLayout *NewEntry =
|
2009-07-19 05:19:52 +08:00
|
|
|
ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl);
|
|
|
|
ObjCLayouts[Key] = NewEntry;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-06-05 05:54:36 +08:00
|
|
|
return *NewEntry;
|
|
|
|
}
|
|
|
|
|
2009-05-03 18:38:35 +08:00
|
|
|
const ASTRecordLayout &
|
|
|
|
ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) {
|
|
|
|
return getObjCLayout(D, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ASTRecordLayout &
|
|
|
|
ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
|
|
|
|
return getObjCLayout(D->getClassInterface(), D);
|
|
|
|
}
|
|
|
|
|
2007-11-02 03:11:01 +08:00
|
|
|
/// getASTRecordLayout - Get or compute information about the layout of the
|
2007-07-19 01:52:12 +08:00
|
|
|
/// specified record (struct/union/class), which indicates its size and field
|
|
|
|
/// position information.
|
2008-03-06 02:54:05 +08:00
|
|
|
const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
D = D->getDefinition(*this);
|
|
|
|
assert(D && "Cannot get layout of forward declarations!");
|
2008-05-30 17:31:38 +08:00
|
|
|
|
2007-07-19 01:52:12 +08:00
|
|
|
// Look up this layout, if already laid out, return what we have.
|
2009-07-23 04:29:16 +08:00
|
|
|
// Note that we can't save a reference to the entry because this function
|
|
|
|
// is recursive.
|
|
|
|
const ASTRecordLayout *Entry = ASTRecordLayouts[D];
|
2007-07-19 01:52:12 +08:00
|
|
|
if (Entry) return *Entry;
|
2008-05-30 17:31:38 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
const ASTRecordLayout *NewEntry =
|
2009-07-19 05:19:52 +08:00
|
|
|
ASTRecordLayoutBuilder::ComputeLayout(*this, D);
|
2009-07-23 04:29:16 +08:00
|
|
|
ASTRecordLayouts[D] = NewEntry;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-19 02:26:58 +08:00
|
|
|
return *NewEntry;
|
2007-07-19 01:52:12 +08:00
|
|
|
}
|
|
|
|
|
2007-07-14 06:13:22 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type creation/memoization methods
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) {
|
|
|
|
unsigned Fast = Quals.getFastQualifiers();
|
|
|
|
Quals.removeFastQualifiers();
|
|
|
|
|
|
|
|
// Check if we've already instantiated this type.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ExtQuals::Profile(ID, TypeNode, Quals);
|
|
|
|
void *InsertPos = 0;
|
|
|
|
if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) {
|
|
|
|
assert(EQ->getQualifiers() == Quals);
|
|
|
|
QualType T = QualType(EQ, Fast);
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals);
|
2009-09-25 03:53:00 +08:00
|
|
|
ExtQualNodes.InsertNode(New, InsertPos);
|
|
|
|
QualType T = QualType(New, Fast);
|
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTContext::getVolatileType(QualType T) {
|
|
|
|
QualType CanT = getCanonicalType(T);
|
|
|
|
if (CanT.isVolatileQualified()) return T;
|
|
|
|
|
|
|
|
QualifierCollector Quals;
|
|
|
|
const Type *TypeNode = Quals.strip(T);
|
|
|
|
Quals.addVolatile();
|
|
|
|
|
|
|
|
return getExtQualType(TypeNode, Quals);
|
|
|
|
}
|
|
|
|
|
2009-02-18 02:27:45 +08:00
|
|
|
QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
|
2008-04-07 06:59:24 +08:00
|
|
|
QualType CanT = getCanonicalType(T);
|
|
|
|
if (CanT.getAddressSpace() == AddressSpace)
|
2008-02-21 04:55:12 +08:00
|
|
|
return T;
|
2009-02-19 06:53:11 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If we are composing extended qualifiers together, merge together
|
|
|
|
// into one ExtQuals node.
|
|
|
|
QualifierCollector Quals;
|
|
|
|
const Type *TypeNode = Quals.strip(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If this type already has an address space specified, it cannot get
|
|
|
|
// another one.
|
|
|
|
assert(!Quals.hasAddressSpace() &&
|
|
|
|
"Type cannot be in multiple addr spaces!");
|
|
|
|
Quals.addAddressSpace(AddressSpace);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
return getExtQualType(TypeNode, Quals);
|
2008-02-04 10:31:56 +08:00
|
|
|
}
|
|
|
|
|
2009-02-19 06:53:11 +08:00
|
|
|
QualType ASTContext::getObjCGCQualType(QualType T,
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers::GC GCAttr) {
|
2009-02-18 13:09:49 +08:00
|
|
|
QualType CanT = getCanonicalType(T);
|
2009-02-19 06:53:11 +08:00
|
|
|
if (CanT.getObjCGCAttr() == GCAttr)
|
2009-02-18 13:09:49 +08:00
|
|
|
return T;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-04 01:15:17 +08:00
|
|
|
if (T->isPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType Pointee = T->getAs<PointerType>()->getPointeeType();
|
2009-07-15 02:25:06 +08:00
|
|
|
if (Pointee->isAnyPointerType()) {
|
2009-06-04 01:15:17 +08:00
|
|
|
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
|
|
|
|
return getPointerType(ResultType);
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If we are composing extended qualifiers together, merge together
|
|
|
|
// into one ExtQuals node.
|
|
|
|
QualifierCollector Quals;
|
|
|
|
const Type *TypeNode = Quals.strip(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If this type already has an ObjCGC specified, it cannot get
|
|
|
|
// another one.
|
|
|
|
assert(!Quals.hasObjCGCAttr() &&
|
|
|
|
"Type cannot have multiple ObjCGCs!");
|
|
|
|
Quals.addObjCGCAttr(GCAttr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
return getExtQualType(TypeNode, Quals);
|
2009-02-18 13:09:49 +08:00
|
|
|
}
|
2007-07-14 06:13:22 +08:00
|
|
|
|
2009-07-26 05:26:53 +08:00
|
|
|
QualType ASTContext::getNoReturnType(QualType T) {
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType ResultType;
|
2009-07-26 05:26:53 +08:00
|
|
|
if (T->isPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType Pointee = T->getAs<PointerType>()->getPointeeType();
|
2009-09-25 03:53:00 +08:00
|
|
|
ResultType = getNoReturnType(Pointee);
|
2009-07-26 07:24:03 +08:00
|
|
|
ResultType = getPointerType(ResultType);
|
2009-09-25 03:53:00 +08:00
|
|
|
} else if (T->isBlockPointerType()) {
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType();
|
2009-09-25 03:53:00 +08:00
|
|
|
ResultType = getNoReturnType(Pointee);
|
2009-07-26 07:24:03 +08:00
|
|
|
ResultType = getBlockPointerType(ResultType);
|
2009-09-25 03:53:00 +08:00
|
|
|
} else {
|
|
|
|
assert (T->isFunctionType()
|
|
|
|
&& "can't noreturn qualify non-pointer to function or block type");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 19:47:22 +08:00
|
|
|
if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) {
|
|
|
|
ResultType = getFunctionNoProtoType(FNPT->getResultType(), true);
|
2009-09-25 03:53:00 +08:00
|
|
|
} else {
|
|
|
|
const FunctionProtoType *F = T->getAs<FunctionProtoType>();
|
|
|
|
ResultType
|
|
|
|
= getFunctionType(F->getResultType(), F->arg_type_begin(),
|
|
|
|
F->getNumArgs(), F->isVariadic(), F->getTypeQuals(),
|
|
|
|
F->hasExceptionSpec(), F->hasAnyExceptionSpec(),
|
|
|
|
F->getNumExceptions(), F->exception_begin(), true);
|
|
|
|
}
|
2009-07-26 05:26:53 +08:00
|
|
|
}
|
2009-09-25 03:53:00 +08:00
|
|
|
|
|
|
|
return getQualifiedType(ResultType, T.getQualifiers());
|
2009-07-26 05:26:53 +08:00
|
|
|
}
|
|
|
|
|
2007-06-23 04:56:16 +08:00
|
|
|
/// getComplexType - Return the uniqued reference to the type for a complex
|
|
|
|
/// number with the specified element type.
|
|
|
|
QualType ASTContext::getComplexType(QualType T) {
|
|
|
|
// Unique pointers, to guarantee there is only one pointer of a particular
|
|
|
|
// structure.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ComplexType::Profile(ID, T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-23 04:56:16 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(CT, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-23 04:56:16 +08:00
|
|
|
// If the pointee type isn't canonical, this won't be a canonical type either,
|
|
|
|
// so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!T->isCanonical()) {
|
2008-04-07 06:59:24 +08:00
|
|
|
Canonical = getComplexType(getCanonicalType(T));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-23 04:56:16 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-06-23 04:56:16 +08:00
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical);
|
2007-06-23 04:56:16 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
ComplexTypes.InsertNode(New, InsertPos);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-02-13 10:31:07 +08:00
|
|
|
QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) {
|
|
|
|
llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ?
|
|
|
|
SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes;
|
|
|
|
FixedWidthIntType *&Entry = Map[Width];
|
|
|
|
if (!Entry)
|
|
|
|
Entry = new FixedWidthIntType(Width, Signed);
|
|
|
|
return QualType(Entry, 0);
|
|
|
|
}
|
2007-06-23 04:56:16 +08:00
|
|
|
|
2006-11-12 08:37:36 +08:00
|
|
|
/// getPointerType - Return the uniqued reference to the type for a pointer to
|
|
|
|
/// the specified type.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType ASTContext::getPointerType(QualType T) {
|
2006-11-12 08:53:46 +08:00
|
|
|
// Unique pointers, to guarantee there is only one pointer of a particular
|
|
|
|
// structure.
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2007-01-27 09:29:36 +08:00
|
|
|
PointerType::Profile(ID, T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-27 09:29:36 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(PT, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 16:50:50 +08:00
|
|
|
// If the pointee type isn't canonical, this won't be a canonical type either,
|
|
|
|
// so fill in the canonical type field.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType Canonical;
|
2007-01-27 09:29:36 +08:00
|
|
|
if (!T->isCanonical()) {
|
2008-04-07 06:59:24 +08:00
|
|
|
Canonical = getPointerType(getCanonicalType(T));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-27 09:29:36 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-01-27 09:29:36 +08:00
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical);
|
2007-01-27 09:29:36 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
PointerTypes.InsertNode(New, InsertPos);
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(New, 0);
|
2006-11-10 14:34:16 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// getBlockPointerType - Return the uniqued reference to the type for
|
2008-08-28 00:04:49 +08:00
|
|
|
/// a pointer to the specified block.
|
|
|
|
QualType ASTContext::getBlockPointerType(QualType T) {
|
2008-08-29 03:20:44 +08:00
|
|
|
assert(T->isFunctionType() && "block of function types only");
|
|
|
|
// Unique pointers, to guarantee there is only one block of a particular
|
2008-08-28 00:04:49 +08:00
|
|
|
// structure.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
BlockPointerType::Profile(ID, T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 00:04:49 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
if (BlockPointerType *PT =
|
|
|
|
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(PT, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// If the block pointee type isn't canonical, this won't be a canonical
|
2008-08-28 00:04:49 +08:00
|
|
|
// type either so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!T->isCanonical()) {
|
|
|
|
Canonical = getBlockPointerType(getCanonicalType(T));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 00:04:49 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
BlockPointerType *NewIP =
|
|
|
|
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2008-08-28 00:04:49 +08:00
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
BlockPointerType *New
|
|
|
|
= new (*this, TypeAlignment) BlockPointerType(T, Canonical);
|
2008-08-28 00:04:49 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
BlockPointerTypes.InsertNode(New, InsertPos);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-03-17 07:22:08 +08:00
|
|
|
/// getLValueReferenceType - Return the uniqued reference to the type for an
|
|
|
|
/// lvalue reference to the specified type.
|
|
|
|
QualType ASTContext::getLValueReferenceType(QualType T) {
|
2007-05-27 18:15:43 +08:00
|
|
|
// Unique pointers, to guarantee there is only one pointer of a particular
|
|
|
|
// structure.
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2007-05-27 18:15:43 +08:00
|
|
|
ReferenceType::Profile(ID, T);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-03-17 07:22:08 +08:00
|
|
|
if (LValueReferenceType *RT =
|
|
|
|
LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-05-27 18:15:43 +08:00
|
|
|
return QualType(RT, 0);
|
2009-03-17 07:22:08 +08:00
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
// If the referencee type isn't canonical, this won't be a canonical type
|
|
|
|
// either, so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!T->isCanonical()) {
|
2009-03-17 07:22:08 +08:00
|
|
|
Canonical = getLValueReferenceType(getCanonicalType(T));
|
|
|
|
|
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
LValueReferenceType *NewIP =
|
|
|
|
LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
|
|
|
}
|
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
LValueReferenceType *New
|
|
|
|
= new (*this, TypeAlignment) LValueReferenceType(T, Canonical);
|
2009-03-17 07:22:08 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
LValueReferenceTypes.InsertNode(New, InsertPos);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getRValueReferenceType - Return the uniqued reference to the type for an
|
|
|
|
/// rvalue reference to the specified type.
|
|
|
|
QualType ASTContext::getRValueReferenceType(QualType T) {
|
|
|
|
// Unique pointers, to guarantee there is only one pointer of a particular
|
|
|
|
// structure.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ReferenceType::Profile(ID, T);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
if (RValueReferenceType *RT =
|
|
|
|
RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(RT, 0);
|
|
|
|
|
|
|
|
// If the referencee type isn't canonical, this won't be a canonical type
|
|
|
|
// either, so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!T->isCanonical()) {
|
|
|
|
Canonical = getRValueReferenceType(getCanonicalType(T));
|
|
|
|
|
2007-05-27 18:15:43 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
2009-03-17 07:22:08 +08:00
|
|
|
RValueReferenceType *NewIP =
|
|
|
|
RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-05-27 18:15:43 +08:00
|
|
|
}
|
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
RValueReferenceType *New
|
|
|
|
= new (*this, TypeAlignment) RValueReferenceType(T, Canonical);
|
2007-05-27 18:15:43 +08:00
|
|
|
Types.push_back(New);
|
2009-03-17 07:22:08 +08:00
|
|
|
RValueReferenceTypes.InsertNode(New, InsertPos);
|
2007-05-27 18:15:43 +08:00
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-01-25 05:16:55 +08:00
|
|
|
/// getMemberPointerType - Return the uniqued reference to the type for a
|
|
|
|
/// member pointer to the specified type, in the specified class.
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) {
|
2009-01-25 05:16:55 +08:00
|
|
|
// Unique pointers, to guarantee there is only one pointer of a particular
|
|
|
|
// structure.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
MemberPointerType::Profile(ID, T, Cls);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
if (MemberPointerType *PT =
|
|
|
|
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(PT, 0);
|
|
|
|
|
|
|
|
// If the pointee or class type isn't canonical, this won't be a canonical
|
|
|
|
// type either, so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!T->isCanonical()) {
|
|
|
|
Canonical = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls));
|
|
|
|
|
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
MemberPointerType *NewIP =
|
|
|
|
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
MemberPointerType *New
|
|
|
|
= new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical);
|
2009-01-25 05:16:55 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
MemberPointerTypes.InsertNode(New, InsertPos);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// getConstantArrayType - Return the unique reference to the type for an
|
2007-08-30 09:06:46 +08:00
|
|
|
/// array of the specified element type.
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getConstantArrayType(QualType EltTy,
|
2009-05-13 12:12:56 +08:00
|
|
|
const llvm::APInt &ArySizeIn,
|
2007-08-31 02:10:14 +08:00
|
|
|
ArrayType::ArraySizeModifier ASM,
|
|
|
|
unsigned EltTypeQuals) {
|
2009-05-30 04:17:55 +08:00
|
|
|
assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) &&
|
|
|
|
"Constant array of VLAs is illegal!");
|
|
|
|
|
2009-05-13 12:12:56 +08:00
|
|
|
// Convert the array size into a canonical width matching the pointer size for
|
|
|
|
// the target.
|
|
|
|
llvm::APInt ArySize(ArySizeIn);
|
|
|
|
ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-02-20 01:31:02 +08:00
|
|
|
ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-27 16:31:04 +08:00
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (ConstantArrayType *ATP =
|
2007-11-01 01:10:13 +08:00
|
|
|
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(ATP, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-11-12 16:50:50 +08:00
|
|
|
// If the element type isn't canonical, this won't be a canonical type either,
|
|
|
|
// so fill in the canonical type field.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType Canonical;
|
2007-01-27 16:31:04 +08:00
|
|
|
if (!EltTy->isCanonical()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize,
|
2007-08-31 02:10:14 +08:00
|
|
|
ASM, EltTypeQuals);
|
2007-01-27 16:31:04 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
2009-09-09 23:08:12 +08:00
|
|
|
ConstantArrayType *NewIP =
|
2007-11-01 01:10:13 +08:00
|
|
|
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-01-27 16:31:04 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
ConstantArrayType *New = new(*this,TypeAlignment)
|
|
|
|
ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
|
2007-11-01 01:10:13 +08:00
|
|
|
ConstantArrayTypes.InsertNode(New, InsertPos);
|
2007-01-27 16:31:04 +08:00
|
|
|
Types.push_back(New);
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(New, 0);
|
2006-11-12 16:50:50 +08:00
|
|
|
}
|
|
|
|
|
2007-08-31 02:14:25 +08:00
|
|
|
/// getVariableArrayType - Returns a non-unique reference to the type for a
|
|
|
|
/// variable array of the specified element type.
|
2009-07-06 23:59:29 +08:00
|
|
|
QualType ASTContext::getVariableArrayType(QualType EltTy,
|
|
|
|
Expr *NumElts,
|
2007-08-31 02:10:14 +08:00
|
|
|
ArrayType::ArraySizeModifier ASM,
|
2009-07-06 23:59:29 +08:00
|
|
|
unsigned EltTypeQuals,
|
|
|
|
SourceRange Brackets) {
|
2008-02-16 02:16:39 +08:00
|
|
|
// Since we don't unique expressions, it isn't possible to unique VLA's
|
|
|
|
// that have an expression provided for their size.
|
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
VariableArrayType *New = new(*this, TypeAlignment)
|
|
|
|
VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets);
|
2008-02-16 02:16:39 +08:00
|
|
|
|
|
|
|
VariableArrayTypes.push_back(New);
|
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
/// getDependentSizedArrayType - Returns a non-unique reference to
|
|
|
|
/// the type for a dependently-sized array of the specified element
|
2009-07-31 08:23:35 +08:00
|
|
|
/// type.
|
2009-07-06 23:59:29 +08:00
|
|
|
QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
|
|
|
|
Expr *NumElts,
|
2008-12-06 07:32:09 +08:00
|
|
|
ArrayType::ArraySizeModifier ASM,
|
2009-07-06 23:59:29 +08:00
|
|
|
unsigned EltTypeQuals,
|
|
|
|
SourceRange Brackets) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
|
2008-12-06 07:32:09 +08:00
|
|
|
"Size must be type- or value-dependent!");
|
|
|
|
|
2009-07-31 08:23:35 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-09-09 23:08:12 +08:00
|
|
|
DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
|
2009-07-31 08:23:35 +08:00
|
|
|
EltTypeQuals, NumElts);
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2009-07-31 08:23:35 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
DependentSizedArrayType *Canon
|
|
|
|
= DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
DependentSizedArrayType *New;
|
|
|
|
if (Canon) {
|
|
|
|
// We already have a canonical version of this array type; use it as
|
|
|
|
// the canonical type for a newly-built type.
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedArrayType(*this, EltTy, QualType(Canon, 0),
|
|
|
|
NumElts, ASM, EltTypeQuals, Brackets);
|
2009-07-31 08:23:35 +08:00
|
|
|
} else {
|
|
|
|
QualType CanonEltTy = getCanonicalType(EltTy);
|
|
|
|
if (CanonEltTy == EltTy) {
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedArrayType(*this, EltTy, QualType(),
|
|
|
|
NumElts, ASM, EltTypeQuals, Brackets);
|
2009-07-31 08:23:35 +08:00
|
|
|
DependentSizedArrayTypes.InsertNode(New, InsertPos);
|
|
|
|
} else {
|
|
|
|
QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
|
|
|
|
ASM, EltTypeQuals,
|
|
|
|
SourceRange());
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedArrayType(*this, EltTy, Canon,
|
|
|
|
NumElts, ASM, EltTypeQuals, Brackets);
|
2009-07-31 08:23:35 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2008-02-16 02:16:39 +08:00
|
|
|
QualType ASTContext::getIncompleteArrayType(QualType EltTy,
|
|
|
|
ArrayType::ArraySizeModifier ASM,
|
|
|
|
unsigned EltTypeQuals) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-02-20 01:31:02 +08:00
|
|
|
IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals);
|
2008-02-16 02:16:39 +08:00
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (IncompleteArrayType *ATP =
|
2008-02-16 02:16:39 +08:00
|
|
|
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(ATP, 0);
|
|
|
|
|
|
|
|
// If the element type isn't canonical, this won't be a canonical type
|
|
|
|
// either, so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
|
|
|
|
if (!EltTy->isCanonical()) {
|
2008-04-07 06:59:24 +08:00
|
|
|
Canonical = getIncompleteArrayType(getCanonicalType(EltTy),
|
2007-10-30 07:37:31 +08:00
|
|
|
ASM, EltTypeQuals);
|
2008-02-16 02:16:39 +08:00
|
|
|
|
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
IncompleteArrayType *NewIP =
|
|
|
|
IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-10-30 07:37:31 +08:00
|
|
|
}
|
2008-02-16 02:16:39 +08:00
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
IncompleteArrayType *New = new (*this, TypeAlignment)
|
|
|
|
IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals);
|
2008-02-16 02:16:39 +08:00
|
|
|
|
|
|
|
IncompleteArrayTypes.InsertNode(New, InsertPos);
|
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
2007-08-30 09:06:46 +08:00
|
|
|
}
|
|
|
|
|
2007-07-19 02:00:27 +08:00
|
|
|
/// getVectorType - Return the unique reference to a vector type of
|
|
|
|
/// the specified element type and size. VectorType must be a built-in type.
|
|
|
|
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) {
|
2007-07-07 07:09:18 +08:00
|
|
|
BuiltinType *baseType;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
|
2007-07-19 02:00:27 +08:00
|
|
|
assert(baseType != 0 && "getVectorType(): Expecting a built-in type");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-07 07:09:18 +08:00
|
|
|
// Check if we've already instantiated a vector of this type.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-09-09 23:08:12 +08:00
|
|
|
VectorType::Profile(ID, vecType, NumElts, Type::Vector);
|
2007-07-07 07:09:18 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(VTP, 0);
|
|
|
|
|
|
|
|
// If the element type isn't canonical, this won't be a canonical type either,
|
|
|
|
// so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!vecType->isCanonical()) {
|
2008-04-07 06:59:24 +08:00
|
|
|
Canonical = getVectorType(getCanonicalType(vecType), NumElts);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-07 07:09:18 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-07-07 07:09:18 +08:00
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
VectorType *New = new (*this, TypeAlignment)
|
|
|
|
VectorType(vecType, NumElts, Canonical);
|
2007-07-07 07:09:18 +08:00
|
|
|
VectorTypes.InsertNode(New, InsertPos);
|
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2008-04-19 07:10:10 +08:00
|
|
|
/// getExtVectorType - Return the unique reference to an extended vector type of
|
2007-07-19 02:00:27 +08:00
|
|
|
/// the specified element type and size. VectorType must be a built-in type.
|
2008-04-19 07:10:10 +08:00
|
|
|
QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
|
2007-07-19 02:00:27 +08:00
|
|
|
BuiltinType *baseType;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
|
2008-04-19 07:10:10 +08:00
|
|
|
assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-19 02:00:27 +08:00
|
|
|
// Check if we've already instantiated a vector of this type.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-09-09 23:08:12 +08:00
|
|
|
VectorType::Profile(ID, vecType, NumElts, Type::ExtVector);
|
2007-07-19 02:00:27 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(VTP, 0);
|
|
|
|
|
|
|
|
// If the element type isn't canonical, this won't be a canonical type either,
|
|
|
|
// so fill in the canonical type field.
|
|
|
|
QualType Canonical;
|
|
|
|
if (!vecType->isCanonical()) {
|
2008-04-19 07:10:10 +08:00
|
|
|
Canonical = getExtVectorType(getCanonicalType(vecType), NumElts);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-07-19 02:00:27 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
|
|
|
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-07-19 02:00:27 +08:00
|
|
|
}
|
2009-09-25 07:30:46 +08:00
|
|
|
ExtVectorType *New = new (*this, TypeAlignment)
|
|
|
|
ExtVectorType(vecType, NumElts, Canonical);
|
2007-07-19 02:00:27 +08:00
|
|
|
VectorTypes.InsertNode(New, InsertPos);
|
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
|
2009-06-18 05:51:59 +08:00
|
|
|
Expr *SizeExpr,
|
|
|
|
SourceLocation AttrLoc) {
|
2009-07-31 11:54:25 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-09-09 23:08:12 +08:00
|
|
|
DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType),
|
2009-07-31 11:54:25 +08:00
|
|
|
SizeExpr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 11:54:25 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
DependentSizedExtVectorType *Canon
|
|
|
|
= DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
DependentSizedExtVectorType *New;
|
|
|
|
if (Canon) {
|
|
|
|
// We already have a canonical version of this array type; use it as
|
|
|
|
// the canonical type for a newly-built type.
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedExtVectorType(*this, vecType, QualType(Canon, 0),
|
|
|
|
SizeExpr, AttrLoc);
|
2009-07-31 11:54:25 +08:00
|
|
|
} else {
|
|
|
|
QualType CanonVecTy = getCanonicalType(vecType);
|
|
|
|
if (CanonVecTy == vecType) {
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr,
|
|
|
|
AttrLoc);
|
2009-07-31 11:54:25 +08:00
|
|
|
DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
|
|
|
|
} else {
|
|
|
|
QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
|
|
|
|
SourceLocation());
|
2009-09-25 07:30:46 +08:00
|
|
|
New = new (*this, TypeAlignment)
|
|
|
|
DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc);
|
2009-07-31 11:54:25 +08:00
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-18 05:51:59 +08:00
|
|
|
Types.push_back(New);
|
|
|
|
return QualType(New, 0);
|
|
|
|
}
|
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
|
2006-12-02 15:52:18 +08:00
|
|
|
///
|
2009-07-26 05:26:53 +08:00
|
|
|
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) {
|
2006-12-02 15:52:18 +08:00
|
|
|
// Unique functions, to guarantee there is only one function of a particular
|
|
|
|
// structure.
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-07-26 05:26:53 +08:00
|
|
|
FunctionNoProtoType::Profile(ID, ResultTy, NoReturn);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-27 16:37:20 +08:00
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (FunctionNoProtoType *FT =
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(FT, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType Canonical;
|
2007-01-27 16:37:20 +08:00
|
|
|
if (!ResultTy->isCanonical()) {
|
2009-07-26 05:26:53 +08:00
|
|
|
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-01-27 16:37:20 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionNoProtoType *NewIP =
|
|
|
|
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2007-01-27 16:37:20 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 07:30:46 +08:00
|
|
|
FunctionNoProtoType *New = new (*this, TypeAlignment)
|
|
|
|
FunctionNoProtoType(ResultTy, Canonical, NoReturn);
|
2007-01-27 16:37:20 +08:00
|
|
|
Types.push_back(New);
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionNoProtoTypes.InsertNode(New, InsertPos);
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(New, 0);
|
2006-12-02 15:52:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// getFunctionType - Return a normal function type with a typed argument
|
|
|
|
/// list. isVariadic indicates whether the argument list includes '...'.
|
2008-10-06 01:34:18 +08:00
|
|
|
QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
|
2008-10-25 05:46:40 +08:00
|
|
|
unsigned NumArgs, bool isVariadic,
|
2009-05-28 06:11:52 +08:00
|
|
|
unsigned TypeQuals, bool hasExceptionSpec,
|
|
|
|
bool hasAnyExceptionSpec, unsigned NumExs,
|
2009-07-26 05:26:53 +08:00
|
|
|
const QualType *ExArray, bool NoReturn) {
|
2009-09-17 07:47:08 +08:00
|
|
|
if (LangOpts.CPlusPlus) {
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i)
|
2009-09-25 03:53:00 +08:00
|
|
|
assert(!ArgArray[i].hasQualifiers() &&
|
|
|
|
"C++ arguments can't have toplevel qualifiers!");
|
2009-09-17 07:47:08 +08:00
|
|
|
}
|
|
|
|
|
2006-12-02 15:52:18 +08:00
|
|
|
// Unique functions, to guarantee there is only one function of a particular
|
|
|
|
// structure.
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
|
2009-05-28 06:11:52 +08:00
|
|
|
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
2009-07-26 05:26:53 +08:00
|
|
|
NumExs, ExArray, NoReturn);
|
2007-01-27 09:15:32 +08:00
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
if (FunctionProtoType *FTP =
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(FTP, 0);
|
2009-05-28 06:11:52 +08:00
|
|
|
|
|
|
|
// Determine whether the type being created is already canonical or not.
|
2006-12-02 15:52:18 +08:00
|
|
|
bool isCanonical = ResultTy->isCanonical();
|
2009-05-28 06:11:52 +08:00
|
|
|
if (hasExceptionSpec)
|
|
|
|
isCanonical = false;
|
2006-12-02 15:52:18 +08:00
|
|
|
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
|
|
|
|
if (!ArgArray[i]->isCanonical())
|
|
|
|
isCanonical = false;
|
|
|
|
|
|
|
|
// If this type isn't canonical, get the canonical version of it.
|
2009-05-28 06:11:52 +08:00
|
|
|
// The exception spec is not part of the canonical type.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType Canonical;
|
2006-12-02 15:52:18 +08:00
|
|
|
if (!isCanonical) {
|
2007-06-16 07:05:46 +08:00
|
|
|
llvm::SmallVector<QualType, 16> CanonicalArgs;
|
2006-12-02 15:52:18 +08:00
|
|
|
CanonicalArgs.reserve(NumArgs);
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i)
|
2008-04-07 06:59:24 +08:00
|
|
|
CanonicalArgs.push_back(getCanonicalType(ArgArray[i]));
|
2009-05-28 06:11:52 +08:00
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
Canonical = getFunctionType(getCanonicalType(ResultTy),
|
2009-05-21 17:52:38 +08:00
|
|
|
CanonicalArgs.data(), NumArgs,
|
2009-08-06 03:03:35 +08:00
|
|
|
isVariadic, TypeQuals, false,
|
|
|
|
false, 0, 0, NoReturn);
|
2009-05-28 06:11:52 +08:00
|
|
|
|
2007-01-27 09:15:32 +08:00
|
|
|
// Get the new insert position for the node we care about.
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionProtoType *NewIP =
|
|
|
|
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2008-10-12 08:26:57 +08:00
|
|
|
assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
|
2006-12-02 15:52:18 +08:00
|
|
|
}
|
2009-05-28 06:11:52 +08:00
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
// FunctionProtoType objects are allocated with extra bytes after them
|
2009-05-28 06:11:52 +08:00
|
|
|
// for two variable size arrays (for parameter and exception types) at the
|
|
|
|
// end of them.
|
2009-09-09 23:08:12 +08:00
|
|
|
FunctionProtoType *FTP =
|
2009-05-28 06:11:52 +08:00
|
|
|
(FunctionProtoType*)Allocate(sizeof(FunctionProtoType) +
|
|
|
|
NumArgs*sizeof(QualType) +
|
2009-09-25 07:30:46 +08:00
|
|
|
NumExs*sizeof(QualType), TypeAlignment);
|
2009-02-27 07:50:07 +08:00
|
|
|
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
|
2009-05-28 06:11:52 +08:00
|
|
|
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
|
2009-07-26 05:26:53 +08:00
|
|
|
ExArray, NumExs, Canonical, NoReturn);
|
2006-12-02 15:52:18 +08:00
|
|
|
Types.push_back(FTP);
|
2009-02-27 07:50:07 +08:00
|
|
|
FunctionProtoTypes.InsertNode(FTP, InsertPos);
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(FTP, 0);
|
2006-12-02 15:52:18 +08:00
|
|
|
}
|
2006-11-10 15:17:23 +08:00
|
|
|
|
2008-04-14 05:07:44 +08:00
|
|
|
/// getTypeDeclType - Return the unique reference to the type for the
|
|
|
|
/// specified type declaration.
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
|
2008-10-17 00:50:47 +08:00
|
|
|
assert(Decl && "Passed null for Decl param");
|
2008-04-14 05:07:44 +08:00
|
|
|
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-17 00:50:47 +08:00
|
|
|
if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl))
|
2008-04-14 05:07:44 +08:00
|
|
|
return getTypedefType(Typedef);
|
2009-02-06 07:33:38 +08:00
|
|
|
else if (isa<TemplateTypeParmDecl>(Decl)) {
|
|
|
|
assert(false && "Template type parameter types are always available.");
|
2009-07-31 10:02:20 +08:00
|
|
|
} else if (ObjCInterfaceDecl *ObjCInterface
|
|
|
|
= dyn_cast<ObjCInterfaceDecl>(Decl))
|
2008-04-14 05:07:44 +08:00
|
|
|
return getObjCInterfaceType(ObjCInterface);
|
2008-08-08 04:55:28 +08:00
|
|
|
|
2009-02-28 09:32:25 +08:00
|
|
|
if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
|
2009-01-20 05:31:22 +08:00
|
|
|
if (PrevDecl)
|
|
|
|
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
2009-01-28 06:08:43 +08:00
|
|
|
else
|
2009-09-25 07:30:46 +08:00
|
|
|
Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record);
|
2009-07-31 10:02:20 +08:00
|
|
|
} else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
|
2009-01-20 05:31:22 +08:00
|
|
|
if (PrevDecl)
|
|
|
|
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
2009-01-28 06:08:43 +08:00
|
|
|
else
|
2009-09-25 07:30:46 +08:00
|
|
|
Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum);
|
2009-07-31 10:02:20 +08:00
|
|
|
} else
|
2008-04-14 05:07:44 +08:00
|
|
|
assert(false && "TypeDecl without a type?");
|
2008-08-08 04:55:28 +08:00
|
|
|
|
Change struct forward declarations and definitions to use unique RecordDecls, as opposed to creating a single RecordDecl and reusing it.
This change effects both RecordDecls and CXXRecordDecls, but does not effect EnumDecls (yet).
The motivation of this patch is as follows:
- Capture more source information, necessary for refactoring/rewriting clients.
- Pave the way to resolve ownership issues with RecordDecls with the forthcoming
addition of DeclGroups.
Current caveats:
- Until DeclGroups are in place, we will leak RecordDecls not explicitly
referenced by the AST. For example:
typedef struct { ... } x;
The RecordDecl for the struct will be leaked because the TypedefDecl doesn't
refer to it. This will be solved with DeclGroups.
- This patch also (temporarily) breaks CodeGen. More below.
High-level changes:
- As before, TagType still refers to a TagDecl, but it doesn't own it. When
a struct/union/class is first referenced, a RecordType and RecordDecl are
created for it, and the RecordType refers to that RecordDecl. Later, if
a new RecordDecl is created, the pointer to a RecordDecl in RecordType is
updated to point to the RecordDecl that defines the struct/union/class.
- TagDecl and RecordDecl now how a method 'getDefinition()' to return the
TagDecl*/RecordDecl* that refers to the TagDecl* that defines a particular
enum/struct/class/union. This is useful from going from a RecordDecl* that
defines a forward declaration to the RecordDecl* that provides the actual
definition. Note that this also works for EnumDecls, except that in this case
there is no distinction between forward declarations and definitions (yet).
- Clients should no longer assume that 'isDefinition()' returns true from a
RecordDecl if the corresponding struct/union/class has been defined.
isDefinition() only returns true if a particular RecordDecl is the defining
Decl. Use 'getDefinition()' instead to determine if a struct has been defined.
- The main changes to Sema happen in ActOnTag. To make the changes more
incremental, I split off the processing of enums and structs et al into two
code paths. Enums use the original code path (which is in ActOnTag) and
structs use the ActOnTagStruct. Eventually the two code paths will be merged,
but the idea was to preserve the original logic both for comparison and not to
change the logic for both enums and structs all at once.
- There is NO CHAINING of RecordDecls for the same RecordType. All RecordDecls
that correspond to the same type simply have a pointer to that type. If we
need to figure out what are all the RecordDecls for a given type we can build
a backmap.
- The diff in CXXRecordDecl.[cpp,h] is actually very small; it just mimics the
changes to RecordDecl. For some reason 'svn' marks the entire file as changed.
Why is CodeGen broken:
- Codegen assumes that there is an equivalence between RecordDecl* and
RecordType*. This was true before because we only created one RecordDecl* for
a given RecordType*, but it is no longer true. I believe this shouldn't be too
hard to change, but the patch was big enough as it is.
I have tested this patch on both the clang test suite, and by running the static analyzer over Postgresql and a large Apple-internal project (mix of Objective-C and C).
llvm-svn: 55839
2008-09-06 01:16:31 +08:00
|
|
|
if (!PrevDecl) Types.push_back(Decl->TypeForDecl);
|
2008-08-08 04:55:28 +08:00
|
|
|
return QualType(Decl->TypeForDecl, 0);
|
2008-04-14 05:07:44 +08:00
|
|
|
}
|
|
|
|
|
2007-01-26 10:01:53 +08:00
|
|
|
/// getTypedefType - Return the unique reference to the type for the
|
2006-11-20 12:02:15 +08:00
|
|
|
/// specified typename decl.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
|
|
|
|
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
|
2009-09-25 07:30:46 +08:00
|
|
|
Decl->TypeForDecl = new(*this, TypeAlignment)
|
|
|
|
TypedefType(Type::Typedef, Decl, Canonical);
|
2007-03-27 04:16:44 +08:00
|
|
|
Types.push_back(Decl->TypeForDecl);
|
2007-04-06 06:36:20 +08:00
|
|
|
return QualType(Decl->TypeForDecl, 0);
|
2006-11-20 12:02:15 +08:00
|
|
|
}
|
|
|
|
|
2009-10-18 17:09:24 +08:00
|
|
|
/// \brief Retrieve a substitution-result type.
|
|
|
|
QualType
|
|
|
|
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
|
|
|
|
QualType Replacement) {
|
|
|
|
assert(Replacement->isCanonical()
|
|
|
|
&& "replacement types must always be canonical");
|
|
|
|
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
|
|
|
|
void *InsertPos = 0;
|
|
|
|
SubstTemplateTypeParmType *SubstParm
|
|
|
|
= SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
|
|
|
|
if (!SubstParm) {
|
|
|
|
SubstParm = new (*this, TypeAlignment)
|
|
|
|
SubstTemplateTypeParmType(Parm, Replacement);
|
|
|
|
Types.push_back(SubstParm);
|
|
|
|
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return QualType(SubstParm, 0);
|
|
|
|
}
|
|
|
|
|
2009-02-06 07:33:38 +08:00
|
|
|
/// \brief Retrieve the template type parameter type for a template
|
2009-09-09 23:08:12 +08:00
|
|
|
/// parameter or parameter pack with the given depth, index, and (optionally)
|
2009-06-16 08:30:48 +08:00
|
|
|
/// name.
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
2009-06-16 08:30:48 +08:00
|
|
|
bool ParameterPack,
|
2009-02-06 07:33:38 +08:00
|
|
|
IdentifierInfo *Name) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-06-16 08:30:48 +08:00
|
|
|
TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name);
|
2009-02-06 07:33:38 +08:00
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateTypeParmType *TypeParm
|
2009-02-06 07:33:38 +08:00
|
|
|
= TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
|
|
|
|
if (TypeParm)
|
|
|
|
return QualType(TypeParm, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-16 08:30:48 +08:00
|
|
|
if (Name) {
|
|
|
|
QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack);
|
2009-09-25 07:30:46 +08:00
|
|
|
TypeParm = new (*this, TypeAlignment)
|
|
|
|
TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon);
|
2009-06-16 08:30:48 +08:00
|
|
|
} else
|
2009-09-25 07:30:46 +08:00
|
|
|
TypeParm = new (*this, TypeAlignment)
|
|
|
|
TemplateTypeParmType(Depth, Index, ParameterPack);
|
2009-02-06 07:33:38 +08:00
|
|
|
|
|
|
|
Types.push_back(TypeParm);
|
|
|
|
TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos);
|
|
|
|
|
|
|
|
return QualType(TypeParm, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType
|
2009-03-31 06:58:21 +08:00
|
|
|
ASTContext::getTemplateSpecializationType(TemplateName Template,
|
|
|
|
const TemplateArgument *Args,
|
|
|
|
unsigned NumArgs,
|
|
|
|
QualType Canon) {
|
2009-07-31 01:40:51 +08:00
|
|
|
if (!Canon.isNull())
|
|
|
|
Canon = getCanonicalType(Canon);
|
|
|
|
else {
|
|
|
|
// Build the canonical template specialization type.
|
2009-07-29 07:00:59 +08:00
|
|
|
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
|
|
|
|
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
|
|
|
|
CanonArgs.reserve(NumArgs);
|
|
|
|
for (unsigned I = 0; I != NumArgs; ++I)
|
|
|
|
CanonArgs.push_back(getCanonicalTemplateArgument(Args[I]));
|
|
|
|
|
|
|
|
// Determine whether this canonical template specialization type already
|
|
|
|
// exists.
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateSpecializationType::Profile(ID, CanonTemplate,
|
2009-07-30 00:09:57 +08:00
|
|
|
CanonArgs.data(), NumArgs, *this);
|
2009-07-29 07:00:59 +08:00
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
TemplateSpecializationType *Spec
|
|
|
|
= TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
if (!Spec) {
|
|
|
|
// Allocate a new canonical template specialization type.
|
2009-09-09 23:08:12 +08:00
|
|
|
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
|
2009-07-29 07:00:59 +08:00
|
|
|
sizeof(TemplateArgument) * NumArgs),
|
2009-09-25 07:30:46 +08:00
|
|
|
TypeAlignment);
|
2009-09-09 23:08:12 +08:00
|
|
|
Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
|
2009-07-29 07:00:59 +08:00
|
|
|
CanonArgs.data(), NumArgs,
|
2009-07-31 01:40:51 +08:00
|
|
|
Canon);
|
2009-07-29 07:00:59 +08:00
|
|
|
Types.push_back(Spec);
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
2009-07-29 07:00:59 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 01:40:51 +08:00
|
|
|
if (Canon.isNull())
|
|
|
|
Canon = QualType(Spec, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(Canon->isDependentType() &&
|
2009-07-29 07:00:59 +08:00
|
|
|
"Non-dependent template-id type must have a canonical type");
|
2009-07-31 01:40:51 +08:00
|
|
|
}
|
2009-02-27 06:19:44 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
// Allocate the (non-canonical) template specialization type, but don't
|
|
|
|
// try to unique it: these types typically have location information that
|
|
|
|
// we don't unique and don't want to lose.
|
2009-09-09 23:08:12 +08:00
|
|
|
void *Mem = Allocate((sizeof(TemplateSpecializationType) +
|
2009-03-10 07:48:35 +08:00
|
|
|
sizeof(TemplateArgument) * NumArgs),
|
2009-09-25 07:30:46 +08:00
|
|
|
TypeAlignment);
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateSpecializationType *Spec
|
|
|
|
= new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs,
|
2009-07-30 00:09:57 +08:00
|
|
|
Canon);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-10 02:46:07 +08:00
|
|
|
Types.push_back(Spec);
|
2009-09-09 23:08:12 +08:00
|
|
|
return QualType(Spec, 0);
|
2009-02-10 02:46:07 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType
|
2009-03-27 07:50:42 +08:00
|
|
|
ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
QualType NamedType) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-03-27 07:50:42 +08:00
|
|
|
QualifiedNameType::Profile(ID, NNS, NamedType);
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
QualifiedNameType *T
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
= QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (T)
|
|
|
|
return QualType(T, 0);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
T = new (*this) QualifiedNameType(NNS, NamedType,
|
2009-03-27 07:50:42 +08:00
|
|
|
getCanonicalType(NamedType));
|
Introduce a representation for types that we referred to via a
qualified name, e.g.,
foo::x
so that we retain the nested-name-specifier as written in the source
code and can reproduce that qualified name when printing the types
back (e.g., in diagnostics). This is PR3493, which won't be complete
until finished the other tasks mentioned near the end of this commit.
The parser's representation of nested-name-specifiers, CXXScopeSpec,
is now a bit fatter, because it needs to contain the scopes that
precede each '::' and keep track of whether the global scoping
operator '::' was at the beginning. For example, we need to keep track
of the leading '::', 'foo', and 'bar' in
::foo::bar::x
The Action's CXXScopeTy * is no longer a DeclContext *. It's now the
opaque version of the new NestedNameSpecifier, which contains a single
component of a nested-name-specifier (either a DeclContext * or a Type
*, bitmangled).
The new sugar type QualifiedNameType composes a sequence of
NestedNameSpecifiers with a representation of the type we're actually
referring to. At present, we only build QualifiedNameType nodes within
Sema::getTypeName. This will be extended to other type-constructing
actions (e.g., ActOnClassTemplateId).
Also on the way: QualifiedDeclRefExprs will also store a sequence of
NestedNameSpecifiers, so that we can print out the property
nested-name-specifier. I expect to also use this for handling
dependent names like Fibonacci<I - 1>::value.
llvm-svn: 67265
2009-03-19 08:18:19 +08:00
|
|
|
Types.push_back(T);
|
|
|
|
QualifiedNameTypes.InsertNode(T, InsertPos);
|
|
|
|
return QualType(T, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS,
|
2009-03-28 07:10:48 +08:00
|
|
|
const IdentifierInfo *Name,
|
|
|
|
QualType Canon) {
|
|
|
|
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
|
|
|
|
|
|
|
|
if (Canon.isNull()) {
|
|
|
|
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
|
|
|
|
if (CanonNNS != NNS)
|
|
|
|
Canon = getTypenameType(CanonNNS, Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
TypenameType::Profile(ID, NNS, Name);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
TypenameType *T
|
2009-03-28 07:10:48 +08:00
|
|
|
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (T)
|
|
|
|
return QualType(T, 0);
|
|
|
|
|
|
|
|
T = new (*this) TypenameType(NNS, Name, Canon);
|
|
|
|
Types.push_back(T);
|
|
|
|
TypenameTypes.InsertNode(T, InsertPos);
|
2009-09-09 23:08:12 +08:00
|
|
|
return QualType(T, 0);
|
2009-03-28 07:10:48 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType
|
|
|
|
ASTContext::getTypenameType(NestedNameSpecifier *NNS,
|
2009-04-01 08:28:59 +08:00
|
|
|
const TemplateSpecializationType *TemplateId,
|
|
|
|
QualType Canon) {
|
|
|
|
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
|
|
|
|
|
|
|
|
if (Canon.isNull()) {
|
|
|
|
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
|
|
|
|
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
|
|
|
|
if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
|
|
|
|
const TemplateSpecializationType *CanonTemplateId
|
2009-09-22 07:43:11 +08:00
|
|
|
= CanonType->getAs<TemplateSpecializationType>();
|
2009-04-01 08:28:59 +08:00
|
|
|
assert(CanonTemplateId &&
|
|
|
|
"Canonical type must also be a template specialization type");
|
|
|
|
Canon = getTypenameType(CanonNNS, CanonTemplateId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
TypenameType::Profile(ID, NNS, TemplateId);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
TypenameType *T
|
2009-04-01 08:28:59 +08:00
|
|
|
= TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (T)
|
|
|
|
return QualType(T, 0);
|
|
|
|
|
|
|
|
T = new (*this) TypenameType(NNS, TemplateId, Canon);
|
|
|
|
Types.push_back(T);
|
|
|
|
TypenameTypes.InsertNode(T, InsertPos);
|
2009-09-09 23:08:12 +08:00
|
|
|
return QualType(T, 0);
|
2009-04-01 08:28:59 +08:00
|
|
|
}
|
|
|
|
|
2009-09-05 08:15:47 +08:00
|
|
|
QualType
|
|
|
|
ASTContext::getElaboratedType(QualType UnderlyingType,
|
|
|
|
ElaboratedType::TagKind Tag) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ElaboratedType::Profile(ID, UnderlyingType, Tag);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-05 08:15:47 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (T)
|
|
|
|
return QualType(T, 0);
|
|
|
|
|
|
|
|
QualType Canon = getCanonicalType(UnderlyingType);
|
|
|
|
|
|
|
|
T = new (*this) ElaboratedType(UnderlyingType, Tag, Canon);
|
|
|
|
Types.push_back(T);
|
|
|
|
ElaboratedTypes.InsertNode(T, InsertPos);
|
|
|
|
return QualType(T, 0);
|
|
|
|
}
|
|
|
|
|
2008-04-07 12:56:42 +08:00
|
|
|
/// CmpProtocolNames - Comparison predicate for sorting protocols
|
|
|
|
/// alphabetically.
|
|
|
|
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
|
|
|
|
const ObjCProtocolDecl *RHS) {
|
2008-11-17 22:58:09 +08:00
|
|
|
return LHS->getDeclName() < RHS->getDeclName();
|
2008-04-07 12:56:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols,
|
|
|
|
unsigned &NumProtocols) {
|
|
|
|
ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 12:56:42 +08:00
|
|
|
// Sort protocols, keyed by name.
|
|
|
|
std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames);
|
|
|
|
|
|
|
|
// Remove duplicates.
|
|
|
|
ProtocolsEnd = std::unique(Protocols, ProtocolsEnd);
|
|
|
|
NumProtocols = ProtocolsEnd-Protocols;
|
|
|
|
}
|
|
|
|
|
2009-06-18 06:40:22 +08:00
|
|
|
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
|
|
|
|
/// the given interface decl and the conforming protocol list.
|
2009-07-11 07:34:53 +08:00
|
|
|
QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
|
2009-09-09 23:08:12 +08:00
|
|
|
ObjCProtocolDecl **Protocols,
|
2009-06-18 06:40:22 +08:00
|
|
|
unsigned NumProtocols) {
|
|
|
|
// Sort the protocol list alphabetically to canonicalize it.
|
|
|
|
if (NumProtocols)
|
|
|
|
SortAndUniqueProtocols(Protocols, NumProtocols);
|
|
|
|
|
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-07-11 07:34:53 +08:00
|
|
|
ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols);
|
2009-06-18 06:40:22 +08:00
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
if (ObjCObjectPointerType *QT =
|
|
|
|
ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(QT, 0);
|
|
|
|
|
|
|
|
// No Match;
|
2009-09-25 07:30:46 +08:00
|
|
|
ObjCObjectPointerType *QType = new (*this, TypeAlignment)
|
|
|
|
ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-18 06:40:22 +08:00
|
|
|
Types.push_back(QType);
|
|
|
|
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
|
|
|
|
return QualType(QType, 0);
|
|
|
|
}
|
2008-04-07 12:56:42 +08:00
|
|
|
|
2009-07-18 23:33:26 +08:00
|
|
|
/// getObjCInterfaceType - Return the unique reference to the type for the
|
|
|
|
/// specified ObjC interface decl. The list of protocols is optional.
|
|
|
|
QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCProtocolDecl **Protocols, unsigned NumProtocols) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (NumProtocols)
|
2009-07-18 23:33:26 +08:00
|
|
|
// Sort the protocol list alphabetically to canonicalize it.
|
|
|
|
SortAndUniqueProtocols(Protocols, NumProtocols);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-11 08:55:41 +08:00
|
|
|
llvm::FoldingSetNodeID ID;
|
2009-07-18 23:33:26 +08:00
|
|
|
ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-11 08:55:41 +08:00
|
|
|
void *InsertPos = 0;
|
2009-07-18 23:33:26 +08:00
|
|
|
if (ObjCInterfaceType *QT =
|
|
|
|
ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
|
2007-10-11 08:55:41 +08:00
|
|
|
return QualType(QT, 0);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-11 08:55:41 +08:00
|
|
|
// No Match;
|
2009-09-25 07:30:46 +08:00
|
|
|
ObjCInterfaceType *QType = new (*this, TypeAlignment)
|
|
|
|
ObjCInterfaceType(const_cast<ObjCInterfaceDecl*>(Decl),
|
|
|
|
Protocols, NumProtocols);
|
2007-10-11 08:55:41 +08:00
|
|
|
Types.push_back(QType);
|
2009-07-18 23:33:26 +08:00
|
|
|
ObjCInterfaceTypes.InsertNode(QType, InsertPos);
|
2007-10-11 08:55:41 +08:00
|
|
|
return QualType(QType, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-30 03:42:55 +08:00
|
|
|
QualType ASTContext::getObjCProtocolListType(QualType T,
|
|
|
|
ObjCProtocolDecl **Protocols,
|
|
|
|
unsigned NumProtocols) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
ObjCProtocolListType::Profile(ID, T, Protocols, NumProtocols);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
if (ObjCProtocolListType *QT =
|
|
|
|
ObjCProtocolListTypes.FindNodeOrInsertPos(ID, InsertPos))
|
|
|
|
return QualType(QT, 0);
|
|
|
|
|
|
|
|
// No Match;
|
|
|
|
ObjCProtocolListType *QType = new (*this, TypeAlignment)
|
|
|
|
ObjCProtocolListType(T, Protocols, NumProtocols);
|
|
|
|
Types.push_back(QType);
|
|
|
|
ObjCProtocolListTypes.InsertNode(QType, InsertPos);
|
|
|
|
return QualType(QType, 0);
|
|
|
|
}
|
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
/// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
|
|
|
|
/// TypeOfExprType AST's (since expression's are never shared). For example,
|
2007-08-02 02:02:17 +08:00
|
|
|
/// multiple declarations that refer to "typeof(x)" all contain different
|
2009-09-09 23:08:12 +08:00
|
|
|
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
|
2007-08-02 02:02:17 +08:00
|
|
|
/// on canonical type's (which are always unique).
|
2009-02-27 07:50:07 +08:00
|
|
|
QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
|
2009-07-08 08:03:05 +08:00
|
|
|
TypeOfExprType *toe;
|
2009-07-31 07:18:24 +08:00
|
|
|
if (tofExpr->isTypeDependent()) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
DependentTypeOfExprType::Profile(ID, *this, tofExpr);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 07:18:24 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
DependentTypeOfExprType *Canon
|
|
|
|
= DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (Canon) {
|
|
|
|
// We already have a "canonical" version of an identical, dependent
|
|
|
|
// typeof(expr) type. Use that as our canonical type.
|
2009-09-25 07:30:46 +08:00
|
|
|
toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr,
|
2009-07-31 07:18:24 +08:00
|
|
|
QualType((TypeOfExprType*)Canon, 0));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Build a new, canonical typeof(expr) type.
|
2009-09-25 07:30:46 +08:00
|
|
|
Canon
|
|
|
|
= new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr);
|
2009-07-31 07:18:24 +08:00
|
|
|
DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
|
|
|
|
toe = Canon;
|
|
|
|
}
|
|
|
|
} else {
|
2009-07-08 08:03:05 +08:00
|
|
|
QualType Canonical = getCanonicalType(tofExpr->getType());
|
2009-09-25 07:30:46 +08:00
|
|
|
toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical);
|
2009-07-08 08:03:05 +08:00
|
|
|
}
|
2007-08-02 02:02:17 +08:00
|
|
|
Types.push_back(toe);
|
|
|
|
return QualType(toe, 0);
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
|
|
|
|
2007-08-02 02:02:17 +08:00
|
|
|
/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique
|
|
|
|
/// TypeOfType AST's. The only motivation to unique these nodes would be
|
|
|
|
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
|
2009-09-09 23:08:12 +08:00
|
|
|
/// an issue. This doesn't effect the type checker, since it operates
|
2007-08-02 02:02:17 +08:00
|
|
|
/// on canonical type's (which are always unique).
|
2007-07-31 20:34:36 +08:00
|
|
|
QualType ASTContext::getTypeOfType(QualType tofType) {
|
2008-04-07 06:59:24 +08:00
|
|
|
QualType Canonical = getCanonicalType(tofType);
|
2009-09-25 07:30:46 +08:00
|
|
|
TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
|
2007-08-02 02:02:17 +08:00
|
|
|
Types.push_back(tot);
|
|
|
|
return QualType(tot, 0);
|
2007-07-31 20:34:36 +08:00
|
|
|
}
|
|
|
|
|
2009-06-25 05:24:56 +08:00
|
|
|
/// getDecltypeForExpr - Given an expr, will return the decltype for that
|
|
|
|
/// expression, according to the rules in C++0x [dcl.type.simple]p4
|
|
|
|
static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
|
2009-06-25 23:00:34 +08:00
|
|
|
if (e->isTypeDependent())
|
|
|
|
return Context.DependentTy;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 05:24:56 +08:00
|
|
|
// If e is an id expression or a class member access, decltype(e) is defined
|
|
|
|
// as the type of the entity named by e.
|
|
|
|
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) {
|
|
|
|
if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
|
|
|
|
return VD->getType();
|
|
|
|
}
|
|
|
|
if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) {
|
|
|
|
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
|
|
|
|
return FD->getType();
|
|
|
|
}
|
|
|
|
// If e is a function call or an invocation of an overloaded operator,
|
|
|
|
// (parentheses around e are ignored), decltype(e) is defined as the
|
|
|
|
// return type of that function.
|
|
|
|
if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens()))
|
|
|
|
return CE->getCallReturnType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 05:24:56 +08:00
|
|
|
QualType T = e->getType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
|
2009-06-25 05:24:56 +08:00
|
|
|
// defined as T&, otherwise decltype(e) is defined as T.
|
|
|
|
if (e->isLvalue(Context) == Expr::LV_Valid)
|
|
|
|
T = Context.getLValueReferenceType(T);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-25 05:24:56 +08:00
|
|
|
return T;
|
|
|
|
}
|
|
|
|
|
2009-06-25 03:06:50 +08:00
|
|
|
/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique
|
|
|
|
/// DecltypeType AST's. The only motivation to unique these nodes would be
|
|
|
|
/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
|
2009-09-09 23:08:12 +08:00
|
|
|
/// an issue. This doesn't effect the type checker, since it operates
|
2009-06-25 03:06:50 +08:00
|
|
|
/// on canonical type's (which are always unique).
|
|
|
|
QualType ASTContext::getDecltypeType(Expr *e) {
|
2009-07-08 08:03:05 +08:00
|
|
|
DecltypeType *dt;
|
2009-07-31 07:36:40 +08:00
|
|
|
if (e->isTypeDependent()) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
DependentDecltypeType::Profile(ID, *this, e);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 07:36:40 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
DependentDecltypeType *Canon
|
|
|
|
= DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (Canon) {
|
|
|
|
// We already have a "canonical" version of an equivalent, dependent
|
|
|
|
// decltype type. Use that as our canonical type.
|
2009-09-25 07:30:46 +08:00
|
|
|
dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy,
|
2009-07-31 07:36:40 +08:00
|
|
|
QualType((DecltypeType*)Canon, 0));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Build a new, canonical typeof(expr) type.
|
2009-09-25 07:30:46 +08:00
|
|
|
Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e);
|
2009-07-31 07:36:40 +08:00
|
|
|
DependentDecltypeTypes.InsertNode(Canon, InsertPos);
|
|
|
|
dt = Canon;
|
|
|
|
}
|
|
|
|
} else {
|
2009-07-08 08:03:05 +08:00
|
|
|
QualType T = getDecltypeForExpr(e, *this);
|
2009-09-25 07:30:46 +08:00
|
|
|
dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T));
|
2009-07-08 08:03:05 +08:00
|
|
|
}
|
2009-06-25 03:06:50 +08:00
|
|
|
Types.push_back(dt);
|
|
|
|
return QualType(dt, 0);
|
|
|
|
}
|
|
|
|
|
2007-01-23 13:45:31 +08:00
|
|
|
/// getTagDeclType - Return the unique reference to the type for the
|
|
|
|
/// specified TagDecl (struct/union/class/enum) decl.
|
2009-08-08 02:05:12 +08:00
|
|
|
QualType ASTContext::getTagDeclType(const TagDecl *Decl) {
|
2007-11-27 05:16:01 +08:00
|
|
|
assert (Decl);
|
2009-08-08 02:05:12 +08:00
|
|
|
// FIXME: What is the design on getTagDeclType when it requires casting
|
|
|
|
// away const? mutable?
|
|
|
|
return getTypeDeclType(const_cast<TagDecl*>(Decl));
|
2007-01-23 13:45:31 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
|
|
|
|
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
|
|
|
|
/// needs to agree with the definition in <stddef.h>.
|
2007-04-06 06:36:20 +08:00
|
|
|
QualType ASTContext::getSizeType() const {
|
2008-11-03 22:12:49 +08:00
|
|
|
return getFromTargetType(Target.getSizeType());
|
2007-04-03 06:35:25 +08:00
|
|
|
}
|
2007-01-23 13:45:31 +08:00
|
|
|
|
2008-08-10 00:51:54 +08:00
|
|
|
/// getSignedWCharType - Return the type of "signed wchar_t".
|
|
|
|
/// Used when in C++, as a GCC extension.
|
|
|
|
QualType ASTContext::getSignedWCharType() const {
|
|
|
|
// FIXME: derive from "Target" ?
|
|
|
|
return WCharTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// getUnsignedWCharType - Return the type of "unsigned wchar_t".
|
|
|
|
/// Used when in C++, as a GCC extension.
|
|
|
|
QualType ASTContext::getUnsignedWCharType() const {
|
|
|
|
// FIXME: derive from "Target" ?
|
|
|
|
return UnsignedIntTy;
|
|
|
|
}
|
|
|
|
|
2007-07-13 11:05:23 +08:00
|
|
|
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?)
|
|
|
|
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
|
|
|
|
QualType ASTContext::getPointerDiffType() const {
|
2008-11-03 22:12:49 +08:00
|
|
|
return getFromTargetType(Target.getPtrDiffType(0));
|
2007-07-13 11:05:23 +08:00
|
|
|
}
|
|
|
|
|
2008-04-02 13:18:44 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Operators
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-04-07 06:41:35 +08:00
|
|
|
/// getCanonicalType - Return the canonical (structural) type corresponding to
|
|
|
|
/// the specified potentially non-canonical type. The non-canonical version
|
|
|
|
/// of a type may have many "decorated" versions of types. Decorators can
|
|
|
|
/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
|
|
|
|
/// to be free of any of these, allowing two canonical types to be compared
|
|
|
|
/// for exact equality with a simple pointer comparison.
|
2009-08-05 13:36:45 +08:00
|
|
|
CanQualType ASTContext::getCanonicalType(QualType T) {
|
2009-09-25 03:53:00 +08:00
|
|
|
QualifierCollector Quals;
|
|
|
|
const Type *Ptr = Quals.strip(T);
|
|
|
|
QualType CanType = Ptr->getCanonicalTypeInternal();
|
|
|
|
|
|
|
|
// The canonical internal type will be the canonical type *except*
|
|
|
|
// that we push type qualifiers down through array types.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If there are no new qualifiers to push down, stop here.
|
|
|
|
if (!Quals.hasQualifiers())
|
2009-08-05 13:36:45 +08:00
|
|
|
return CanQualType::CreateUnsafe(CanType);
|
2008-08-04 15:31:14 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If the type qualifiers are on an array type, get the canonical
|
|
|
|
// type of the array with the qualifiers applied to the element
|
|
|
|
// type.
|
2008-08-04 15:31:14 +08:00
|
|
|
ArrayType *AT = dyn_cast<ArrayType>(CanType);
|
|
|
|
if (!AT)
|
2009-09-25 03:53:00 +08:00
|
|
|
return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
// Get the canonical version of the element with the extra qualifiers on it.
|
|
|
|
// This can recursively sink qualifiers through multiple levels of arrays.
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals);
|
2008-08-04 15:31:14 +08:00
|
|
|
NewEltTy = getCanonicalType(NewEltTy);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
|
2009-08-05 13:36:45 +08:00
|
|
|
return CanQualType::CreateUnsafe(
|
|
|
|
getConstantArrayType(NewEltTy, CAT->getSize(),
|
|
|
|
CAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
CAT->getIndexTypeCVRQualifiers()));
|
2008-08-04 15:31:14 +08:00
|
|
|
if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
|
2009-08-05 13:36:45 +08:00
|
|
|
return CanQualType::CreateUnsafe(
|
|
|
|
getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
IAT->getIndexTypeCVRQualifiers()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-06 07:32:09 +08:00
|
|
|
if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
|
2009-08-05 13:36:45 +08:00
|
|
|
return CanQualType::CreateUnsafe(
|
|
|
|
getDependentSizedArrayType(NewEltTy,
|
2009-08-15 10:50:32 +08:00
|
|
|
DSAT->getSizeExpr() ?
|
|
|
|
DSAT->getSizeExpr()->Retain() : 0,
|
2009-08-05 13:36:45 +08:00
|
|
|
DSAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
DSAT->getIndexTypeCVRQualifiers(),
|
2009-08-05 13:36:45 +08:00
|
|
|
DSAT->getBracketsRange()));
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
VariableArrayType *VAT = cast<VariableArrayType>(AT);
|
2009-08-05 13:36:45 +08:00
|
|
|
return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy,
|
2009-08-15 10:50:32 +08:00
|
|
|
VAT->getSizeExpr() ?
|
|
|
|
VAT->getSizeExpr()->Retain() : 0,
|
2009-08-05 13:36:45 +08:00
|
|
|
VAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
VAT->getIndexTypeCVRQualifiers(),
|
2009-08-05 13:36:45 +08:00
|
|
|
VAT->getBracketsRange()));
|
2008-08-04 15:31:14 +08:00
|
|
|
}
|
|
|
|
|
2009-05-07 14:41:52 +08:00
|
|
|
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
|
|
|
|
// If this template name refers to a template, the canonical
|
|
|
|
// template name merely stores the template itself.
|
|
|
|
if (TemplateDecl *Template = Name.getAsTemplateDecl())
|
2009-07-18 08:34:25 +08:00
|
|
|
return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl()));
|
2009-05-07 14:41:52 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// If this template name refers to a set of overloaded function templates,
|
2009-07-30 02:26:50 +08:00
|
|
|
/// the canonical template name merely stores the set of function templates.
|
2009-07-31 13:24:01 +08:00
|
|
|
if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) {
|
|
|
|
OverloadedFunctionDecl *CanonOvl = 0;
|
|
|
|
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
|
|
|
|
FEnd = Ovl->function_end();
|
|
|
|
F != FEnd; ++F) {
|
|
|
|
Decl *Canon = F->get()->getCanonicalDecl();
|
|
|
|
if (CanonOvl || Canon != F->get()) {
|
|
|
|
if (!CanonOvl)
|
2009-09-09 23:08:12 +08:00
|
|
|
CanonOvl = OverloadedFunctionDecl::Create(*this,
|
|
|
|
Ovl->getDeclContext(),
|
2009-07-31 13:24:01 +08:00
|
|
|
Ovl->getDeclName());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 13:24:01 +08:00
|
|
|
CanonOvl->addOverload(
|
|
|
|
AnyFunctionDecl::getFromNamedDecl(cast<NamedDecl>(Canon)));
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-31 13:24:01 +08:00
|
|
|
return TemplateName(CanonOvl? CanonOvl : Ovl);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-07 14:41:52 +08:00
|
|
|
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
|
|
|
|
assert(DTN && "Non-dependent template names must refer to template decls.");
|
|
|
|
return DTN->CanonicalTemplateName;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateArgument
|
2009-07-29 07:00:59 +08:00
|
|
|
ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
|
|
|
|
switch (Arg.getKind()) {
|
|
|
|
case TemplateArgument::Null:
|
|
|
|
return Arg;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
case TemplateArgument::Expression:
|
|
|
|
// FIXME: Build canonical expression?
|
|
|
|
return Arg;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
case TemplateArgument::Declaration:
|
|
|
|
return TemplateArgument(SourceLocation(),
|
|
|
|
Arg.getAsDecl()->getCanonicalDecl());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
case TemplateArgument::Integral:
|
|
|
|
return TemplateArgument(SourceLocation(),
|
|
|
|
*Arg.getAsIntegral(),
|
|
|
|
getCanonicalType(Arg.getIntegralType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
case TemplateArgument::Type:
|
|
|
|
return TemplateArgument(SourceLocation(),
|
|
|
|
getCanonicalType(Arg.getAsType()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
case TemplateArgument::Pack: {
|
|
|
|
// FIXME: Allocate in ASTContext
|
|
|
|
TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()];
|
|
|
|
unsigned Idx = 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
|
2009-07-29 07:00:59 +08:00
|
|
|
AEnd = Arg.pack_end();
|
|
|
|
A != AEnd; (void)++A, ++Idx)
|
|
|
|
CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-29 07:00:59 +08:00
|
|
|
TemplateArgument Result;
|
|
|
|
Result.setArgumentPack(CanonArgs, Arg.pack_size(), false);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Silence GCC warning
|
|
|
|
assert(false && "Unhandled template argument kind");
|
|
|
|
return TemplateArgument();
|
|
|
|
}
|
|
|
|
|
2009-03-28 07:10:48 +08:00
|
|
|
NestedNameSpecifier *
|
|
|
|
ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (!NNS)
|
2009-03-28 07:10:48 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (NNS->getKind()) {
|
|
|
|
case NestedNameSpecifier::Identifier:
|
|
|
|
// Canonicalize the prefix but keep the identifier the same.
|
2009-09-09 23:08:12 +08:00
|
|
|
return NestedNameSpecifier::Create(*this,
|
2009-03-28 07:10:48 +08:00
|
|
|
getCanonicalNestedNameSpecifier(NNS->getPrefix()),
|
|
|
|
NNS->getAsIdentifier());
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Namespace:
|
|
|
|
// A namespace is canonical; build a nested-name-specifier with
|
|
|
|
// this namespace and no prefix.
|
|
|
|
return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
|
|
|
|
|
|
|
|
case NestedNameSpecifier::TypeSpec:
|
|
|
|
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
|
|
|
QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
|
2009-09-09 23:08:12 +08:00
|
|
|
return NestedNameSpecifier::Create(*this, 0,
|
|
|
|
NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
|
2009-03-28 07:10:48 +08:00
|
|
|
T.getTypePtr());
|
|
|
|
}
|
|
|
|
|
|
|
|
case NestedNameSpecifier::Global:
|
|
|
|
// The global specifier is canonical and unique.
|
|
|
|
return NNS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Required to silence a GCC warning
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
|
|
|
|
const ArrayType *ASTContext::getAsArrayType(QualType T) {
|
|
|
|
// Handle the non-qualified case efficiently.
|
2009-09-25 03:53:00 +08:00
|
|
|
if (!T.hasQualifiers()) {
|
2008-08-04 15:31:14 +08:00
|
|
|
// Handle the common positive case fast.
|
|
|
|
if (const ArrayType *AT = dyn_cast<ArrayType>(T))
|
|
|
|
return AT;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// Handle the common negative case fast.
|
2008-08-04 15:31:14 +08:00
|
|
|
QualType CType = T->getCanonicalTypeInternal();
|
2009-09-25 03:53:00 +08:00
|
|
|
if (!isa<ArrayType>(CType))
|
2008-08-04 15:31:14 +08:00
|
|
|
return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// Apply any qualifiers from the array type to the element type. This
|
2008-08-04 15:31:14 +08:00
|
|
|
// implements C99 6.7.3p8: "If the specification of an array type includes
|
|
|
|
// any type qualifiers, the element type is so qualified, not the array type."
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
// If we get here, we either have type qualifiers on the type, or we have
|
|
|
|
// sugar such as a typedef in the way. If we have type qualifiers on the type
|
2009-08-05 13:36:45 +08:00
|
|
|
// we must propagate them down into the element type.
|
2009-09-25 03:53:00 +08:00
|
|
|
|
|
|
|
QualifierCollector Qs;
|
|
|
|
const Type *Ty = Qs.strip(T.getDesugaredType());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
// If we have a simple case, just return now.
|
|
|
|
const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
|
2009-09-25 03:53:00 +08:00
|
|
|
if (ATy == 0 || Qs.empty())
|
2008-08-04 15:31:14 +08:00
|
|
|
return ATy;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
// Otherwise, we have an array and we have qualifiers on it. Push the
|
|
|
|
// qualifiers into the array element type and return a new array type.
|
|
|
|
// Get the canonical version of the element with the extra qualifiers on it.
|
|
|
|
// This can recursively sink qualifiers through multiple levels of arrays.
|
2009-09-25 03:53:00 +08:00
|
|
|
QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
|
|
|
|
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
|
|
|
|
CAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
CAT->getIndexTypeCVRQualifiers()));
|
2008-08-04 15:31:14 +08:00
|
|
|
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy))
|
|
|
|
return cast<ArrayType>(getIncompleteArrayType(NewEltTy,
|
|
|
|
IAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
IAT->getIndexTypeCVRQualifiers()));
|
2008-12-06 07:32:09 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const DependentSizedArrayType *DSAT
|
2008-12-06 07:32:09 +08:00
|
|
|
= dyn_cast<DependentSizedArrayType>(ATy))
|
|
|
|
return cast<ArrayType>(
|
2009-09-09 23:08:12 +08:00
|
|
|
getDependentSizedArrayType(NewEltTy,
|
2009-08-15 10:50:32 +08:00
|
|
|
DSAT->getSizeExpr() ?
|
|
|
|
DSAT->getSizeExpr()->Retain() : 0,
|
2008-12-06 07:32:09 +08:00
|
|
|
DSAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
DSAT->getIndexTypeCVRQualifiers(),
|
2009-07-06 23:59:29 +08:00
|
|
|
DSAT->getBracketsRange()));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
|
2009-07-06 23:59:29 +08:00
|
|
|
return cast<ArrayType>(getVariableArrayType(NewEltTy,
|
2009-08-15 10:50:32 +08:00
|
|
|
VAT->getSizeExpr() ?
|
2009-09-25 03:53:00 +08:00
|
|
|
VAT->getSizeExpr()->Retain() : 0,
|
2008-08-04 15:31:14 +08:00
|
|
|
VAT->getSizeModifier(),
|
2009-09-25 03:53:00 +08:00
|
|
|
VAT->getIndexTypeCVRQualifiers(),
|
2009-07-06 23:59:29 +08:00
|
|
|
VAT->getBracketsRange()));
|
2008-04-07 06:41:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-02 13:18:44 +08:00
|
|
|
/// getArrayDecayedType - Return the properly qualified result of decaying the
|
|
|
|
/// specified array type to a pointer. This operation is non-trivial when
|
|
|
|
/// handling typedefs etc. The canonical type of "T" must be an array type,
|
|
|
|
/// this returns a pointer to a properly qualified element of the array.
|
|
|
|
///
|
|
|
|
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
|
|
|
|
QualType ASTContext::getArrayDecayedType(QualType Ty) {
|
2008-08-04 15:31:14 +08:00
|
|
|
// Get the element type with 'getAsArrayType' so that we don't lose any
|
|
|
|
// typedefs in the element type of the array. This also handles propagation
|
|
|
|
// of type qualifiers from the array type into the element type if present
|
|
|
|
// (C99 6.7.3p8).
|
|
|
|
const ArrayType *PrettyArrayType = getAsArrayType(Ty);
|
|
|
|
assert(PrettyArrayType && "Not an array type!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-04 15:31:14 +08:00
|
|
|
QualType PtrTy = getPointerType(PrettyArrayType->getElementType());
|
2008-04-02 13:18:44 +08:00
|
|
|
|
|
|
|
// int x[restrict 4] -> int *restrict
|
2009-09-25 03:53:00 +08:00
|
|
|
return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers());
|
2008-04-02 13:18:44 +08:00
|
|
|
}
|
|
|
|
|
2009-07-24 07:49:00 +08:00
|
|
|
QualType ASTContext::getBaseElementType(QualType QT) {
|
2009-09-25 03:53:00 +08:00
|
|
|
QualifierCollector Qs;
|
2009-07-24 07:49:00 +08:00
|
|
|
while (true) {
|
2009-09-25 03:53:00 +08:00
|
|
|
const Type *UT = Qs.strip(QT);
|
2009-07-24 07:49:00 +08:00
|
|
|
if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) {
|
|
|
|
QT = AT->getElementType();
|
2009-07-26 07:24:03 +08:00
|
|
|
} else {
|
2009-09-25 03:53:00 +08:00
|
|
|
return Qs.apply(QT);
|
2009-07-24 07:49:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-25 09:23:32 +08:00
|
|
|
QualType ASTContext::getBaseElementType(const ArrayType *AT) {
|
|
|
|
QualType ElemTy = AT->getElementType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 09:23:32 +08:00
|
|
|
if (const ArrayType *AT = getAsArrayType(ElemTy))
|
|
|
|
return getBaseElementType(AT);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-21 11:44:36 +08:00
|
|
|
return ElemTy;
|
|
|
|
}
|
|
|
|
|
2009-08-22 00:31:06 +08:00
|
|
|
/// getConstantArrayElementCount - Returns number of constant array elements.
|
2009-09-09 23:08:12 +08:00
|
|
|
uint64_t
|
2009-08-22 00:31:06 +08:00
|
|
|
ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
|
|
|
|
uint64_t ElementCount = 1;
|
|
|
|
do {
|
|
|
|
ElementCount *= CA->getSize().getZExtValue();
|
|
|
|
CA = dyn_cast<ConstantArrayType>(CA->getElementType());
|
|
|
|
} while (CA);
|
|
|
|
return ElementCount;
|
|
|
|
}
|
|
|
|
|
2007-04-28 05:51:21 +08:00
|
|
|
/// getFloatingRank - Return a relative rank for floating point types.
|
|
|
|
/// This routine will assert if passed a built-in type that isn't a float.
|
2008-04-07 07:38:49 +08:00
|
|
|
static FloatingRank getFloatingRank(QualType T) {
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ComplexType *CT = T->getAs<ComplexType>())
|
2007-06-23 04:56:16 +08:00
|
|
|
return getFloatingRank(CT->getElementType());
|
2008-04-07 07:38:49 +08:00
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
|
|
|
|
switch (T->getAs<BuiltinType>()->getKind()) {
|
2008-04-07 07:38:49 +08:00
|
|
|
default: assert(0 && "getFloatingRank(): not a floating type");
|
2007-06-23 04:56:16 +08:00
|
|
|
case BuiltinType::Float: return FloatRank;
|
|
|
|
case BuiltinType::Double: return DoubleRank;
|
|
|
|
case BuiltinType::LongDouble: return LongDoubleRank;
|
2007-04-28 02:30:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// getFloatingTypeOfSizeWithinDomain - Returns a real floating
|
|
|
|
/// point or a complex type (based on typeDomain/typeSize).
|
2007-08-27 09:41:48 +08:00
|
|
|
/// 'typeDomain' is a real floating point or complex type.
|
|
|
|
/// 'typeSize' is a real floating point or complex type.
|
2008-04-07 07:58:54 +08:00
|
|
|
QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
|
|
|
|
QualType Domain) const {
|
|
|
|
FloatingRank EltRank = getFloatingRank(Size);
|
|
|
|
if (Domain->isComplexType()) {
|
|
|
|
switch (EltRank) {
|
2007-08-27 09:41:48 +08:00
|
|
|
default: assert(0 && "getFloatingRank(): illegal value for rank");
|
2007-08-27 09:27:54 +08:00
|
|
|
case FloatRank: return FloatComplexTy;
|
|
|
|
case DoubleRank: return DoubleComplexTy;
|
|
|
|
case LongDoubleRank: return LongDoubleComplexTy;
|
|
|
|
}
|
|
|
|
}
|
2008-04-07 07:58:54 +08:00
|
|
|
|
|
|
|
assert(Domain->isRealFloatingType() && "Unknown domain!");
|
|
|
|
switch (EltRank) {
|
|
|
|
default: assert(0 && "getFloatingRank(): illegal value for rank");
|
|
|
|
case FloatRank: return FloatTy;
|
|
|
|
case DoubleRank: return DoubleTy;
|
|
|
|
case LongDoubleRank: return LongDoubleTy;
|
2007-04-28 05:51:21 +08:00
|
|
|
}
|
2007-04-28 02:30:00 +08:00
|
|
|
}
|
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
/// getFloatingTypeOrder - Compare the rank of the two specified floating
|
|
|
|
/// point types, ignoring the domain of the type (i.e. 'double' ==
|
|
|
|
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
2009-09-09 23:08:12 +08:00
|
|
|
/// LHS < RHS, return -1.
|
2008-04-07 07:38:49 +08:00
|
|
|
int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
|
|
|
|
FloatingRank LHSR = getFloatingRank(LHS);
|
|
|
|
FloatingRank RHSR = getFloatingRank(RHS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:38:49 +08:00
|
|
|
if (LHSR == RHSR)
|
2007-08-27 23:30:22 +08:00
|
|
|
return 0;
|
2008-04-07 07:38:49 +08:00
|
|
|
if (LHSR > RHSR)
|
2007-08-27 23:30:22 +08:00
|
|
|
return 1;
|
|
|
|
return -1;
|
2007-04-28 02:30:00 +08:00
|
|
|
}
|
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
|
|
|
|
/// routine will assert if passed a built-in type that isn't an integer or enum,
|
|
|
|
/// or if it is not canonicalized.
|
2009-02-13 10:31:07 +08:00
|
|
|
unsigned ASTContext::getIntegerRank(Type *T) {
|
2008-04-07 06:59:24 +08:00
|
|
|
assert(T->isCanonical() && "T should be canonicalized");
|
2009-02-13 10:31:07 +08:00
|
|
|
if (EnumType* ET = dyn_cast<EnumType>(T))
|
|
|
|
T = ET->getDecl()->getIntegerType().getTypePtr();
|
|
|
|
|
2009-07-06 07:44:27 +08:00
|
|
|
if (T->isSpecificBuiltinType(BuiltinType::WChar))
|
|
|
|
T = getFromTargetType(Target.getWCharType()).getTypePtr();
|
|
|
|
|
2009-07-14 14:30:34 +08:00
|
|
|
if (T->isSpecificBuiltinType(BuiltinType::Char16))
|
|
|
|
T = getFromTargetType(Target.getChar16Type()).getTypePtr();
|
|
|
|
|
|
|
|
if (T->isSpecificBuiltinType(BuiltinType::Char32))
|
|
|
|
T = getFromTargetType(Target.getChar32Type()).getTypePtr();
|
|
|
|
|
2009-02-13 10:31:07 +08:00
|
|
|
// There are two things which impact the integer rank: the width, and
|
|
|
|
// the ordering of builtins. The builtin ordering is encoded in the
|
|
|
|
// bottom three bits; the width is encoded in the bits above that.
|
2009-06-14 09:54:56 +08:00
|
|
|
if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T))
|
2009-02-13 10:31:07 +08:00
|
|
|
return FWIT->getWidth() << 3;
|
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
switch (cast<BuiltinType>(T)->getKind()) {
|
2008-04-07 07:55:33 +08:00
|
|
|
default: assert(0 && "getIntegerRank(): not a built-in integer");
|
|
|
|
case BuiltinType::Bool:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 1 + (getIntWidth(BoolTy) << 3);
|
2008-04-07 07:55:33 +08:00
|
|
|
case BuiltinType::Char_S:
|
|
|
|
case BuiltinType::Char_U:
|
|
|
|
case BuiltinType::SChar:
|
|
|
|
case BuiltinType::UChar:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 2 + (getIntWidth(CharTy) << 3);
|
2008-04-07 07:55:33 +08:00
|
|
|
case BuiltinType::Short:
|
|
|
|
case BuiltinType::UShort:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 3 + (getIntWidth(ShortTy) << 3);
|
2008-04-07 07:55:33 +08:00
|
|
|
case BuiltinType::Int:
|
|
|
|
case BuiltinType::UInt:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 4 + (getIntWidth(IntTy) << 3);
|
2008-04-07 07:55:33 +08:00
|
|
|
case BuiltinType::Long:
|
|
|
|
case BuiltinType::ULong:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 5 + (getIntWidth(LongTy) << 3);
|
2008-04-07 07:55:33 +08:00
|
|
|
case BuiltinType::LongLong:
|
|
|
|
case BuiltinType::ULongLong:
|
2009-02-13 10:31:07 +08:00
|
|
|
return 6 + (getIntWidth(LongLongTy) << 3);
|
2009-04-30 10:43:43 +08:00
|
|
|
case BuiltinType::Int128:
|
|
|
|
case BuiltinType::UInt128:
|
|
|
|
return 7 + (getIntWidth(Int128Ty) << 3);
|
2008-04-07 06:59:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-20 12:21:42 +08:00
|
|
|
/// \brief Whether this is a promotable bitfield reference according
|
|
|
|
/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions).
|
|
|
|
///
|
|
|
|
/// \returns the type this bit-field will promote to, or NULL if no
|
|
|
|
/// promotion occurs.
|
|
|
|
QualType ASTContext::isPromotableBitField(Expr *E) {
|
|
|
|
FieldDecl *Field = E->getBitField();
|
|
|
|
if (!Field)
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
QualType FT = Field->getType();
|
|
|
|
|
|
|
|
llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this);
|
|
|
|
uint64_t BitWidth = BitWidthAP.getZExtValue();
|
|
|
|
uint64_t IntSize = getTypeSize(IntTy);
|
|
|
|
// GCC extension compatibility: if the bit-field size is less than or equal
|
|
|
|
// to the size of int, it gets promoted no matter what its type is.
|
|
|
|
// For instance, unsigned long bf : 4 gets promoted to signed int.
|
|
|
|
if (BitWidth < IntSize)
|
|
|
|
return IntTy;
|
|
|
|
|
|
|
|
if (BitWidth == IntSize)
|
|
|
|
return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy;
|
|
|
|
|
|
|
|
// Types bigger than int are not subject to promotions, and therefore act
|
|
|
|
// like the base type.
|
|
|
|
// FIXME: This doesn't quite match what gcc does, but what gcc does here
|
|
|
|
// is ridiculous.
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
2009-08-19 15:44:53 +08:00
|
|
|
/// getPromotedIntegerType - Returns the type that Promotable will
|
|
|
|
/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
|
|
|
|
/// integer type.
|
|
|
|
QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
|
|
|
|
assert(!Promotable.isNull());
|
|
|
|
assert(Promotable->isPromotableIntegerType());
|
|
|
|
if (Promotable->isSignedIntegerType())
|
|
|
|
return IntTy;
|
|
|
|
uint64_t PromotableSize = getTypeSize(Promotable);
|
|
|
|
uint64_t IntSize = getTypeSize(IntTy);
|
|
|
|
assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
|
|
|
|
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// getIntegerTypeOrder - Returns the highest ranked integer type:
|
2008-04-07 07:55:33 +08:00
|
|
|
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
|
2009-09-09 23:08:12 +08:00
|
|
|
/// LHS < RHS, return -1.
|
2008-04-07 07:55:33 +08:00
|
|
|
int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
|
2008-04-07 06:59:24 +08:00
|
|
|
Type *LHSC = getCanonicalType(LHS).getTypePtr();
|
|
|
|
Type *RHSC = getCanonicalType(RHS).getTypePtr();
|
2008-04-07 07:55:33 +08:00
|
|
|
if (LHSC == RHSC) return 0;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 06:59:24 +08:00
|
|
|
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
|
|
|
|
bool RHSUnsigned = RHSC->isUnsignedIntegerType();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
unsigned LHSRank = getIntegerRank(LHSC);
|
|
|
|
unsigned RHSRank = getIntegerRank(RHSC);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned.
|
|
|
|
if (LHSRank == RHSRank) return 0;
|
|
|
|
return LHSRank > RHSRank ? 1 : -1;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
// Otherwise, the LHS is signed and the RHS is unsigned or visa versa.
|
|
|
|
if (LHSUnsigned) {
|
|
|
|
// If the unsigned [LHS] type is larger, return it.
|
|
|
|
if (LHSRank >= RHSRank)
|
|
|
|
return 1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
// If the signed type can represent all values of the unsigned type, it
|
|
|
|
// wins. Because we are dealing with 2's complement and types that are
|
2009-09-09 23:08:12 +08:00
|
|
|
// powers of two larger than each other, this is always safe.
|
2008-04-07 07:55:33 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the unsigned [RHS] type is larger, return it.
|
|
|
|
if (RHSRank >= LHSRank)
|
|
|
|
return -1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 07:55:33 +08:00
|
|
|
// If the signed type can represent all values of the unsigned type, it
|
|
|
|
// wins. Because we are dealing with 2's complement and types that are
|
2009-09-09 23:08:12 +08:00
|
|
|
// powers of two larger than each other, this is always safe.
|
2008-04-07 07:55:33 +08:00
|
|
|
return 1;
|
2007-04-28 02:30:00 +08:00
|
|
|
}
|
2007-08-17 13:31:46 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// getCFConstantStringType - Return the type used for constant CFStrings.
|
2007-08-17 13:31:46 +08:00
|
|
|
QualType ASTContext::getCFConstantStringType() {
|
|
|
|
if (!CFConstantStringTypeDecl) {
|
2009-09-09 23:08:12 +08:00
|
|
|
CFConstantStringTypeDecl =
|
|
|
|
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
|
2008-09-05 09:34:33 +08:00
|
|
|
&Idents.get("NSConstantString"));
|
2007-11-19 08:25:30 +08:00
|
|
|
QualType FieldTypes[4];
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-17 13:31:46 +08:00
|
|
|
// const int *isa;
|
2009-09-25 03:53:00 +08:00
|
|
|
FieldTypes[0] = getPointerType(IntTy.withConst());
|
2007-11-19 08:25:30 +08:00
|
|
|
// int flags;
|
|
|
|
FieldTypes[1] = IntTy;
|
2007-08-17 13:31:46 +08:00
|
|
|
// const char *str;
|
2009-09-25 03:53:00 +08:00
|
|
|
FieldTypes[2] = getPointerType(CharTy.withConst());
|
2007-08-17 13:31:46 +08:00
|
|
|
// long length;
|
2009-09-09 23:08:12 +08:00
|
|
|
FieldTypes[3] = LongTy;
|
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
// Create fields
|
|
|
|
for (unsigned i = 0; i < 4; ++i) {
|
2009-09-09 23:08:12 +08:00
|
|
|
FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl,
|
2008-12-12 00:49:14 +08:00
|
|
|
SourceLocation(), 0,
|
2009-08-19 09:27:57 +08:00
|
|
|
FieldTypes[i], /*DInfo=*/0,
|
2009-09-09 23:08:12 +08:00
|
|
|
/*BitWidth=*/0,
|
2009-01-20 09:17:11 +08:00
|
|
|
/*Mutable=*/false);
|
2009-06-30 10:36:12 +08:00
|
|
|
CFConstantStringTypeDecl->addDecl(Field);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
CFConstantStringTypeDecl->completeDefinition(*this);
|
2007-08-17 13:31:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-08-17 13:31:46 +08:00
|
|
|
return getTagDeclType(CFConstantStringTypeDecl);
|
2007-09-11 23:32:40 +08:00
|
|
|
}
|
2007-10-11 09:00:40 +08:00
|
|
|
|
2009-04-24 06:29:11 +08:00
|
|
|
void ASTContext::setCFConstantStringType(QualType T) {
|
2009-07-30 05:53:49 +08:00
|
|
|
const RecordType *Rec = T->getAs<RecordType>();
|
2009-04-24 06:29:11 +08:00
|
|
|
assert(Rec && "Invalid CFConstantStringType");
|
|
|
|
CFConstantStringTypeDecl = Rec->getDecl();
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType ASTContext::getObjCFastEnumerationStateType() {
|
2008-08-31 03:34:46 +08:00
|
|
|
if (!ObjCFastEnumerationStateTypeDecl) {
|
2008-12-12 00:49:14 +08:00
|
|
|
ObjCFastEnumerationStateTypeDecl =
|
|
|
|
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
|
|
|
|
&Idents.get("__objcFastEnumerationState"));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-31 03:34:46 +08:00
|
|
|
QualType FieldTypes[] = {
|
|
|
|
UnsignedLongTy,
|
2009-07-16 02:40:39 +08:00
|
|
|
getPointerType(ObjCIdTypedefType),
|
2008-08-31 03:34:46 +08:00
|
|
|
getPointerType(UnsignedLongTy),
|
|
|
|
getConstantArrayType(UnsignedLongTy,
|
|
|
|
llvm::APInt(32, 5), ArrayType::Normal, 0)
|
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
for (size_t i = 0; i < 4; ++i) {
|
2009-09-09 23:08:12 +08:00
|
|
|
FieldDecl *Field = FieldDecl::Create(*this,
|
|
|
|
ObjCFastEnumerationStateTypeDecl,
|
|
|
|
SourceLocation(), 0,
|
2009-08-19 09:27:57 +08:00
|
|
|
FieldTypes[i], /*DInfo=*/0,
|
2009-09-09 23:08:12 +08:00
|
|
|
/*BitWidth=*/0,
|
2009-01-20 09:17:11 +08:00
|
|
|
/*Mutable=*/false);
|
2009-06-30 10:36:12 +08:00
|
|
|
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
|
2008-12-12 00:49:14 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-12 00:49:14 +08:00
|
|
|
ObjCFastEnumerationStateTypeDecl->completeDefinition(*this);
|
2008-08-31 03:34:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-31 03:34:46 +08:00
|
|
|
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
|
|
|
|
}
|
|
|
|
|
2009-10-20 10:12:22 +08:00
|
|
|
QualType ASTContext::getBlockDescriptorType() {
|
|
|
|
if (BlockDescriptorType)
|
|
|
|
return getTagDeclType(BlockDescriptorType);
|
|
|
|
|
|
|
|
RecordDecl *T;
|
|
|
|
// FIXME: Needs the FlagAppleBlock bit.
|
|
|
|
T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
|
|
|
|
&Idents.get("__block_descriptor"));
|
|
|
|
|
|
|
|
QualType FieldTypes[] = {
|
|
|
|
UnsignedLongTy,
|
|
|
|
UnsignedLongTy,
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *FieldNames[] = {
|
|
|
|
"reserved",
|
|
|
|
"Size",
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
|
|
FieldDecl *Field = FieldDecl::Create(*this,
|
|
|
|
T,
|
|
|
|
SourceLocation(),
|
|
|
|
&Idents.get(FieldNames[i]),
|
|
|
|
FieldTypes[i], /*DInfo=*/0,
|
|
|
|
/*BitWidth=*/0,
|
|
|
|
/*Mutable=*/false);
|
|
|
|
T->addDecl(Field);
|
|
|
|
}
|
|
|
|
|
|
|
|
T->completeDefinition(*this);
|
|
|
|
|
|
|
|
BlockDescriptorType = T;
|
|
|
|
|
|
|
|
return getTagDeclType(BlockDescriptorType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTContext::setBlockDescriptorType(QualType T) {
|
|
|
|
const RecordType *Rec = T->getAs<RecordType>();
|
|
|
|
assert(Rec && "Invalid BlockDescriptorType");
|
|
|
|
BlockDescriptorType = Rec->getDecl();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTContext::getBlockParmType() {
|
|
|
|
// FIXME: Move up
|
|
|
|
static int UniqueBlockParmTypeID = 0;
|
|
|
|
char Name[36];
|
|
|
|
sprintf(Name, "__block_literal_%u", ++UniqueBlockParmTypeID);
|
|
|
|
RecordDecl *T;
|
|
|
|
T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
|
|
|
|
&Idents.get(Name));
|
|
|
|
|
|
|
|
#define REV2
|
|
|
|
#ifdef REV2
|
|
|
|
cast<TagDecl>(T)->startDefinition();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return getPointerType(getTagDeclType(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ASTContext::completeBlockParmType(QualType Ty,
|
|
|
|
llvm::SmallVector<const Expr *, 8> &BlockDeclRefDecls) {
|
|
|
|
RecordDecl *PT = Ty->getPointeeType()->getAs<RecordType>()->getDecl();
|
|
|
|
llvm::StringRef Name = PT->getIdentifier()->getName();
|
|
|
|
|
|
|
|
RecordDecl *T;
|
|
|
|
#ifdef REV2
|
|
|
|
T = PT;
|
|
|
|
#else
|
|
|
|
T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
|
|
|
|
&Idents.get(Name), SourceLocation(), PT);
|
|
|
|
|
|
|
|
cast<TagDecl>(T)->startDefinition();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QualType FieldTypes[] = {
|
|
|
|
getPointerType(VoidPtrTy),
|
|
|
|
IntTy,
|
|
|
|
IntTy,
|
|
|
|
getPointerType(VoidPtrTy),
|
|
|
|
getPointerType(getBlockDescriptorType()),
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *FieldNames[] = {
|
|
|
|
"__isa",
|
|
|
|
"__flags",
|
|
|
|
"__reserved",
|
|
|
|
"__FuncPtr",
|
|
|
|
"__descriptor"
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 5; ++i) {
|
|
|
|
FieldDecl *Field = FieldDecl::Create(*this,
|
|
|
|
T,
|
|
|
|
SourceLocation(),
|
|
|
|
&Idents.get(FieldNames[i]),
|
|
|
|
FieldTypes[i], /*DInfo=*/0,
|
|
|
|
/*BitWidth=*/0,
|
|
|
|
/*Mutable=*/false);
|
|
|
|
// FIXME: Do this instead or addDecl?
|
|
|
|
// PushOnScopeChains(FieldTypes, S);
|
|
|
|
T->addDecl(Field);
|
|
|
|
}
|
|
|
|
|
|
|
|
T->completeDefinition(*this);
|
|
|
|
}
|
|
|
|
|
2009-04-24 06:29:11 +08:00
|
|
|
void ASTContext::setObjCFastEnumerationStateType(QualType T) {
|
2009-07-30 05:53:49 +08:00
|
|
|
const RecordType *Rec = T->getAs<RecordType>();
|
2009-04-24 06:29:11 +08:00
|
|
|
assert(Rec && "Invalid ObjCFAstEnumerationStateType");
|
|
|
|
ObjCFastEnumerationStateTypeDecl = Rec->getDecl();
|
|
|
|
}
|
|
|
|
|
2007-10-29 14:33:42 +08:00
|
|
|
// This returns true if a type has been typedefed to BOOL:
|
|
|
|
// typedef <type> BOOL;
|
2007-10-31 04:27:44 +08:00
|
|
|
static bool isTypeTypedefedAsBOOL(QualType T) {
|
2007-10-29 14:33:42 +08:00
|
|
|
if (const TypedefType *TT = dyn_cast<TypedefType>(T))
|
2008-11-24 11:52:59 +08:00
|
|
|
if (IdentifierInfo *II = TT->getDecl()->getIdentifier())
|
|
|
|
return II->isStr("BOOL");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-29 13:01:08 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
2007-10-30 06:57:28 +08:00
|
|
|
/// purpose.
|
2008-01-08 03:49:32 +08:00
|
|
|
int ASTContext::getObjCEncodingTypeSize(QualType type) {
|
2008-03-06 02:54:05 +08:00
|
|
|
uint64_t sz = getTypeSize(type);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-30 06:57:28 +08:00
|
|
|
// Make all integer and enum types at least as large as an int
|
|
|
|
if (sz > 0 && type->isIntegralType())
|
2008-03-06 02:54:05 +08:00
|
|
|
sz = std::max(sz, getTypeSize(IntTy));
|
2007-10-30 06:57:28 +08:00
|
|
|
// Treat arrays as pointers, since that's how they're passed in.
|
|
|
|
else if (type->isArrayType())
|
2008-03-06 02:54:05 +08:00
|
|
|
sz = getTypeSize(VoidPtrTy);
|
|
|
|
return sz / getTypeSize(CharTy);
|
2007-10-30 06:57:28 +08:00
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
|
2007-10-30 06:57:28 +08:00
|
|
|
/// declaration.
|
2009-09-09 23:08:12 +08:00
|
|
|
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
|
2008-11-19 15:24:05 +08:00
|
|
|
std::string& S) {
|
2008-08-28 12:38:10 +08:00
|
|
|
// FIXME: This is not very efficient.
|
2007-11-02 01:18:37 +08:00
|
|
|
// Encode type qualifer, 'in', 'inout', etc. for the return type.
|
2008-01-08 03:49:32 +08:00
|
|
|
getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
|
2007-10-30 06:57:28 +08:00
|
|
|
// Encode result type.
|
2008-10-18 04:21:44 +08:00
|
|
|
getObjCEncodingForType(Decl->getResultType(), S);
|
2007-10-30 06:57:28 +08:00
|
|
|
// Compute size of all parameters.
|
|
|
|
// Start with computing size of a pointer in number of bytes.
|
|
|
|
// FIXME: There might(should) be a better way of doing this computation!
|
|
|
|
SourceLocation Loc;
|
2008-03-06 02:54:05 +08:00
|
|
|
int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
|
2007-10-30 06:57:28 +08:00
|
|
|
// The first two arguments (self and _cmd) are pointers; account for
|
|
|
|
// their size.
|
|
|
|
int ParmOffset = 2 * PtrSize;
|
2009-02-21 02:43:26 +08:00
|
|
|
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
|
|
|
|
E = Decl->param_end(); PI != E; ++PI) {
|
|
|
|
QualType PType = (*PI)->getType();
|
|
|
|
int sz = getObjCEncodingTypeSize(PType);
|
2008-01-08 03:49:32 +08:00
|
|
|
assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
|
2007-10-30 06:57:28 +08:00
|
|
|
ParmOffset += sz;
|
|
|
|
}
|
|
|
|
S += llvm::utostr(ParmOffset);
|
|
|
|
S += "@0:";
|
|
|
|
S += llvm::utostr(PtrSize);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-30 06:57:28 +08:00
|
|
|
// Argument types.
|
|
|
|
ParmOffset = 2 * PtrSize;
|
2009-02-21 02:43:26 +08:00
|
|
|
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
|
|
|
|
E = Decl->param_end(); PI != E; ++PI) {
|
|
|
|
ParmVarDecl *PVDecl = *PI;
|
2009-09-09 23:08:12 +08:00
|
|
|
QualType PType = PVDecl->getOriginalType();
|
2008-12-21 07:29:59 +08:00
|
|
|
if (const ArrayType *AT =
|
2009-04-14 08:03:58 +08:00
|
|
|
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
|
|
|
|
// Use array's original type only if it has known number of
|
|
|
|
// elements.
|
2009-04-14 08:40:09 +08:00
|
|
|
if (!isa<ConstantArrayType>(AT))
|
2009-04-14 08:03:58 +08:00
|
|
|
PType = PVDecl->getType();
|
|
|
|
} else if (PType->isFunctionType())
|
|
|
|
PType = PVDecl->getType();
|
2007-11-02 01:18:37 +08:00
|
|
|
// Process argument qualifiers for user supplied arguments; such as,
|
2007-10-30 06:57:28 +08:00
|
|
|
// 'in', 'inout', etc.
|
2008-12-21 07:29:59 +08:00
|
|
|
getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
|
2008-10-18 04:21:44 +08:00
|
|
|
getObjCEncodingForType(PType, S);
|
2007-10-30 06:57:28 +08:00
|
|
|
S += llvm::utostr(ParmOffset);
|
2008-01-08 03:49:32 +08:00
|
|
|
ParmOffset += getObjCEncodingTypeSize(PType);
|
2007-10-30 06:57:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-28 12:38:10 +08:00
|
|
|
/// getObjCEncodingForPropertyDecl - Return the encoded type for this
|
2009-01-21 04:04:12 +08:00
|
|
|
/// property declaration. If non-NULL, Container must be either an
|
2008-08-28 12:38:10 +08:00
|
|
|
/// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be
|
|
|
|
/// NULL when getting encodings for protocol properties.
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Property attributes are stored as a comma-delimited C string. The simple
|
|
|
|
/// attributes readonly and bycopy are encoded as single characters. The
|
|
|
|
/// parametrized attributes, getter=name, setter=name, and ivar=name, are
|
|
|
|
/// encoded as single characters, followed by an identifier. Property types
|
|
|
|
/// are also encoded as a parametrized attribute. The characters used to encode
|
2009-01-21 04:04:12 +08:00
|
|
|
/// these attributes are defined by the following enumeration:
|
|
|
|
/// @code
|
|
|
|
/// enum PropertyAttributes {
|
|
|
|
/// kPropertyReadOnly = 'R', // property is read-only.
|
|
|
|
/// kPropertyBycopy = 'C', // property is a copy of the value last assigned
|
|
|
|
/// kPropertyByref = '&', // property is a reference to the value last assigned
|
|
|
|
/// kPropertyDynamic = 'D', // property is dynamic
|
|
|
|
/// kPropertyGetter = 'G', // followed by getter selector name
|
|
|
|
/// kPropertySetter = 'S', // followed by setter selector name
|
|
|
|
/// kPropertyInstanceVariable = 'V' // followed by instance variable name
|
|
|
|
/// kPropertyType = 't' // followed by old-style type encoding.
|
|
|
|
/// kPropertyWeak = 'W' // 'weak' property
|
|
|
|
/// kPropertyStrong = 'P' // property GC'able
|
|
|
|
/// kPropertyNonAtomic = 'N' // property non-atomic
|
|
|
|
/// };
|
|
|
|
/// @endcode
|
2009-09-09 23:08:12 +08:00
|
|
|
void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
|
2008-08-28 12:38:10 +08:00
|
|
|
const Decl *Container,
|
2008-11-19 15:24:05 +08:00
|
|
|
std::string& S) {
|
2008-08-28 12:38:10 +08:00
|
|
|
// Collect information from the property implementation decl(s).
|
|
|
|
bool Dynamic = false;
|
|
|
|
ObjCPropertyImplDecl *SynthesizePID = 0;
|
|
|
|
|
|
|
|
// FIXME: Duplicated code due to poor abstraction.
|
|
|
|
if (Container) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const ObjCCategoryImplDecl *CID =
|
2008-08-28 12:38:10 +08:00
|
|
|
dyn_cast<ObjCCategoryImplDecl>(Container)) {
|
|
|
|
for (ObjCCategoryImplDecl::propimpl_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
i = CID->propimpl_begin(), e = CID->propimpl_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
i != e; ++i) {
|
2008-08-28 12:38:10 +08:00
|
|
|
ObjCPropertyImplDecl *PID = *i;
|
|
|
|
if (PID->getPropertyDecl() == PD) {
|
|
|
|
if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
|
|
|
|
Dynamic = true;
|
|
|
|
} else {
|
|
|
|
SynthesizePID = PID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2008-10-06 01:34:18 +08:00
|
|
|
const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container);
|
2008-08-28 12:38:10 +08:00
|
|
|
for (ObjCCategoryImplDecl::propimpl_iterator
|
2009-06-30 10:36:12 +08:00
|
|
|
i = OID->propimpl_begin(), e = OID->propimpl_end();
|
2009-04-23 09:02:12 +08:00
|
|
|
i != e; ++i) {
|
2008-08-28 12:38:10 +08:00
|
|
|
ObjCPropertyImplDecl *PID = *i;
|
|
|
|
if (PID->getPropertyDecl() == PD) {
|
|
|
|
if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) {
|
|
|
|
Dynamic = true;
|
|
|
|
} else {
|
|
|
|
SynthesizePID = PID;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2008-08-28 12:38:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: This is not very efficient.
|
|
|
|
S = "T";
|
|
|
|
|
|
|
|
// Encode result type.
|
2009-01-21 03:14:18 +08:00
|
|
|
// GCC has some special rules regarding encoding of properties which
|
|
|
|
// closely resembles encoding of ivars.
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0,
|
2009-01-21 03:14:18 +08:00
|
|
|
true /* outermost type */,
|
|
|
|
true /* encoding for property */);
|
2008-08-28 12:38:10 +08:00
|
|
|
|
|
|
|
if (PD->isReadOnly()) {
|
|
|
|
S += ",R";
|
|
|
|
} else {
|
|
|
|
switch (PD->getSetterKind()) {
|
|
|
|
case ObjCPropertyDecl::Assign: break;
|
|
|
|
case ObjCPropertyDecl::Copy: S += ",C"; break;
|
2009-09-09 23:08:12 +08:00
|
|
|
case ObjCPropertyDecl::Retain: S += ",&"; break;
|
2008-08-28 12:38:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// It really isn't clear at all what this means, since properties
|
|
|
|
// are "dynamic by default".
|
|
|
|
if (Dynamic)
|
|
|
|
S += ",D";
|
|
|
|
|
2009-01-21 03:14:18 +08:00
|
|
|
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic)
|
|
|
|
S += ",N";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-28 12:38:10 +08:00
|
|
|
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) {
|
|
|
|
S += ",G";
|
2008-11-24 11:33:13 +08:00
|
|
|
S += PD->getGetterName().getAsString();
|
2008-08-28 12:38:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) {
|
|
|
|
S += ",S";
|
2008-11-24 11:33:13 +08:00
|
|
|
S += PD->getSetterName().getAsString();
|
2008-08-28 12:38:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (SynthesizePID) {
|
|
|
|
const ObjCIvarDecl *OID = SynthesizePID->getPropertyIvarDecl();
|
|
|
|
S += ",V";
|
2008-11-24 12:00:27 +08:00
|
|
|
S += OID->getNameAsString();
|
2008-08-28 12:38:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: OBJCGC: weak & strong
|
|
|
|
}
|
|
|
|
|
2008-12-24 03:56:47 +08:00
|
|
|
/// getLegacyIntegralTypeEncoding -
|
2009-09-09 23:08:12 +08:00
|
|
|
/// Another legacy compatibility encoding: 32-bit longs are encoded as
|
|
|
|
/// 'l' or 'L' , but not always. For typedefs, we need to use
|
2008-12-24 03:56:47 +08:00
|
|
|
/// 'i' or 'I' instead if encoding a struct field, or a pointer!
|
|
|
|
///
|
|
|
|
void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
|
2009-07-23 02:58:19 +08:00
|
|
|
if (isa<TypedefType>(PointeeTy.getTypePtr())) {
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) {
|
2009-02-12 07:59:18 +08:00
|
|
|
if (BT->getKind() == BuiltinType::ULong &&
|
|
|
|
((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
|
2008-12-24 03:56:47 +08:00
|
|
|
PointeeTy = UnsignedIntTy;
|
2009-09-09 23:08:12 +08:00
|
|
|
else
|
2009-02-12 07:59:18 +08:00
|
|
|
if (BT->getKind() == BuiltinType::Long &&
|
|
|
|
((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
|
2008-12-24 03:56:47 +08:00
|
|
|
PointeeTy = IntTy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-23 06:44:46 +08:00
|
|
|
void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
|
2009-04-20 14:37:24 +08:00
|
|
|
const FieldDecl *Field) {
|
2008-10-17 15:30:50 +08:00
|
|
|
// We follow the behavior of gcc, expanding structures which are
|
|
|
|
// directly pointed to, and expanding embedded structures. Note that
|
|
|
|
// these rules are sufficient to prevent recursive encoding of the
|
|
|
|
// same type.
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(T, S, true, true, Field,
|
2008-12-23 07:22:27 +08:00
|
|
|
true /* outermost type */);
|
2008-10-17 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
static void EncodeBitField(const ASTContext *Context, std::string& S,
|
2009-04-20 14:37:24 +08:00
|
|
|
const FieldDecl *FD) {
|
2009-01-13 09:18:13 +08:00
|
|
|
const Expr *E = FD->getBitWidth();
|
|
|
|
assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
|
|
|
|
ASTContext *Ctx = const_cast<ASTContext*>(Context);
|
2009-04-27 03:19:15 +08:00
|
|
|
unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
|
2009-01-13 09:18:13 +08:00
|
|
|
S += 'b';
|
|
|
|
S += llvm::utostr(N);
|
|
|
|
}
|
|
|
|
|
2009-10-19 05:17:35 +08:00
|
|
|
// FIXME: Use SmallString for accumulating string.
|
2008-10-17 15:30:50 +08:00
|
|
|
void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
|
|
|
|
bool ExpandPointedToStructures,
|
|
|
|
bool ExpandStructures,
|
2009-04-20 14:37:24 +08:00
|
|
|
const FieldDecl *FD,
|
2009-01-21 03:14:18 +08:00
|
|
|
bool OutermostType,
|
2009-04-10 05:40:53 +08:00
|
|
|
bool EncodingProperty) {
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const BuiltinType *BT = T->getAs<BuiltinType>()) {
|
2009-07-13 08:10:46 +08:00
|
|
|
if (FD && FD->isBitField())
|
|
|
|
return EncodeBitField(this, S, FD);
|
|
|
|
char encoding;
|
|
|
|
switch (BT->getKind()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
default: assert(0 && "Unhandled builtin type kind");
|
2009-07-13 08:10:46 +08:00
|
|
|
case BuiltinType::Void: encoding = 'v'; break;
|
|
|
|
case BuiltinType::Bool: encoding = 'B'; break;
|
|
|
|
case BuiltinType::Char_U:
|
|
|
|
case BuiltinType::UChar: encoding = 'C'; break;
|
|
|
|
case BuiltinType::UShort: encoding = 'S'; break;
|
|
|
|
case BuiltinType::UInt: encoding = 'I'; break;
|
2009-09-09 23:08:12 +08:00
|
|
|
case BuiltinType::ULong:
|
|
|
|
encoding =
|
|
|
|
(const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q';
|
2009-02-12 06:31:45 +08:00
|
|
|
break;
|
2009-07-13 08:10:46 +08:00
|
|
|
case BuiltinType::UInt128: encoding = 'T'; break;
|
|
|
|
case BuiltinType::ULongLong: encoding = 'Q'; break;
|
|
|
|
case BuiltinType::Char_S:
|
|
|
|
case BuiltinType::SChar: encoding = 'c'; break;
|
|
|
|
case BuiltinType::Short: encoding = 's'; break;
|
|
|
|
case BuiltinType::Int: encoding = 'i'; break;
|
2009-09-09 23:08:12 +08:00
|
|
|
case BuiltinType::Long:
|
|
|
|
encoding =
|
|
|
|
(const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q';
|
2009-07-13 08:10:46 +08:00
|
|
|
break;
|
|
|
|
case BuiltinType::LongLong: encoding = 'q'; break;
|
|
|
|
case BuiltinType::Int128: encoding = 't'; break;
|
|
|
|
case BuiltinType::Float: encoding = 'f'; break;
|
|
|
|
case BuiltinType::Double: encoding = 'd'; break;
|
|
|
|
case BuiltinType::LongDouble: encoding = 'd'; break;
|
2008-12-20 07:34:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
S += encoding;
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ComplexType *CT = T->getAs<ComplexType>()) {
|
2009-04-10 05:55:45 +08:00
|
|
|
S += 'j';
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
|
2009-04-10 05:55:45 +08:00
|
|
|
false);
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const PointerType *PT = T->getAs<PointerType>()) {
|
2007-10-29 13:01:08 +08:00
|
|
|
QualType PointeeTy = PT->getPointeeType();
|
2008-12-24 03:56:47 +08:00
|
|
|
bool isReadOnly = false;
|
|
|
|
// For historical/compatibility reasons, the read-only qualifier of the
|
|
|
|
// pointee gets emitted _before_ the '^'. The read-only qualifier of
|
|
|
|
// the pointer itself gets ignored, _unless_ we are looking at a typedef!
|
2009-09-09 23:08:12 +08:00
|
|
|
// Also, do not emit the 'r' for anything but the outermost type!
|
2009-07-23 02:58:19 +08:00
|
|
|
if (isa<TypedefType>(T.getTypePtr())) {
|
2008-12-24 03:56:47 +08:00
|
|
|
if (OutermostType && T.isConstQualified()) {
|
|
|
|
isReadOnly = true;
|
|
|
|
S += 'r';
|
|
|
|
}
|
2009-07-31 10:02:20 +08:00
|
|
|
} else if (OutermostType) {
|
2008-12-24 03:56:47 +08:00
|
|
|
QualType P = PointeeTy;
|
2009-07-30 05:53:49 +08:00
|
|
|
while (P->getAs<PointerType>())
|
|
|
|
P = P->getAs<PointerType>()->getPointeeType();
|
2008-12-24 03:56:47 +08:00
|
|
|
if (P.isConstQualified()) {
|
|
|
|
isReadOnly = true;
|
|
|
|
S += 'r';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isReadOnly) {
|
|
|
|
// Another legacy compatibility encoding. Some ObjC qualifier and type
|
|
|
|
// combinations need to be rearranged.
|
|
|
|
// Rewrite "in const" from "nr" to "rn"
|
|
|
|
const char * s = S.c_str();
|
|
|
|
int len = S.length();
|
|
|
|
if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') {
|
|
|
|
std::string replace = "rn";
|
|
|
|
S.replace(S.end()-2, S.end(), replace);
|
|
|
|
}
|
|
|
|
}
|
2009-07-11 07:34:53 +08:00
|
|
|
if (isObjCSelType(PointeeTy)) {
|
2007-10-31 10:53:19 +08:00
|
|
|
S += ':';
|
|
|
|
return;
|
2007-10-31 01:06:23 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-29 13:01:08 +08:00
|
|
|
if (PointeeTy->isCharType()) {
|
|
|
|
// char pointer types should be encoded as '*' unless it is a
|
|
|
|
// type that has been typedef'd to 'BOOL'.
|
2007-10-29 14:33:42 +08:00
|
|
|
if (!isTypeTypedefedAsBOOL(PointeeTy)) {
|
2007-10-29 13:01:08 +08:00
|
|
|
S += '*';
|
|
|
|
return;
|
|
|
|
}
|
2009-07-30 05:53:49 +08:00
|
|
|
} else if (const RecordType *RTy = PointeeTy->getAs<RecordType>()) {
|
2009-07-23 01:14:51 +08:00
|
|
|
// GCC binary compat: Need to convert "struct objc_class *" to "#".
|
|
|
|
if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) {
|
|
|
|
S += '#';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// GCC binary compat: Need to convert "struct objc_object *" to "@".
|
|
|
|
if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) {
|
|
|
|
S += '@';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// fall through...
|
2007-10-29 13:01:08 +08:00
|
|
|
}
|
|
|
|
S += '^';
|
2008-12-24 03:56:47 +08:00
|
|
|
getLegacyIntegralTypeEncoding(PointeeTy);
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures,
|
2008-12-20 07:34:38 +08:00
|
|
|
NULL);
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
if (const ArrayType *AT =
|
|
|
|
// Ignore type qualifiers etc.
|
|
|
|
dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
|
2009-02-22 09:38:57 +08:00
|
|
|
if (isa<IncompleteArrayType>(AT)) {
|
|
|
|
// Incomplete arrays are encoded as a pointer to the array element.
|
|
|
|
S += '^';
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(AT->getElementType(), S,
|
2009-02-22 09:38:57 +08:00
|
|
|
false, ExpandStructures, FD);
|
|
|
|
} else {
|
|
|
|
S += '[';
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-22 09:38:57 +08:00
|
|
|
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
|
|
|
|
S += llvm::utostr(CAT->getSize().getZExtValue());
|
|
|
|
else {
|
|
|
|
//Variable length arrays are encoded as a regular array with 0 elements.
|
|
|
|
assert(isa<VariableArrayType>(AT) && "Unknown array type!");
|
|
|
|
S += '0';
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
getObjCEncodingForTypeImpl(AT->getElementType(), S,
|
2009-02-22 09:38:57 +08:00
|
|
|
false, ExpandStructures, FD);
|
|
|
|
S += ']';
|
|
|
|
}
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
if (T->getAs<FunctionType>()) {
|
2007-10-30 08:06:20 +08:00
|
|
|
S += '?';
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const RecordType *RTy = T->getAs<RecordType>()) {
|
2008-10-17 15:30:50 +08:00
|
|
|
RecordDecl *RDecl = RTy->getDecl();
|
2008-10-18 00:17:37 +08:00
|
|
|
S += RDecl->isUnion() ? '(' : '{';
|
2008-10-17 14:22:57 +08:00
|
|
|
// Anonymous structures print as '?'
|
|
|
|
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
|
|
|
|
S += II->getName();
|
|
|
|
} else {
|
|
|
|
S += '?';
|
|
|
|
}
|
2008-10-18 04:21:44 +08:00
|
|
|
if (ExpandStructures) {
|
2008-01-23 06:44:46 +08:00
|
|
|
S += '=';
|
2009-06-30 10:36:12 +08:00
|
|
|
for (RecordDecl::field_iterator Field = RDecl->field_begin(),
|
|
|
|
FieldEnd = RDecl->field_end();
|
2008-12-12 00:49:14 +08:00
|
|
|
Field != FieldEnd; ++Field) {
|
2008-12-20 07:34:38 +08:00
|
|
|
if (FD) {
|
2008-10-18 00:17:37 +08:00
|
|
|
S += '"';
|
2008-12-12 00:49:14 +08:00
|
|
|
S += Field->getNameAsString();
|
2008-10-18 00:17:37 +08:00
|
|
|
S += '"';
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-10-18 00:17:37 +08:00
|
|
|
// Special case bit-fields.
|
2008-12-20 07:34:38 +08:00
|
|
|
if (Field->isBitField()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
|
2008-12-20 07:34:38 +08:00
|
|
|
(*Field));
|
2008-10-18 00:17:37 +08:00
|
|
|
} else {
|
2008-12-24 03:56:47 +08:00
|
|
|
QualType qt = Field->getType();
|
|
|
|
getLegacyIntegralTypeEncoding(qt);
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(qt, S, false, true,
|
2008-12-20 07:34:38 +08:00
|
|
|
FD);
|
2008-10-18 00:17:37 +08:00
|
|
|
}
|
2008-01-23 06:44:46 +08:00
|
|
|
}
|
2007-11-14 07:21:38 +08:00
|
|
|
}
|
2008-10-18 00:17:37 +08:00
|
|
|
S += RDecl->isUnion() ? ')' : '}';
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
if (T->isEnumeralType()) {
|
2009-01-13 09:18:13 +08:00
|
|
|
if (FD && FD->isBitField())
|
|
|
|
EncodeBitField(this, S, FD);
|
|
|
|
else
|
|
|
|
S += 'i';
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
if (T->isBlockPointerType()) {
|
2009-02-03 02:24:29 +08:00
|
|
|
S += "@?"; // Unlike a pointer-to-function, which is "^?".
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
|
2008-12-20 07:34:38 +08:00
|
|
|
// @encode(class_name)
|
2009-09-25 03:53:00 +08:00
|
|
|
ObjCInterfaceDecl *OI = OIT->getDecl();
|
2008-12-20 07:34:38 +08:00
|
|
|
S += '{';
|
|
|
|
const IdentifierInfo *II = OI->getIdentifier();
|
|
|
|
S += II->getName();
|
|
|
|
S += '=';
|
2009-03-31 16:48:01 +08:00
|
|
|
llvm::SmallVector<FieldDecl*, 32> RecFields;
|
2008-12-20 07:34:38 +08:00
|
|
|
CollectObjCIvars(OI, RecFields);
|
2009-03-31 16:48:01 +08:00
|
|
|
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
|
2008-12-20 07:34:38 +08:00
|
|
|
if (RecFields[i]->isBitField())
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
|
2008-12-20 07:34:38 +08:00
|
|
|
RecFields[i]);
|
|
|
|
else
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true,
|
2008-12-20 07:34:38 +08:00
|
|
|
FD);
|
|
|
|
}
|
|
|
|
S += '}';
|
2009-07-13 08:10:46 +08:00
|
|
|
return;
|
2008-12-20 07:34:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
|
2009-07-11 07:34:53 +08:00
|
|
|
if (OPT->isObjCIdType()) {
|
|
|
|
S += '@';
|
|
|
|
return;
|
2009-07-13 08:10:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
if (OPT->isObjCClassType()) {
|
2009-07-11 07:34:53 +08:00
|
|
|
S += '#';
|
|
|
|
return;
|
2009-07-13 08:10:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
if (OPT->isObjCQualifiedIdType()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(getObjCIdType(), S,
|
2009-07-11 07:34:53 +08:00
|
|
|
ExpandPointedToStructures,
|
|
|
|
ExpandStructures, FD);
|
|
|
|
if (FD || EncodingProperty) {
|
|
|
|
// Note that we do extended encoding of protocol qualifer list
|
|
|
|
// Only when doing ivar or property encoding.
|
|
|
|
S += '"';
|
2009-07-21 01:56:53 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
|
|
|
|
E = OPT->qual_end(); I != E; ++I) {
|
2009-07-11 07:34:53 +08:00
|
|
|
S += '<';
|
|
|
|
S += (*I)->getNameAsString();
|
|
|
|
S += '>';
|
|
|
|
}
|
|
|
|
S += '"';
|
|
|
|
}
|
|
|
|
return;
|
2009-07-13 08:10:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
QualType PointeeTy = OPT->getPointeeType();
|
|
|
|
if (!EncodingProperty &&
|
|
|
|
isa<TypedefType>(PointeeTy.getTypePtr())) {
|
|
|
|
// Another historical/compatibility reason.
|
2009-09-09 23:08:12 +08:00
|
|
|
// We encode the underlying type which comes out as
|
2009-07-13 08:10:46 +08:00
|
|
|
// {...};
|
|
|
|
S += '^';
|
2009-09-09 23:08:12 +08:00
|
|
|
getObjCEncodingForTypeImpl(PointeeTy, S,
|
|
|
|
false, ExpandPointedToStructures,
|
2009-07-13 08:10:46 +08:00
|
|
|
NULL);
|
2009-07-11 07:34:53 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-07-13 08:10:46 +08:00
|
|
|
|
|
|
|
S += '@';
|
|
|
|
if (FD || EncodingProperty) {
|
|
|
|
S += '"';
|
2009-07-21 01:56:53 +08:00
|
|
|
S += OPT->getInterfaceDecl()->getNameAsCString();
|
|
|
|
for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(),
|
|
|
|
E = OPT->qual_end(); I != E; ++I) {
|
2009-07-13 08:10:46 +08:00
|
|
|
S += '<';
|
|
|
|
S += (*I)->getNameAsString();
|
|
|
|
S += '>';
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-07-13 08:10:46 +08:00
|
|
|
S += '"';
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
assert(0 && "@encode for type not implemented!");
|
2007-10-29 13:01:08 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
|
2007-11-02 01:18:37 +08:00
|
|
|
std::string& S) const {
|
|
|
|
if (QT & Decl::OBJC_TQ_In)
|
|
|
|
S += 'n';
|
|
|
|
if (QT & Decl::OBJC_TQ_Inout)
|
|
|
|
S += 'N';
|
|
|
|
if (QT & Decl::OBJC_TQ_Out)
|
|
|
|
S += 'o';
|
|
|
|
if (QT & Decl::OBJC_TQ_Bycopy)
|
|
|
|
S += 'O';
|
|
|
|
if (QT & Decl::OBJC_TQ_Byref)
|
|
|
|
S += 'R';
|
|
|
|
if (QT & Decl::OBJC_TQ_Oneway)
|
|
|
|
S += 'V';
|
|
|
|
}
|
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
void ASTContext::setBuiltinVaListType(QualType T) {
|
2007-10-11 09:00:40 +08:00
|
|
|
assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-11 09:00:40 +08:00
|
|
|
BuiltinVaListType = T;
|
|
|
|
}
|
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
void ASTContext::setObjCIdType(QualType T) {
|
2009-07-16 02:40:39 +08:00
|
|
|
ObjCIdTypedefType = T;
|
2007-10-15 22:41:52 +08:00
|
|
|
}
|
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
void ASTContext::setObjCSelType(QualType T) {
|
2009-04-24 06:29:11 +08:00
|
|
|
ObjCSelType = T;
|
|
|
|
|
2009-09-22 07:43:11 +08:00
|
|
|
const TypedefType *TT = T->getAs<TypedefType>();
|
2009-04-24 06:29:11 +08:00
|
|
|
if (!TT)
|
|
|
|
return;
|
|
|
|
TypedefDecl *TD = TT->getDecl();
|
2007-10-17 04:40:23 +08:00
|
|
|
|
|
|
|
// typedef struct objc_selector *SEL;
|
2009-07-30 05:53:49 +08:00
|
|
|
const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>();
|
2009-01-17 03:58:32 +08:00
|
|
|
if (!ptr)
|
|
|
|
return;
|
2007-10-17 04:40:23 +08:00
|
|
|
const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
|
2009-01-17 03:58:32 +08:00
|
|
|
if (!rec)
|
|
|
|
return;
|
2007-10-17 04:40:23 +08:00
|
|
|
SelStructType = rec;
|
|
|
|
}
|
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
void ASTContext::setObjCProtoType(QualType QT) {
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCProtoType = QT;
|
2007-10-18 00:58:11 +08:00
|
|
|
}
|
|
|
|
|
2009-07-13 08:10:46 +08:00
|
|
|
void ASTContext::setObjCClassType(QualType T) {
|
2009-07-16 02:40:39 +08:00
|
|
|
ObjCClassTypedefType = T;
|
2007-10-31 10:53:19 +08:00
|
|
|
}
|
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert(ObjCConstantStringType.isNull() &&
|
2007-10-16 07:35:17 +08:00
|
|
|
"'NSConstantString' type already set!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-01-08 03:49:32 +08:00
|
|
|
ObjCConstantStringType = getObjCInterfaceType(Decl);
|
2007-10-16 07:35:17 +08:00
|
|
|
}
|
|
|
|
|
2009-03-31 06:58:21 +08:00
|
|
|
/// \brief Retrieve the template name that represents a qualified
|
|
|
|
/// template name such as \c std::vector.
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
|
2009-03-31 06:58:21 +08:00
|
|
|
bool TemplateKeyword,
|
|
|
|
TemplateDecl *Template) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
QualifiedTemplateName *QTN =
|
|
|
|
QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (!QTN) {
|
|
|
|
QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template);
|
|
|
|
QualifiedTemplateNames.InsertNode(QTN, InsertPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TemplateName(QTN);
|
|
|
|
}
|
|
|
|
|
2009-07-30 02:26:50 +08:00
|
|
|
/// \brief Retrieve the template name that represents a qualified
|
|
|
|
/// template name such as \c std::vector.
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
|
2009-07-30 02:26:50 +08:00
|
|
|
bool TemplateKeyword,
|
|
|
|
OverloadedFunctionDecl *Template) {
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 02:26:50 +08:00
|
|
|
void *InsertPos = 0;
|
|
|
|
QualifiedTemplateName *QTN =
|
|
|
|
QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
if (!QTN) {
|
|
|
|
QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template);
|
|
|
|
QualifiedTemplateNames.InsertNode(QTN, InsertPos);
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-30 02:26:50 +08:00
|
|
|
return TemplateName(QTN);
|
|
|
|
}
|
|
|
|
|
2009-03-31 06:58:21 +08:00
|
|
|
/// \brief Retrieve the template name that represents a dependent
|
|
|
|
/// template name such as \c MetaFun::template apply.
|
2009-09-09 23:08:12 +08:00
|
|
|
TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
|
2009-03-31 06:58:21 +08:00
|
|
|
const IdentifierInfo *Name) {
|
2009-09-09 23:08:12 +08:00
|
|
|
assert((!NNS || NNS->isDependent()) &&
|
2009-09-09 08:23:06 +08:00
|
|
|
"Nested name specifier must be dependent");
|
2009-03-31 06:58:21 +08:00
|
|
|
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
|
|
DependentTemplateName::Profile(ID, NNS, Name);
|
|
|
|
|
|
|
|
void *InsertPos = 0;
|
|
|
|
DependentTemplateName *QTN =
|
|
|
|
DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
|
|
|
|
|
|
|
|
if (QTN)
|
|
|
|
return TemplateName(QTN);
|
|
|
|
|
|
|
|
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
|
|
|
|
if (CanonNNS == NNS) {
|
|
|
|
QTN = new (*this,4) DependentTemplateName(NNS, Name);
|
|
|
|
} else {
|
|
|
|
TemplateName Canon = getDependentTemplateName(CanonNNS, Name);
|
|
|
|
QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon);
|
|
|
|
}
|
|
|
|
|
|
|
|
DependentTemplateNames.InsertNode(QTN, InsertPos);
|
|
|
|
return TemplateName(QTN);
|
|
|
|
}
|
|
|
|
|
2008-11-03 22:12:49 +08:00
|
|
|
/// getFromTargetType - Given one of the integer types provided by
|
2008-11-03 23:57:00 +08:00
|
|
|
/// TargetInfo, produce the corresponding type. The unsigned @p Type
|
|
|
|
/// is actually a value of type @c TargetInfo::IntType.
|
|
|
|
QualType ASTContext::getFromTargetType(unsigned Type) const {
|
2008-11-03 22:12:49 +08:00
|
|
|
switch (Type) {
|
2009-09-09 23:08:12 +08:00
|
|
|
case TargetInfo::NoInt: return QualType();
|
2008-11-03 22:12:49 +08:00
|
|
|
case TargetInfo::SignedShort: return ShortTy;
|
|
|
|
case TargetInfo::UnsignedShort: return UnsignedShortTy;
|
|
|
|
case TargetInfo::SignedInt: return IntTy;
|
|
|
|
case TargetInfo::UnsignedInt: return UnsignedIntTy;
|
|
|
|
case TargetInfo::SignedLong: return LongTy;
|
|
|
|
case TargetInfo::UnsignedLong: return UnsignedLongTy;
|
|
|
|
case TargetInfo::SignedLongLong: return LongLongTy;
|
|
|
|
case TargetInfo::UnsignedLongLong: return UnsignedLongLongTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(false && "Unhandled TargetInfo::IntType value");
|
2008-11-11 09:16:00 +08:00
|
|
|
return QualType();
|
2008-11-03 22:12:49 +08:00
|
|
|
}
|
2008-07-25 07:58:27 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Predicates.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-01-14 07:34:40 +08:00
|
|
|
/// isObjCNSObjectType - Return true if this is an NSObject object using
|
|
|
|
/// NSObject attribute on a c-style pointer type.
|
|
|
|
/// FIXME - Make it work directly on types.
|
2009-07-16 23:41:00 +08:00
|
|
|
/// FIXME: Move to Type.
|
2009-01-14 07:34:40 +08:00
|
|
|
///
|
|
|
|
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
|
|
|
|
if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
|
|
|
|
if (TypedefDecl *TD = TDT->getDecl())
|
2009-06-30 10:34:44 +08:00
|
|
|
if (TD->getAttr<ObjCNSObjectAttr>())
|
2009-01-14 07:34:40 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
return false;
|
2009-01-14 07:34:40 +08:00
|
|
|
}
|
|
|
|
|
2009-02-19 05:49:28 +08:00
|
|
|
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
|
|
|
|
/// garbage collection attribute.
|
|
|
|
///
|
2009-09-25 03:53:00 +08:00
|
|
|
Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
|
|
|
|
Qualifiers::GC GCAttrs = Qualifiers::GCNone;
|
2009-02-19 05:49:28 +08:00
|
|
|
if (getLangOptions().ObjC1 &&
|
|
|
|
getLangOptions().getGCMode() != LangOptions::NonGC) {
|
2009-02-19 06:53:11 +08:00
|
|
|
GCAttrs = Ty.getObjCGCAttr();
|
2009-02-19 05:49:28 +08:00
|
|
|
// Default behavious under objective-c's gc is for objective-c pointers
|
2009-09-09 23:08:12 +08:00
|
|
|
// (or pointers to them) be treated as though they were declared
|
2009-02-20 07:36:06 +08:00
|
|
|
// as __strong.
|
2009-09-25 03:53:00 +08:00
|
|
|
if (GCAttrs == Qualifiers::GCNone) {
|
2009-09-11 07:38:45 +08:00
|
|
|
if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
|
2009-09-25 03:53:00 +08:00
|
|
|
GCAttrs = Qualifiers::Strong;
|
2009-02-20 07:36:06 +08:00
|
|
|
else if (Ty->isPointerType())
|
2009-07-30 05:53:49 +08:00
|
|
|
return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
|
2009-02-20 07:36:06 +08:00
|
|
|
}
|
2009-04-11 08:00:54 +08:00
|
|
|
// Non-pointers have none gc'able attribute regardless of the attribute
|
|
|
|
// set on them.
|
2009-07-16 23:41:00 +08:00
|
|
|
else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType())
|
2009-09-25 03:53:00 +08:00
|
|
|
return Qualifiers::GCNone;
|
2009-02-19 05:49:28 +08:00
|
|
|
}
|
2009-02-19 06:53:11 +08:00
|
|
|
return GCAttrs;
|
2009-02-19 05:49:28 +08:00
|
|
|
}
|
|
|
|
|
2008-04-07 14:51:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Compatibility Testing
|
|
|
|
//===----------------------------------------------------------------------===//
|
2007-11-01 13:03:41 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// areCompatVectorTypes - Return true if the two specified vector types are
|
2008-04-07 14:51:04 +08:00
|
|
|
/// compatible.
|
|
|
|
static bool areCompatVectorTypes(const VectorType *LHS,
|
|
|
|
const VectorType *RHS) {
|
|
|
|
assert(LHS->isCanonical() && RHS->isCanonical());
|
|
|
|
return LHS->getElementType() == RHS->getElementType() &&
|
2008-10-06 01:34:18 +08:00
|
|
|
LHS->getNumElements() == RHS->getNumElements();
|
2008-04-07 14:51:04 +08:00
|
|
|
}
|
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
|
|
|
|
/// inheritance hierarchy of 'rProto'.
|
2009-08-12 06:02:25 +08:00
|
|
|
bool ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
|
|
|
|
ObjCProtocolDecl *rProto) {
|
2009-07-23 09:01:38 +08:00
|
|
|
if (lProto == rProto)
|
2009-07-11 07:34:53 +08:00
|
|
|
return true;
|
2009-07-23 09:01:38 +08:00
|
|
|
for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
|
|
|
|
E = rProto->protocol_end(); PI != E; ++PI)
|
|
|
|
if (ProtocolCompatibleWithProtocol(lProto, *PI))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-11 07:34:53 +08:00
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
|
|
|
|
/// return true if lhs's protocols conform to rhs's protocol; false
|
|
|
|
/// otherwise.
|
|
|
|
bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
|
|
|
|
if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
|
|
|
|
return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
|
|
|
|
/// ObjCQualifiedIDType.
|
|
|
|
bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
|
|
|
|
bool compare) {
|
|
|
|
// Allow id<P..> and an 'id' or void* type in all cases.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (lhs->isVoidPointerType() ||
|
2009-07-23 09:01:38 +08:00
|
|
|
lhs->isObjCIdType() || lhs->isObjCClassType())
|
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
else if (rhs->isVoidPointerType() ||
|
2009-07-23 09:01:38 +08:00
|
|
|
rhs->isObjCIdType() || rhs->isObjCClassType())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
if (!rhsOPT) return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
if (rhsOPT->qual_empty()) {
|
2009-09-09 23:08:12 +08:00
|
|
|
// If the RHS is a unqualified interface pointer "NSString*",
|
2009-07-23 09:01:38 +08:00
|
|
|
// make sure we check the class hierarchy.
|
|
|
|
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
|
|
|
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
|
|
|
E = lhsQID->qual_end(); I != E; ++I) {
|
|
|
|
// when comparing an id<P> on lhs with a static type on rhs,
|
|
|
|
// see if static class implements all of id's protocols, directly or
|
|
|
|
// through its super class and categories.
|
2009-08-12 06:02:25 +08:00
|
|
|
if (!rhsID->ClassImplementsProtocol(*I, true))
|
2009-07-23 09:01:38 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If there are no qualifiers and no interface, we have an 'id'.
|
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
// Both the right and left sides have qualifiers.
|
2009-07-23 09:01:38 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
|
|
|
E = lhsQID->qual_end(); I != E; ++I) {
|
|
|
|
ObjCProtocolDecl *lhsProto = *I;
|
|
|
|
bool match = false;
|
2009-07-16 02:40:39 +08:00
|
|
|
|
|
|
|
// when comparing an id<P> on lhs with a static type on rhs,
|
|
|
|
// see if static class implements all of id's protocols, directly or
|
|
|
|
// through its super class and categories.
|
2009-07-23 09:01:38 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
|
|
|
|
E = rhsOPT->qual_end(); J != E; ++J) {
|
|
|
|
ObjCProtocolDecl *rhsProto = *J;
|
|
|
|
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
|
|
|
|
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
|
|
|
|
match = true;
|
2009-07-17 00:21:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-07-16 02:40:39 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
// If the RHS is a qualified interface pointer "NSString<P>*",
|
2009-07-23 09:01:38 +08:00
|
|
|
// make sure we check the class hierarchy.
|
|
|
|
if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
|
|
|
|
for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
|
|
|
|
E = lhsQID->qual_end(); I != E; ++I) {
|
|
|
|
// when comparing an id<P> on lhs with a static type on rhs,
|
|
|
|
// see if static class implements all of id's protocols, directly or
|
|
|
|
// through its super class and categories.
|
2009-08-12 06:02:25 +08:00
|
|
|
if (rhsID->ClassImplementsProtocol(*I, true)) {
|
2009-07-23 09:01:38 +08:00
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!match)
|
2009-07-16 02:40:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-16 02:40:39 +08:00
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
|
|
|
|
assert(rhsQID && "One of the LHS/RHS should be id<x>");
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
if (const ObjCObjectPointerType *lhsOPT =
|
2009-07-23 09:01:38 +08:00
|
|
|
lhs->getAsObjCInterfacePointerType()) {
|
|
|
|
if (lhsOPT->qual_empty()) {
|
|
|
|
bool match = false;
|
|
|
|
if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
|
|
|
|
for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
|
|
|
|
E = rhsQID->qual_end(); I != E; ++I) {
|
|
|
|
// when comparing an id<P> on lhs with a static type on rhs,
|
|
|
|
// see if static class implements all of id's protocols, directly or
|
|
|
|
// through its super class and categories.
|
2009-08-12 06:02:25 +08:00
|
|
|
if (lhsID->ClassImplementsProtocol(*I, true)) {
|
2009-07-23 09:01:38 +08:00
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!match)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
// Both the right and left sides have qualifiers.
|
2009-07-23 09:01:38 +08:00
|
|
|
for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
|
|
|
|
E = lhsOPT->qual_end(); I != E; ++I) {
|
|
|
|
ObjCProtocolDecl *lhsProto = *I;
|
|
|
|
bool match = false;
|
|
|
|
|
|
|
|
// when comparing an id<P> on lhs with a static type on rhs,
|
|
|
|
// see if static class implements all of id's protocols, directly or
|
|
|
|
// through its super class and categories.
|
|
|
|
for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
|
|
|
|
E = rhsQID->qual_end(); J != E; ++J) {
|
|
|
|
ObjCProtocolDecl *rhsProto = *J;
|
|
|
|
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
|
|
|
|
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
|
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!match)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// canAssignObjCInterfaces - Return true if the two interface types are
|
|
|
|
/// compatible for assignment from RHS to LHS. This handles validation of any
|
|
|
|
/// protocol qualifiers on the LHS or RHS.
|
|
|
|
///
|
|
|
|
bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
|
|
|
|
const ObjCObjectPointerType *RHSOPT) {
|
|
|
|
// If either type represents the built-in 'id' or 'Class' types, return true.
|
|
|
|
if (LHSOPT->isObjCBuiltinType() || RHSOPT->isObjCBuiltinType())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
|
2009-09-09 23:08:12 +08:00
|
|
|
return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
|
|
|
|
QualType(RHSOPT,0),
|
2009-07-23 09:01:38 +08:00
|
|
|
false);
|
|
|
|
|
|
|
|
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
|
|
|
|
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
|
|
|
|
if (LHS && RHS) // We have 2 user-defined types.
|
|
|
|
return canAssignObjCInterfaces(LHS, RHS);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-23 09:01:38 +08:00
|
|
|
return false;
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
|
|
|
|
2008-08-22 08:56:42 +08:00
|
|
|
bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS,
|
|
|
|
const ObjCInterfaceType *RHS) {
|
2008-04-07 14:51:04 +08:00
|
|
|
// Verify that the base decls are compatible: the RHS must be a subclass of
|
|
|
|
// the LHS.
|
|
|
|
if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl()))
|
|
|
|
return false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 14:51:04 +08:00
|
|
|
// RHS must have a superset of the protocols in the LHS. If the LHS is not
|
|
|
|
// protocol qualified at all, then we are good.
|
2009-07-18 23:33:26 +08:00
|
|
|
if (LHS->getNumProtocols() == 0)
|
2008-04-07 14:51:04 +08:00
|
|
|
return true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-07 14:51:04 +08:00
|
|
|
// Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it
|
|
|
|
// isn't a superset.
|
2009-07-18 23:33:26 +08:00
|
|
|
if (RHS->getNumProtocols() == 0)
|
2008-04-07 14:51:04 +08:00
|
|
|
return true; // FIXME: should return false!
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-18 23:33:26 +08:00
|
|
|
for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(),
|
|
|
|
LHSPE = LHS->qual_end();
|
2009-03-02 00:12:44 +08:00
|
|
|
LHSPI != LHSPE; LHSPI++) {
|
|
|
|
bool RHSImplementsProtocol = false;
|
|
|
|
|
|
|
|
// If the RHS doesn't implement the protocol on the left, the types
|
|
|
|
// are incompatible.
|
2009-07-18 23:33:26 +08:00
|
|
|
for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(),
|
2009-07-23 09:01:38 +08:00
|
|
|
RHSPE = RHS->qual_end();
|
2009-07-17 00:21:02 +08:00
|
|
|
RHSPI != RHSPE; RHSPI++) {
|
|
|
|
if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) {
|
2009-03-02 00:12:44 +08:00
|
|
|
RHSImplementsProtocol = true;
|
2009-07-17 00:21:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-03-02 00:12:44 +08:00
|
|
|
}
|
|
|
|
// FIXME: For better diagnostics, consider passing back the protocol name.
|
|
|
|
if (!RHSImplementsProtocol)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// The RHS implements all protocols listed on the LHS.
|
|
|
|
return true;
|
2008-04-07 14:51:04 +08:00
|
|
|
}
|
|
|
|
|
2009-02-13 01:52:19 +08:00
|
|
|
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
|
|
|
|
// get the "pointed to" types
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCObjectPointerType *LHSOPT = LHS->getAs<ObjCObjectPointerType>();
|
|
|
|
const ObjCObjectPointerType *RHSOPT = RHS->getAs<ObjCObjectPointerType>();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-07-11 07:34:53 +08:00
|
|
|
if (!LHSOPT || !RHSOPT)
|
2009-02-13 01:52:19 +08:00
|
|
|
return false;
|
2009-07-11 07:34:53 +08:00
|
|
|
|
|
|
|
return canAssignObjCInterfaces(LHSOPT, RHSOPT) ||
|
|
|
|
canAssignObjCInterfaces(RHSOPT, LHSOPT);
|
2009-02-13 01:52:19 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,
|
2007-10-16 04:41:53 +08:00
|
|
|
/// both shall have the identically qualified version of a compatible type.
|
2009-09-09 23:08:12 +08:00
|
|
|
/// C99 6.2.7p1: Two types have compatible types if their types are the
|
2007-10-16 04:41:53 +08:00
|
|
|
/// same. See 6.7.[2,3,5] for additional rules.
|
2008-08-22 08:56:42 +08:00
|
|
|
bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
|
|
|
|
return !mergeTypes(LHS, RHS).isNull();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
|
2009-09-22 07:43:11 +08:00
|
|
|
const FunctionType *lbase = lhs->getAs<FunctionType>();
|
|
|
|
const FunctionType *rbase = rhs->getAs<FunctionType>();
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase);
|
|
|
|
const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase);
|
2008-08-22 08:56:42 +08:00
|
|
|
bool allLTypes = true;
|
|
|
|
bool allRTypes = true;
|
|
|
|
|
|
|
|
// Check return type
|
|
|
|
QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType());
|
|
|
|
if (retType.isNull()) return QualType();
|
2008-10-06 01:34:18 +08:00
|
|
|
if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType()))
|
|
|
|
allLTypes = false;
|
|
|
|
if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType()))
|
|
|
|
allRTypes = false;
|
2009-07-26 07:24:03 +08:00
|
|
|
// FIXME: double check this
|
2009-07-26 05:26:53 +08:00
|
|
|
bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr();
|
|
|
|
if (NoReturn != lbase->getNoReturnAttr())
|
|
|
|
allLTypes = false;
|
|
|
|
if (NoReturn != rbase->getNoReturnAttr())
|
|
|
|
allRTypes = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-22 08:56:42 +08:00
|
|
|
if (lproto && rproto) { // two C99 style function prototypes
|
2009-05-28 06:11:52 +08:00
|
|
|
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
|
|
|
|
"C++ shouldn't be here");
|
2008-08-22 08:56:42 +08:00
|
|
|
unsigned lproto_nargs = lproto->getNumArgs();
|
|
|
|
unsigned rproto_nargs = rproto->getNumArgs();
|
|
|
|
|
|
|
|
// Compatible functions must have the same number of arguments
|
|
|
|
if (lproto_nargs != rproto_nargs)
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
// Variadic and non-variadic functions aren't compatible
|
|
|
|
if (lproto->isVariadic() != rproto->isVariadic())
|
|
|
|
return QualType();
|
|
|
|
|
2008-10-27 00:43:14 +08:00
|
|
|
if (lproto->getTypeQuals() != rproto->getTypeQuals())
|
|
|
|
return QualType();
|
|
|
|
|
2008-08-22 08:56:42 +08:00
|
|
|
// Check argument compatibility
|
|
|
|
llvm::SmallVector<QualType, 10> types;
|
|
|
|
for (unsigned i = 0; i < lproto_nargs; i++) {
|
|
|
|
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
|
|
|
|
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
|
|
|
|
QualType argtype = mergeTypes(largtype, rargtype);
|
|
|
|
if (argtype.isNull()) return QualType();
|
|
|
|
types.push_back(argtype);
|
2008-10-06 01:34:18 +08:00
|
|
|
if (getCanonicalType(argtype) != getCanonicalType(largtype))
|
|
|
|
allLTypes = false;
|
|
|
|
if (getCanonicalType(argtype) != getCanonicalType(rargtype))
|
|
|
|
allRTypes = false;
|
2008-08-22 08:56:42 +08:00
|
|
|
}
|
|
|
|
if (allLTypes) return lhs;
|
|
|
|
if (allRTypes) return rhs;
|
|
|
|
return getFunctionType(retType, types.begin(), types.size(),
|
2009-07-26 05:26:53 +08:00
|
|
|
lproto->isVariadic(), lproto->getTypeQuals(),
|
|
|
|
NoReturn);
|
2008-08-22 08:56:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lproto) allRTypes = false;
|
|
|
|
if (rproto) allLTypes = false;
|
|
|
|
|
2009-02-27 07:50:07 +08:00
|
|
|
const FunctionProtoType *proto = lproto ? lproto : rproto;
|
2008-08-22 08:56:42 +08:00
|
|
|
if (proto) {
|
2009-05-28 06:11:52 +08:00
|
|
|
assert(!proto->hasExceptionSpec() && "C++ shouldn't be here");
|
2008-08-22 08:56:42 +08:00
|
|
|
if (proto->isVariadic()) return QualType();
|
|
|
|
// Check that the types are compatible with the types that
|
|
|
|
// would result from default argument promotions (C99 6.7.5.3p15).
|
|
|
|
// The only types actually affected are promotable integer
|
|
|
|
// types and floats, which would be passed as a different
|
|
|
|
// type depending on whether the prototype is visible.
|
|
|
|
unsigned proto_nargs = proto->getNumArgs();
|
|
|
|
for (unsigned i = 0; i < proto_nargs; ++i) {
|
|
|
|
QualType argTy = proto->getArgType(i);
|
|
|
|
if (argTy->isPromotableIntegerType() ||
|
|
|
|
getCanonicalType(argTy).getUnqualifiedType() == FloatTy)
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (allLTypes) return lhs;
|
|
|
|
if (allRTypes) return rhs;
|
|
|
|
return getFunctionType(retType, proto->arg_type_begin(),
|
2009-07-27 08:44:23 +08:00
|
|
|
proto->getNumArgs(), proto->isVariadic(),
|
|
|
|
proto->getTypeQuals(), NoReturn);
|
2008-08-22 08:56:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (allLTypes) return lhs;
|
|
|
|
if (allRTypes) return rhs;
|
2009-07-26 05:26:53 +08:00
|
|
|
return getFunctionNoProtoType(retType, NoReturn);
|
2008-08-22 08:56:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
|
2007-12-03 15:33:35 +08:00
|
|
|
// C++ [expr]: If an expression initially has the type "reference to T", the
|
|
|
|
// type is adjusted to "T" prior to any further analysis, the expression
|
|
|
|
// designates the object or function denoted by the reference, and the
|
2009-03-17 07:22:08 +08:00
|
|
|
// expression is an lvalue unless the reference is an rvalue reference and
|
|
|
|
// the expression is a function call (possibly inside parentheses).
|
2008-08-22 08:56:42 +08:00
|
|
|
// FIXME: C++ shouldn't be going through here! The rules are different
|
|
|
|
// enough that they should be handled separately.
|
2009-03-17 07:22:08 +08:00
|
|
|
// FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really*
|
|
|
|
// shouldn't be going through here!
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const ReferenceType *RT = LHS->getAs<ReferenceType>())
|
2008-04-07 12:07:56 +08:00
|
|
|
LHS = RT->getPointeeType();
|
2009-07-30 05:53:49 +08:00
|
|
|
if (const ReferenceType *RT = RHS->getAs<ReferenceType>())
|
2008-04-07 12:07:56 +08:00
|
|
|
RHS = RT->getPointeeType();
|
2008-08-22 08:56:42 +08:00
|
|
|
|
|
|
|
QualType LHSCan = getCanonicalType(LHS),
|
|
|
|
RHSCan = getCanonicalType(RHS);
|
|
|
|
|
2008-04-07 13:37:56 +08:00
|
|
|
// If two types are identical, they are compatible.
|
2008-08-22 08:56:42 +08:00
|
|
|
if (LHSCan == RHSCan)
|
|
|
|
return LHS;
|
|
|
|
|
2009-09-25 03:53:00 +08:00
|
|
|
// If the qualifiers are different, the types aren't compatible... mostly.
|
|
|
|
Qualifiers LQuals = LHSCan.getQualifiers();
|
|
|
|
Qualifiers RQuals = RHSCan.getQualifiers();
|
|
|
|
if (LQuals != RQuals) {
|
|
|
|
// If any of these qualifiers are different, we have a type
|
|
|
|
// mismatch.
|
|
|
|
if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() ||
|
|
|
|
LQuals.getAddressSpace() != RQuals.getAddressSpace())
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
// Exactly one GC qualifier difference is allowed: __strong is
|
|
|
|
// okay if the other type has no GC qualifier but is an Objective
|
|
|
|
// C object pointer (i.e. implicitly strong by default). We fix
|
|
|
|
// this by pretending that the unqualified type was actually
|
|
|
|
// qualified __strong.
|
|
|
|
Qualifiers::GC GC_L = LQuals.getObjCGCAttr();
|
|
|
|
Qualifiers::GC GC_R = RQuals.getObjCGCAttr();
|
|
|
|
assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements");
|
|
|
|
|
|
|
|
if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak)
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) {
|
|
|
|
return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong));
|
|
|
|
}
|
|
|
|
if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) {
|
|
|
|
return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS);
|
|
|
|
}
|
2008-08-22 08:56:42 +08:00
|
|
|
return QualType();
|
2009-09-25 03:53:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Okay, qualifiers are equal.
|
2008-08-22 08:56:42 +08:00
|
|
|
|
2009-06-01 09:22:52 +08:00
|
|
|
Type::TypeClass LHSClass = LHSCan->getTypeClass();
|
|
|
|
Type::TypeClass RHSClass = RHSCan->getTypeClass();
|
2008-04-07 13:37:56 +08:00
|
|
|
|
2008-01-14 13:45:46 +08:00
|
|
|
// We want to consider the two function types to be the same for these
|
|
|
|
// comparisons, just force one to the other.
|
|
|
|
if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto;
|
|
|
|
if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto;
|
2008-02-12 16:23:06 +08:00
|
|
|
|
|
|
|
// Same as above for arrays
|
2008-04-07 13:43:21 +08:00
|
|
|
if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray)
|
|
|
|
LHSClass = Type::ConstantArray;
|
|
|
|
if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray)
|
|
|
|
RHSClass = Type::ConstantArray;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-19 07:10:10 +08:00
|
|
|
// Canonicalize ExtVector -> Vector.
|
|
|
|
if (LHSClass == Type::ExtVector) LHSClass = Type::Vector;
|
|
|
|
if (RHSClass == Type::ExtVector) RHSClass = Type::Vector;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-11 04:07:25 +08:00
|
|
|
// If the canonical type classes don't match.
|
|
|
|
if (LHSClass != RHSClass) {
|
2008-01-14 13:45:46 +08:00
|
|
|
// C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
|
2009-09-09 23:08:12 +08:00
|
|
|
// a signed integer type, or an unsigned integer type.
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
|
2008-08-22 08:56:42 +08:00
|
|
|
if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType())
|
|
|
|
return RHS;
|
2008-02-12 16:46:17 +08:00
|
|
|
}
|
2009-09-22 07:43:11 +08:00
|
|
|
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
|
2008-08-22 08:56:42 +08:00
|
|
|
if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType())
|
|
|
|
return LHS;
|
2008-02-12 16:46:17 +08:00
|
|
|
}
|
2008-01-14 13:45:46 +08:00
|
|
|
|
2008-08-22 08:56:42 +08:00
|
|
|
return QualType();
|
2007-10-16 04:41:53 +08:00
|
|
|
}
|
2008-08-22 08:56:42 +08:00
|
|
|
|
2008-01-10 06:43:08 +08:00
|
|
|
// The canonical type classes match.
|
2008-01-14 13:45:46 +08:00
|
|
|
switch (LHSClass) {
|
2009-02-27 07:50:07 +08:00
|
|
|
#define TYPE(Class, Base)
|
|
|
|
#define ABSTRACT_TYPE(Class, Base)
|
|
|
|
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
|
|
|
|
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
|
|
|
|
#include "clang/AST/TypeNodes.def"
|
|
|
|
assert(false && "Non-canonical and dependent types shouldn't get here");
|
|
|
|
return QualType();
|
|
|
|
|
2009-03-17 07:22:08 +08:00
|
|
|
case Type::LValueReference:
|
|
|
|
case Type::RValueReference:
|
2009-02-27 07:50:07 +08:00
|
|
|
case Type::MemberPointer:
|
|
|
|
assert(false && "C++ should never be in mergeTypes");
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
case Type::IncompleteArray:
|
|
|
|
case Type::VariableArray:
|
|
|
|
case Type::FunctionProto:
|
|
|
|
case Type::ExtVector:
|
|
|
|
assert(false && "Types are eliminated above");
|
|
|
|
return QualType();
|
|
|
|
|
2008-01-14 13:45:46 +08:00
|
|
|
case Type::Pointer:
|
2008-08-22 08:56:42 +08:00
|
|
|
{
|
|
|
|
// Merge two pointer types, while trying to preserve typedef info
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType LHSPointee = LHS->getAs<PointerType>()->getPointeeType();
|
|
|
|
QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType();
|
2008-08-22 08:56:42 +08:00
|
|
|
QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
|
|
|
|
if (ResultType.isNull()) return QualType();
|
2009-06-02 13:28:56 +08:00
|
|
|
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
|
2008-10-06 01:34:18 +08:00
|
|
|
return LHS;
|
2009-06-02 13:28:56 +08:00
|
|
|
if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType))
|
2008-10-06 01:34:18 +08:00
|
|
|
return RHS;
|
2008-08-22 08:56:42 +08:00
|
|
|
return getPointerType(ResultType);
|
|
|
|
}
|
2008-12-11 01:49:55 +08:00
|
|
|
case Type::BlockPointer:
|
|
|
|
{
|
|
|
|
// Merge two block pointer types, while trying to preserve typedef info
|
2009-07-30 05:53:49 +08:00
|
|
|
QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
|
|
|
|
QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
|
2008-12-11 01:49:55 +08:00
|
|
|
QualType ResultType = mergeTypes(LHSPointee, RHSPointee);
|
|
|
|
if (ResultType.isNull()) return QualType();
|
|
|
|
if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType))
|
|
|
|
return LHS;
|
|
|
|
if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType))
|
|
|
|
return RHS;
|
|
|
|
return getBlockPointerType(ResultType);
|
|
|
|
}
|
2008-01-14 13:45:46 +08:00
|
|
|
case Type::ConstantArray:
|
2008-08-22 08:56:42 +08:00
|
|
|
{
|
|
|
|
const ConstantArrayType* LCAT = getAsConstantArrayType(LHS);
|
|
|
|
const ConstantArrayType* RCAT = getAsConstantArrayType(RHS);
|
|
|
|
if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize())
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
QualType LHSElem = getAsArrayType(LHS)->getElementType();
|
|
|
|
QualType RHSElem = getAsArrayType(RHS)->getElementType();
|
|
|
|
QualType ResultType = mergeTypes(LHSElem, RHSElem);
|
|
|
|
if (ResultType.isNull()) return QualType();
|
2008-10-06 01:34:18 +08:00
|
|
|
if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
|
|
|
|
return LHS;
|
|
|
|
if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
|
|
|
|
return RHS;
|
2008-08-22 09:48:21 +08:00
|
|
|
if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
|
|
|
|
ArrayType::ArraySizeModifier(), 0);
|
|
|
|
if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
|
|
|
|
ArrayType::ArraySizeModifier(), 0);
|
2008-08-22 08:56:42 +08:00
|
|
|
const VariableArrayType* LVAT = getAsVariableArrayType(LHS);
|
|
|
|
const VariableArrayType* RVAT = getAsVariableArrayType(RHS);
|
2008-10-06 01:34:18 +08:00
|
|
|
if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
|
|
|
|
return LHS;
|
|
|
|
if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
|
|
|
|
return RHS;
|
2008-08-22 08:56:42 +08:00
|
|
|
if (LVAT) {
|
|
|
|
// FIXME: This isn't correct! But tricky to implement because
|
|
|
|
// the array's size has to be the size of LHS, but the type
|
|
|
|
// has to be different.
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
if (RVAT) {
|
|
|
|
// FIXME: This isn't correct! But tricky to implement because
|
|
|
|
// the array's size has to be the size of RHS, but the type
|
|
|
|
// has to be different.
|
|
|
|
return RHS;
|
|
|
|
}
|
2008-08-22 09:48:21 +08:00
|
|
|
if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS;
|
|
|
|
if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS;
|
2009-07-06 23:59:29 +08:00
|
|
|
return getIncompleteArrayType(ResultType,
|
|
|
|
ArrayType::ArraySizeModifier(), 0);
|
2008-08-22 08:56:42 +08:00
|
|
|
}
|
2008-01-14 13:45:46 +08:00
|
|
|
case Type::FunctionNoProto:
|
2008-08-22 08:56:42 +08:00
|
|
|
return mergeFunctionTypes(LHS, RHS);
|
2009-02-27 07:50:07 +08:00
|
|
|
case Type::Record:
|
|
|
|
case Type::Enum:
|
2008-08-22 08:56:42 +08:00
|
|
|
return QualType();
|
2008-01-14 13:45:46 +08:00
|
|
|
case Type::Builtin:
|
2008-04-07 13:55:38 +08:00
|
|
|
// Only exactly equal builtin types are compatible, which is tested above.
|
2008-08-22 08:56:42 +08:00
|
|
|
return QualType();
|
2009-01-29 05:22:12 +08:00
|
|
|
case Type::Complex:
|
|
|
|
// Distinct complex types are incompatible.
|
|
|
|
return QualType();
|
2008-04-07 13:55:38 +08:00
|
|
|
case Type::Vector:
|
2009-02-28 07:04:43 +08:00
|
|
|
// FIXME: The merged type should be an ExtVector!
|
2009-09-22 07:43:11 +08:00
|
|
|
if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>()))
|
2008-08-22 08:56:42 +08:00
|
|
|
return LHS;
|
2008-10-06 01:34:18 +08:00
|
|
|
return QualType();
|
2009-02-22 01:14:49 +08:00
|
|
|
case Type::ObjCInterface: {
|
2009-02-22 00:18:07 +08:00
|
|
|
// Check if the interfaces are assignment compatible.
|
2009-02-28 07:04:43 +08:00
|
|
|
// FIXME: This should be type compatibility, e.g. whether
|
|
|
|
// "LHS x; RHS x;" at global scope is legal.
|
2009-09-22 07:43:11 +08:00
|
|
|
const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>();
|
|
|
|
const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>();
|
2009-02-22 00:18:07 +08:00
|
|
|
if (LHSIface && RHSIface &&
|
|
|
|
canAssignObjCInterfaces(LHSIface, RHSIface))
|
|
|
|
return LHS;
|
|
|
|
|
2008-08-22 08:56:42 +08:00
|
|
|
return QualType();
|
2009-02-22 01:14:49 +08:00
|
|
|
}
|
2009-07-11 07:34:53 +08:00
|
|
|
case Type::ObjCObjectPointer: {
|
2009-09-22 07:43:11 +08:00
|
|
|
if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
|
|
|
|
RHS->getAs<ObjCObjectPointerType>()))
|
2009-07-11 07:34:53 +08:00
|
|
|
return LHS;
|
|
|
|
|
2008-12-11 06:14:21 +08:00
|
|
|
return QualType();
|
2009-07-11 07:34:53 +08:00
|
|
|
}
|
2009-02-28 07:04:43 +08:00
|
|
|
case Type::FixedWidthInt:
|
|
|
|
// Distinct fixed-width integers are not compatible.
|
|
|
|
return QualType();
|
2009-03-31 06:58:21 +08:00
|
|
|
case Type::TemplateSpecialization:
|
|
|
|
assert(false && "Dependent types have no size");
|
|
|
|
break;
|
2007-10-16 04:41:53 +08:00
|
|
|
}
|
2009-02-27 07:50:07 +08:00
|
|
|
|
|
|
|
return QualType();
|
2007-10-16 04:41:53 +08:00
|
|
|
}
|
2007-11-01 01:10:13 +08:00
|
|
|
|
2008-06-28 14:23:08 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Integer Predicates
|
|
|
|
//===----------------------------------------------------------------------===//
|
2009-01-16 15:15:35 +08:00
|
|
|
|
2008-06-28 14:23:08 +08:00
|
|
|
unsigned ASTContext::getIntWidth(QualType T) {
|
|
|
|
if (T == BoolTy)
|
|
|
|
return 1;
|
2009-10-18 04:33:28 +08:00
|
|
|
if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
|
2009-02-13 10:31:07 +08:00
|
|
|
return FWIT->getWidth();
|
|
|
|
}
|
|
|
|
// For builtin types, just use the standard type sizing method
|
2008-06-28 14:23:08 +08:00
|
|
|
return (unsigned)getTypeSize(T);
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
|
|
|
|
assert(T->isSignedIntegerType() && "Unexpected type");
|
2009-10-18 04:33:28 +08:00
|
|
|
|
|
|
|
// Turn <4 x signed int> -> <4 x unsigned int>
|
|
|
|
if (const VectorType *VTy = T->getAs<VectorType>())
|
|
|
|
return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()),
|
|
|
|
VTy->getNumElements());
|
|
|
|
|
|
|
|
// For enums, we return the unsigned version of the base type.
|
|
|
|
if (const EnumType *ETy = T->getAs<EnumType>())
|
2008-06-28 14:23:08 +08:00
|
|
|
T = ETy->getDecl()->getIntegerType();
|
2009-10-18 04:33:28 +08:00
|
|
|
|
|
|
|
const BuiltinType *BTy = T->getAs<BuiltinType>();
|
|
|
|
assert(BTy && "Unexpected signed integer type");
|
2008-06-28 14:23:08 +08:00
|
|
|
switch (BTy->getKind()) {
|
|
|
|
case BuiltinType::Char_S:
|
|
|
|
case BuiltinType::SChar:
|
|
|
|
return UnsignedCharTy;
|
|
|
|
case BuiltinType::Short:
|
|
|
|
return UnsignedShortTy;
|
|
|
|
case BuiltinType::Int:
|
|
|
|
return UnsignedIntTy;
|
|
|
|
case BuiltinType::Long:
|
|
|
|
return UnsignedLongTy;
|
|
|
|
case BuiltinType::LongLong:
|
|
|
|
return UnsignedLongLongTy;
|
2009-04-30 10:43:43 +08:00
|
|
|
case BuiltinType::Int128:
|
|
|
|
return UnsignedInt128Ty;
|
2008-06-28 14:23:08 +08:00
|
|
|
default:
|
|
|
|
assert(0 && "Unexpected signed integer type");
|
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-10 06:27:44 +08:00
|
|
|
ExternalASTSource::~ExternalASTSource() { }
|
|
|
|
|
|
|
|
void ExternalASTSource::PrintStats() { }
|
2009-06-14 08:45:47 +08:00
|
|
|
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Builtin Type Computation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
|
|
|
|
/// pointer over the consumed characters. This returns the resultant type.
|
2009-09-09 23:08:12 +08:00
|
|
|
static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
|
2009-06-14 08:45:47 +08:00
|
|
|
ASTContext::GetBuiltinTypeError &Error,
|
|
|
|
bool AllowTypeModifiers = true) {
|
|
|
|
// Modifiers.
|
|
|
|
int HowLong = 0;
|
|
|
|
bool Signed = false, Unsigned = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
// Read the modifiers first.
|
|
|
|
bool Done = false;
|
|
|
|
while (!Done) {
|
|
|
|
switch (*Str++) {
|
2009-09-09 23:08:12 +08:00
|
|
|
default: Done = true; --Str; break;
|
2009-06-14 08:45:47 +08:00
|
|
|
case 'S':
|
|
|
|
assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
|
|
|
|
assert(!Signed && "Can't use 'S' modifier multiple times!");
|
|
|
|
Signed = true;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
assert(!Signed && "Can't use both 'S' and 'U' modifiers!");
|
|
|
|
assert(!Unsigned && "Can't use 'S' modifier multiple times!");
|
|
|
|
Unsigned = true;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
assert(HowLong <= 2 && "Can't have LLLL modifier");
|
|
|
|
++HowLong;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType Type;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
// Read the base type.
|
|
|
|
switch (*Str++) {
|
|
|
|
default: assert(0 && "Unknown builtin type letter!");
|
|
|
|
case 'v':
|
|
|
|
assert(HowLong == 0 && !Signed && !Unsigned &&
|
|
|
|
"Bad modifiers used with 'v'!");
|
|
|
|
Type = Context.VoidTy;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
assert(HowLong == 0 && !Signed && !Unsigned &&
|
|
|
|
"Bad modifiers used with 'f'!");
|
|
|
|
Type = Context.FloatTy;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
assert(HowLong < 2 && !Signed && !Unsigned &&
|
|
|
|
"Bad modifiers used with 'd'!");
|
|
|
|
if (HowLong)
|
|
|
|
Type = Context.LongDoubleTy;
|
|
|
|
else
|
|
|
|
Type = Context.DoubleTy;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
assert(HowLong == 0 && "Bad modifiers used with 's'!");
|
|
|
|
if (Unsigned)
|
|
|
|
Type = Context.UnsignedShortTy;
|
|
|
|
else
|
|
|
|
Type = Context.ShortTy;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
if (HowLong == 3)
|
|
|
|
Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty;
|
|
|
|
else if (HowLong == 2)
|
|
|
|
Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy;
|
|
|
|
else if (HowLong == 1)
|
|
|
|
Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy;
|
|
|
|
else
|
|
|
|
Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
assert(HowLong == 0 && "Bad modifiers used with 'c'!");
|
|
|
|
if (Signed)
|
|
|
|
Type = Context.SignedCharTy;
|
|
|
|
else if (Unsigned)
|
|
|
|
Type = Context.UnsignedCharTy;
|
|
|
|
else
|
|
|
|
Type = Context.CharTy;
|
|
|
|
break;
|
|
|
|
case 'b': // boolean
|
|
|
|
assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!");
|
|
|
|
Type = Context.BoolTy;
|
|
|
|
break;
|
|
|
|
case 'z': // size_t.
|
|
|
|
assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'z'!");
|
|
|
|
Type = Context.getSizeType();
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
Type = Context.getCFConstantStringType();
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
Type = Context.getBuiltinVaListType();
|
|
|
|
assert(!Type.isNull() && "builtin va list type not initialized!");
|
|
|
|
break;
|
|
|
|
case 'A':
|
|
|
|
// This is a "reference" to a va_list; however, what exactly
|
|
|
|
// this means depends on how va_list is defined. There are two
|
|
|
|
// different kinds of va_list: ones passed by value, and ones
|
|
|
|
// passed by reference. An example of a by-value va_list is
|
|
|
|
// x86, where va_list is a char*. An example of by-ref va_list
|
|
|
|
// is x86-64, where va_list is a __va_list_tag[1]. For x86,
|
|
|
|
// we want this argument to be a char*&; for x86-64, we want
|
|
|
|
// it to be a __va_list_tag*.
|
|
|
|
Type = Context.getBuiltinVaListType();
|
|
|
|
assert(!Type.isNull() && "builtin va list type not initialized!");
|
|
|
|
if (Type->isArrayType()) {
|
|
|
|
Type = Context.getArrayDecayedType(Type);
|
|
|
|
} else {
|
|
|
|
Type = Context.getLValueReferenceType(Type);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'V': {
|
|
|
|
char *End;
|
|
|
|
unsigned NumElements = strtoul(Str, &End, 10);
|
|
|
|
assert(End != Str && "Missing vector size");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
Str = End;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
|
|
|
|
Type = Context.getVectorType(ElementType, NumElements);
|
|
|
|
break;
|
|
|
|
}
|
2009-09-29 05:45:01 +08:00
|
|
|
case 'X': {
|
|
|
|
QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
|
|
|
|
Type = Context.getComplexType(ElementType);
|
|
|
|
break;
|
|
|
|
}
|
2009-07-29 06:49:34 +08:00
|
|
|
case 'P':
|
2009-07-08 00:35:42 +08:00
|
|
|
Type = Context.getFILEType();
|
|
|
|
if (Type.isNull()) {
|
2009-07-29 07:57:15 +08:00
|
|
|
Error = ASTContext::GE_Missing_stdio;
|
2009-06-14 08:45:47 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
2009-07-29 07:47:15 +08:00
|
|
|
break;
|
2009-07-29 06:49:34 +08:00
|
|
|
case 'J':
|
2009-07-29 07:57:15 +08:00
|
|
|
if (Signed)
|
2009-07-28 10:25:19 +08:00
|
|
|
Type = Context.getsigjmp_bufType();
|
2009-07-29 07:57:15 +08:00
|
|
|
else
|
|
|
|
Type = Context.getjmp_bufType();
|
|
|
|
|
2009-07-29 07:47:15 +08:00
|
|
|
if (Type.isNull()) {
|
2009-07-29 07:57:15 +08:00
|
|
|
Error = ASTContext::GE_Missing_setjmp;
|
2009-07-29 07:47:15 +08:00
|
|
|
return QualType();
|
|
|
|
}
|
|
|
|
break;
|
2009-07-28 10:25:19 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
if (!AllowTypeModifiers)
|
|
|
|
return Type;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
Done = false;
|
|
|
|
while (!Done) {
|
|
|
|
switch (*Str++) {
|
|
|
|
default: Done = true; --Str; break;
|
|
|
|
case '*':
|
|
|
|
Type = Context.getPointerType(Type);
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
Type = Context.getLValueReferenceType(Type);
|
|
|
|
break;
|
|
|
|
// FIXME: There's no way to have a built-in with an rvalue ref arg.
|
|
|
|
case 'C':
|
2009-09-25 03:53:00 +08:00
|
|
|
Type = Type.withConst();
|
2009-06-14 08:45:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// GetBuiltinType - Return the type for the specified builtin.
|
|
|
|
QualType ASTContext::GetBuiltinType(unsigned id,
|
|
|
|
GetBuiltinTypeError &Error) {
|
|
|
|
const char *TypeStr = BuiltinInfo.GetTypeString(id);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
llvm::SmallVector<QualType, 8> ArgTypes;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
Error = GE_None;
|
|
|
|
QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error);
|
|
|
|
if (Error != GE_None)
|
|
|
|
return QualType();
|
|
|
|
while (TypeStr[0] && TypeStr[0] != '.') {
|
|
|
|
QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error);
|
|
|
|
if (Error != GE_None)
|
|
|
|
return QualType();
|
|
|
|
|
|
|
|
// Do array -> pointer decay. The builtin should use the decayed type.
|
|
|
|
if (Ty->isArrayType())
|
|
|
|
Ty = getArrayDecayedType(Ty);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-06-14 08:45:47 +08:00
|
|
|
ArgTypes.push_back(Ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
|
|
|
|
"'.' should only occur at end of builtin type list!");
|
|
|
|
|
|
|
|
// handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
|
|
|
|
if (ArgTypes.size() == 0 && TypeStr[0] == '.')
|
|
|
|
return getFunctionNoProtoType(ResType);
|
|
|
|
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
|
|
|
|
TypeStr[0] == '.', 0);
|
|
|
|
}
|
2009-08-19 15:44:53 +08:00
|
|
|
|
|
|
|
QualType
|
|
|
|
ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
|
|
|
|
// Perform the usual unary conversions. We do this early so that
|
|
|
|
// integral promotions to "int" can allow us to exit early, in the
|
|
|
|
// lhs == rhs check. Also, for conversion purposes, we ignore any
|
|
|
|
// qualifiers. For example, "const float" and "float" are
|
|
|
|
// equivalent.
|
|
|
|
if (lhs->isPromotableIntegerType())
|
|
|
|
lhs = getPromotedIntegerType(lhs);
|
|
|
|
else
|
|
|
|
lhs = lhs.getUnqualifiedType();
|
|
|
|
if (rhs->isPromotableIntegerType())
|
|
|
|
rhs = getPromotedIntegerType(rhs);
|
|
|
|
else
|
|
|
|
rhs = rhs.getUnqualifiedType();
|
|
|
|
|
|
|
|
// If both types are identical, no conversion is needed.
|
|
|
|
if (lhs == rhs)
|
|
|
|
return lhs;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-19 15:44:53 +08:00
|
|
|
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
|
|
|
|
// The caller can deal with this (e.g. pointer + int).
|
|
|
|
if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
|
|
|
|
return lhs;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
// At this point, we have two different arithmetic types.
|
|
|
|
|
2009-08-19 15:44:53 +08:00
|
|
|
// Handle complex types first (C99 6.3.1.8p1).
|
|
|
|
if (lhs->isComplexType() || rhs->isComplexType()) {
|
|
|
|
// if we have an integer operand, the result is the complex type.
|
2009-09-09 23:08:12 +08:00
|
|
|
if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
|
2009-08-19 15:44:53 +08:00
|
|
|
// convert the rhs to the lhs complex type.
|
|
|
|
return lhs;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
|
2009-08-19 15:44:53 +08:00
|
|
|
// convert the lhs to the rhs complex type.
|
|
|
|
return rhs;
|
|
|
|
}
|
|
|
|
// This handles complex/complex, complex/float, or float/complex.
|
2009-09-09 23:08:12 +08:00
|
|
|
// When both operands are complex, the shorter operand is converted to the
|
|
|
|
// type of the longer, and that is the type of the result. This corresponds
|
|
|
|
// to what is done when combining two real floating-point operands.
|
|
|
|
// The fun begins when size promotion occur across type domains.
|
2009-08-19 15:44:53 +08:00
|
|
|
// From H&S 6.3.4: When one operand is complex and the other is a real
|
2009-09-09 23:08:12 +08:00
|
|
|
// floating-point type, the less precise type is converted, within it's
|
2009-08-19 15:44:53 +08:00
|
|
|
// real or complex domain, to the precision of the other type. For example,
|
2009-09-09 23:08:12 +08:00
|
|
|
// when combining a "long double" with a "double _Complex", the
|
2009-08-19 15:44:53 +08:00
|
|
|
// "double _Complex" is promoted to "long double _Complex".
|
|
|
|
int result = getFloatingTypeOrder(lhs, rhs);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
|
|
|
if (result > 0) { // The left side is bigger, convert rhs.
|
2009-08-19 15:44:53 +08:00
|
|
|
rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs);
|
2009-09-09 23:08:12 +08:00
|
|
|
} else if (result < 0) { // The right side is bigger, convert lhs.
|
2009-08-19 15:44:53 +08:00
|
|
|
lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs);
|
2009-09-09 23:08:12 +08:00
|
|
|
}
|
2009-08-19 15:44:53 +08:00
|
|
|
// At this point, lhs and rhs have the same rank/size. Now, make sure the
|
|
|
|
// domains match. This is a requirement for our implementation, C99
|
|
|
|
// does not require this promotion.
|
|
|
|
if (lhs != rhs) { // Domains don't match, we have complex/float mix.
|
|
|
|
if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
|
|
|
|
return rhs;
|
|
|
|
} else { // handle "_Complex double, double".
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs; // The domain/size match exactly.
|
|
|
|
}
|
|
|
|
// Now handle "real" floating types (i.e. float, double, long double).
|
|
|
|
if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
|
|
|
|
// if we have an integer operand, the result is the real floating type.
|
|
|
|
if (rhs->isIntegerType()) {
|
|
|
|
// convert rhs to the lhs floating point type.
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
if (rhs->isComplexIntegerType()) {
|
|
|
|
// convert rhs to the complex floating point type.
|
|
|
|
return getComplexType(lhs);
|
|
|
|
}
|
|
|
|
if (lhs->isIntegerType()) {
|
|
|
|
// convert lhs to the rhs floating point type.
|
|
|
|
return rhs;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
if (lhs->isComplexIntegerType()) {
|
2009-08-19 15:44:53 +08:00
|
|
|
// convert lhs to the complex floating point type.
|
|
|
|
return getComplexType(rhs);
|
|
|
|
}
|
|
|
|
// We have two real floating types, float/complex combos were handled above.
|
|
|
|
// Convert the smaller operand to the bigger result.
|
|
|
|
int result = getFloatingTypeOrder(lhs, rhs);
|
|
|
|
if (result > 0) // convert the rhs
|
|
|
|
return lhs;
|
|
|
|
assert(result < 0 && "illegal float comparison");
|
|
|
|
return rhs; // convert the lhs
|
|
|
|
}
|
|
|
|
if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
|
|
|
|
// Handle GCC complex int extension.
|
|
|
|
const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
|
|
|
|
const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
|
|
|
|
|
|
|
|
if (lhsComplexInt && rhsComplexInt) {
|
2009-09-09 23:08:12 +08:00
|
|
|
if (getIntegerTypeOrder(lhsComplexInt->getElementType(),
|
2009-08-19 15:44:53 +08:00
|
|
|
rhsComplexInt->getElementType()) >= 0)
|
|
|
|
return lhs; // convert the rhs
|
|
|
|
return rhs;
|
|
|
|
} else if (lhsComplexInt && rhs->isIntegerType()) {
|
|
|
|
// convert the rhs to the lhs complex type.
|
|
|
|
return lhs;
|
|
|
|
} else if (rhsComplexInt && lhs->isIntegerType()) {
|
|
|
|
// convert the lhs to the rhs complex type.
|
|
|
|
return rhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Finally, we have two differing integer types.
|
|
|
|
// The rules for this case are in C99 6.3.1.8
|
|
|
|
int compare = getIntegerTypeOrder(lhs, rhs);
|
|
|
|
bool lhsSigned = lhs->isSignedIntegerType(),
|
|
|
|
rhsSigned = rhs->isSignedIntegerType();
|
|
|
|
QualType destType;
|
|
|
|
if (lhsSigned == rhsSigned) {
|
|
|
|
// Same signedness; use the higher-ranked type
|
|
|
|
destType = compare >= 0 ? lhs : rhs;
|
|
|
|
} else if (compare != (lhsSigned ? 1 : -1)) {
|
|
|
|
// The unsigned type has greater than or equal rank to the
|
|
|
|
// signed type, so use the unsigned type
|
|
|
|
destType = lhsSigned ? rhs : lhs;
|
|
|
|
} else if (getIntWidth(lhs) != getIntWidth(rhs)) {
|
|
|
|
// The two types are different widths; if we are here, that
|
|
|
|
// means the signed type is larger than the unsigned type, so
|
|
|
|
// use the signed type.
|
|
|
|
destType = lhsSigned ? lhs : rhs;
|
|
|
|
} else {
|
|
|
|
// The signed type is higher-ranked than the unsigned type,
|
|
|
|
// but isn't actually any bigger (like unsigned int and long
|
|
|
|
// on most 32-bit systems). Use the unsigned type corresponding
|
|
|
|
// to the signed type.
|
|
|
|
destType = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
|
|
|
|
}
|
|
|
|
return destType;
|
|
|
|
}
|