diff options
Diffstat (limited to 'lib/AST')
| -rw-r--r-- | lib/AST/APValue.cpp | 16 | ||||
| -rw-r--r-- | lib/AST/ASTContext.cpp | 2764 | ||||
| -rw-r--r-- | lib/AST/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | lib/AST/CXXInheritance.cpp | 244 | ||||
| -rw-r--r-- | lib/AST/Decl.cpp | 509 | ||||
| -rw-r--r-- | lib/AST/DeclBase.cpp | 164 | ||||
| -rw-r--r-- | lib/AST/DeclCXX.cpp | 610 | ||||
| -rw-r--r-- | lib/AST/DeclObjC.cpp | 440 | ||||
| -rw-r--r-- | lib/AST/DeclPrinter.cpp | 244 | ||||
| -rw-r--r-- | lib/AST/DeclTemplate.cpp | 206 | ||||
| -rw-r--r-- | lib/AST/DeclarationName.cpp | 44 | ||||
| -rw-r--r-- | lib/AST/Expr.cpp | 797 | ||||
| -rw-r--r-- | lib/AST/ExprCXX.cpp | 270 | ||||
| -rw-r--r-- | lib/AST/ExprConstant.cpp | 284 | ||||
| -rw-r--r-- | lib/AST/InheritViz.cpp | 10 | ||||
| -rw-r--r-- | lib/AST/NestedNameSpecifier.cpp | 61 | ||||
| -rw-r--r-- | lib/AST/ParentMap.cpp | 10 | ||||
| -rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 674 | ||||
| -rw-r--r-- | lib/AST/RecordLayoutBuilder.h | 146 | ||||
| -rw-r--r-- | lib/AST/Stmt.cpp | 80 | ||||
| -rw-r--r-- | lib/AST/StmtDumper.cpp | 143 | ||||
| -rw-r--r-- | lib/AST/StmtIterator.cpp | 40 | ||||
| -rw-r--r-- | lib/AST/StmtPrinter.cpp | 191 | ||||
| -rw-r--r-- | lib/AST/StmtProfile.cpp | 720 | ||||
| -rw-r--r-- | lib/AST/StmtViz.cpp | 17 | ||||
| -rw-r--r-- | lib/AST/TemplateName.cpp | 42 | ||||
| -rw-r--r-- | lib/AST/Type.cpp | 983 | ||||
| -rw-r--r-- | lib/AST/TypeLoc.cpp | 370 |
28 files changed, 7043 insertions, 3047 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 4df7671c5a95..772a884c90d3 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -37,7 +37,7 @@ const APValue &APValue::operator=(const APValue &RHS) { else if (isFloat()) setFloat(RHS.getFloat()); else if (isVector()) - setVector(((Vec*)(void*)RHS.Data)->Elts, RHS.getVectorLength()); + setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength()); else if (isComplexInt()) setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) @@ -49,17 +49,17 @@ const APValue &APValue::operator=(const APValue &RHS) { void APValue::MakeUninit() { if (Kind == Int) - ((APSInt*)(void*)Data)->~APSInt(); + ((APSInt*)(char*)Data)->~APSInt(); else if (Kind == Float) - ((APFloat*)(void*)Data)->~APFloat(); + ((APFloat*)(char*)Data)->~APFloat(); else if (Kind == Vector) - ((Vec*)(void*)Data)->~Vec(); + ((Vec*)(char*)Data)->~Vec(); else if (Kind == ComplexInt) - ((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt(); + ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt(); else if (Kind == ComplexFloat) - ((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat(); + ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat(); else if (Kind == LValue) { - ((LV*)(void*)Data)->~LV(); + ((LV*)(char*)Data)->~LV(); } Kind = Uninitialized; } @@ -91,7 +91,7 @@ void APValue::print(llvm::raw_ostream &OS) const { return; case Vector: OS << "Vector: " << getVectorElt(0); - for (unsigned i = 1; i != getVectorLength(); ++i) + for (unsigned i = 1; i != getVectorLength(); ++i) OS << ", " << getVectorElt(i); return; case ComplexInt: diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 2877cc3b7fe7..85b4fd6d6cc0 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/Expr.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/RecordLayout.h" @@ -24,6 +25,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "RecordLayoutBuilder.h" + using namespace clang; enum FloatingRank { @@ -34,15 +37,18 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, - bool FreeMem, unsigned size_reserve) : - GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), - ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), - LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), + bool FreeMem, unsigned size_reserve) : + GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), + sigjmp_bufDecl(0), SourceMgr(SM), LangOpts(LOpts), + LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), - BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { - if (size_reserve > 0) Types.reserve(size_reserve); - InitBuiltinTypes(); + BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { + ObjCIdRedefinitionType = QualType(); + ObjCClassRedefinitionType = QualType(); + if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); + InitBuiltinTypes(); } ASTContext::~ASTContext() { @@ -53,6 +59,13 @@ ASTContext::~ASTContext() { } { + llvm::FoldingSet<ExtQuals>::iterator + I = ExtQualNodes.begin(), E = ExtQualNodes.end(); + while (I != E) + Deallocate(&*I++); + } + + { llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); while (I != E) { @@ -73,8 +86,8 @@ ASTContext::~ASTContext() { // Destroy nested-name-specifiers. for (llvm::FoldingSet<NestedNameSpecifier>::iterator NNS = NestedNameSpecifiers.begin(), - NNSEnd = NestedNameSpecifiers.end(); - NNS != NNSEnd; + NNSEnd = NestedNameSpecifiers.end(); + NNS != NNSEnd; /* Increment in loop */) (*NNS++).Destroy(*this); @@ -84,7 +97,7 @@ ASTContext::~ASTContext() { TUDecl->Destroy(*this); } -void +void ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) { ExternalSource.reset(Source.take()); } @@ -94,7 +107,7 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %d types total.\n", (int)Types.size()); unsigned counts[] = { -#define TYPE(Name, Parent) 0, +#define TYPE(Name, Parent) 0, #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" 0 // Extra @@ -114,7 +127,7 @@ void ASTContext::PrintStats() const { ++Idx; #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" - + fprintf(stderr, "Total bytes = %d\n", int(TotalBytes)); if (ExternalSource.get()) { @@ -125,15 +138,17 @@ void ASTContext::PrintStats() const { void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { - Types.push_back((R = QualType(new (*this,8) BuiltinType(K),0)).getTypePtr()); + BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); + R = QualType(Ty, 0); + Types.push_back(Ty); } void ASTContext::InitBuiltinTypes() { assert(VoidTy.isNull() && "Context reinitialized?"); - + // C99 6.2.5p19. InitBuiltinType(VoidTy, BuiltinType::Void); - + // C99 6.2.5p2. InitBuiltinType(BoolTy, BuiltinType::Bool); // C99 6.2.5p3. @@ -147,14 +162,14 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(IntTy, BuiltinType::Int); InitBuiltinType(LongTy, BuiltinType::Long); InitBuiltinType(LongLongTy, BuiltinType::LongLong); - + // C99 6.2.5p6. InitBuiltinType(UnsignedCharTy, BuiltinType::UChar); InitBuiltinType(UnsignedShortTy, BuiltinType::UShort); InitBuiltinType(UnsignedIntTy, BuiltinType::UInt); InitBuiltinType(UnsignedLongTy, BuiltinType::ULong); InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong); - + // C99 6.2.5p10. InitBuiltinType(FloatTy, BuiltinType::Float); InitBuiltinType(DoubleTy, BuiltinType::Double); @@ -169,6 +184,16 @@ void ASTContext::InitBuiltinTypes() { else // C99 WCharTy = getFromTargetType(Target.getWCharType()); + 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()); + // Placeholder type for functions. InitBuiltinType(OverloadTy, BuiltinType::Overload); @@ -179,23 +204,27 @@ void ASTContext::InitBuiltinTypes() { // expressions. InitBuiltinType(DependentTy, BuiltinType::Dependent); - // Placeholder type for C++0x auto declarations whose real type has + // Placeholder type for C++0x auto declarations whose real type has // not yet been deduced. InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto); - + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); BuiltinVaListType = QualType(); - ObjCIdType = QualType(); - IdStructType = 0; - ObjCClassType = QualType(); - ClassStructType = 0; - + + // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). + ObjCIdTypedefType = QualType(); + ObjCClassTypedefType = QualType(); + + // Builtin types for 'id' and 'Class'. + InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); + InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); + ObjCConstantStringType = QualType(); - + // void * type VoidPtrTy = getPointerType(VoidTy); @@ -203,14 +232,73 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } +MemberSpecializationInfo * +ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { + assert(Var->isStaticDataMember() && "Not a static data member"); + llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>::iterator Pos + = InstantiatedFromStaticDataMember.find(Var); + if (Pos == InstantiatedFromStaticDataMember.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK) { + 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"); + InstantiatedFromStaticDataMember[Inst] + = new (*this) MemberSpecializationInfo(Tmpl, TSK); +} + +UnresolvedUsingDecl * +ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { + llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos + = InstantiatedFromUnresolvedUsingDecl.find(UUD); + if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, + UnresolvedUsingDecl *UUD) { + assert(!InstantiatedFromUnresolvedUsingDecl[UD] && + "Already noted what using decl what instantiated from"); + InstantiatedFromUnresolvedUsingDecl[UD] = UUD; +} + +FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { + llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos + = InstantiatedFromUnnamedFieldDecl.find(Field); + if (Pos == InstantiatedFromUnnamedFieldDecl.end()) + return 0; + + 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"); + + InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; +} + namespace { - class BeforeInTranslationUnit + class BeforeInTranslationUnit : std::binary_function<SourceRange, SourceRange, bool> { SourceManager *SourceMgr; - + public: explicit BeforeInTranslationUnit(SourceManager *SM) : SourceMgr(SM) { } - + bool operator()(SourceRange X, SourceRange Y) { return SourceMgr->isBeforeInTranslationUnit(X.getBegin(), Y.getBegin()); } @@ -226,14 +314,14 @@ namespace { /// \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. -static bool -isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, +static bool +isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, bool Member = false) { - const char *BufferStart + const char *BufferStart = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin())).first; const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin()); const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd()); - + if (End - Start < 4) return false; @@ -247,32 +335,32 @@ isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, } /// \brief Retrieve the comment associated with the given declaration, if -/// it has one. +/// it has one. const char *ASTContext::getCommentForDecl(const Decl *D) { if (!D) return 0; - + // Check whether we have cached a comment string for this declaration // already. - llvm::DenseMap<const Decl *, std::string>::iterator Pos + llvm::DenseMap<const Decl *, std::string>::iterator Pos = DeclComments.find(D); if (Pos != DeclComments.end()) return Pos->second.c_str(); - // If we have an external AST source and have not yet loaded comments from + // If we have an external AST source and have not yet loaded comments from // that source, do so now. if (ExternalSource && !LoadedExternalComments) { std::vector<SourceRange> LoadedComments; ExternalSource->ReadComments(LoadedComments); - + if (!LoadedComments.empty()) Comments.insert(Comments.begin(), LoadedComments.begin(), LoadedComments.end()); - + LoadedExternalComments = true; } - - // If there are no comments anywhere, we won't find anything. + + // If there are no comments anywhere, we won't find anything. if (Comments.empty()) return 0; @@ -284,17 +372,17 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { // Find the comment that occurs just before this declaration. std::vector<SourceRange>::iterator LastComment - = std::lower_bound(Comments.begin(), Comments.end(), + = std::lower_bound(Comments.begin(), Comments.end(), SourceRange(DeclStartLoc), BeforeInTranslationUnit(&SourceMgr)); - + // Decompose the location for the start of the declaration and find the // beginning of the file buffer. - std::pair<FileID, unsigned> DeclStartDecomp + std::pair<FileID, unsigned> DeclStartDecomp = SourceMgr.getDecomposedLoc(DeclStartLoc); - const char *FileBufferStart + const char *FileBufferStart = SourceMgr.getBufferData(DeclStartDecomp.first).first; - + // First check whether we have a comment for a member. if (LastComment != Comments.end() && !isa<TagDecl>(D) && !isa<NamespaceDecl>(D) && @@ -303,19 +391,19 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { = SourceMgr.getDecomposedLoc(LastComment->getEnd()); if (DeclStartDecomp.first == LastCommentEndDecomp.first && SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second) - == SourceMgr.getLineNumber(LastCommentEndDecomp.first, + == SourceMgr.getLineNumber(LastCommentEndDecomp.first, 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]; - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), + Result.append(FileBufferStart + + SourceMgr.getFileOffset(LastComment->getBegin()), FileBufferStart + LastCommentEndDecomp.second + 1); return Result.c_str(); } } - + if (LastComment == Comments.begin()) return 0; --LastComment; @@ -323,33 +411,33 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { // Decompose the end of the comment. std::pair<FileID, unsigned> LastCommentEndDecomp = SourceMgr.getDecomposedLoc(LastComment->getEnd()); - + // If the comment and the declaration aren't in the same file, then they // aren't related. if (DeclStartDecomp.first != LastCommentEndDecomp.first) return 0; - + // Check that we actually have a Doxygen comment. if (!isDoxygenComment(SourceMgr, *LastComment)) return 0; - + // Compute the starting line for the declaration and for the end of the // comment (this is expensive). - unsigned DeclStartLine + unsigned DeclStartLine = SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second); unsigned CommentEndLine - = SourceMgr.getLineNumber(LastCommentEndDecomp.first, + = SourceMgr.getLineNumber(LastCommentEndDecomp.first, LastCommentEndDecomp.second); - + // 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; - + // 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. - unsigned ExpectedLine + unsigned ExpectedLine = SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1; std::vector<SourceRange>::iterator FirstComment = LastComment; while (FirstComment != Comments.begin()) { @@ -357,31 +445,31 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { --FirstComment; std::pair<FileID, unsigned> Decomp = SourceMgr.getDecomposedLoc(FirstComment->getEnd()); - + // If this previous comment is in a different file, we're done. if (Decomp.first != DeclStartDecomp.first) { ++FirstComment; break; } - + // If this comment is not a Doxygen comment, we're done. if (!isDoxygenComment(SourceMgr, *FirstComment)) { ++FirstComment; break; } - + // 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; } - + // Set the next expected line number. - ExpectedLine + ExpectedLine = SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1; } - + // 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 @@ -396,10 +484,10 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { FileBufferStart + DecompEnd.second + 1); ++FirstComment; } - + // Append the last comment line. - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), + Result.append(FileBufferStart + + SourceMgr.getFileOffset(LastComment->getBegin()), FileBufferStart + LastCommentEndDecomp.second + 1); return Result.c_str(); } @@ -411,7 +499,7 @@ const char *ASTContext::getCommentForDecl(const Decl *D) { /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified /// scalar floating point type. const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { - const BuiltinType *BT = T->getAsBuiltinType(); + const BuiltinType *BT = T->getAs<BuiltinType>(); assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: assert(0 && "Not a floating point type!"); @@ -421,7 +509,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { } } -/// getDeclAlign - Return a conservative estimate of the alignment of the +/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the /// specified decl. Note that bitfields do not have a valid alignment, so /// this method will assert on them. unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { @@ -432,7 +520,7 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { QualType T = VD->getType(); - if (const ReferenceType* RT = T->getAsReferenceType()) { + if (const ReferenceType* RT = T->getAs<ReferenceType>()) { unsigned AS = RT->getPointeeType().getAddressSpace(); Align = Target.getPointerAlign(AS); } else if (!T->isIncompleteType() && !T->isFunctionType()) { @@ -449,6 +537,10 @@ unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. +/// +/// FIXME: Pointers into different addr spaces could have different sizes and +/// alignment requirements: getPointerInfo should take an AddrSpace, this +/// should take a QualType, &c. std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) { uint64_t Width=0; @@ -462,6 +554,10 @@ ASTContext::getTypeInfo(const Type *T) { assert(false && "Should not see dependent types"); break; + case Type::ObjCProtocolList: + assert(false && "Should not see protocol list types"); + break; + case Type::FunctionNoProto: case Type::FunctionProto: // GCC extension: alignof(function) = 32 bits @@ -475,9 +571,11 @@ ASTContext::getTypeInfo(const Type *T) { Align = getTypeAlign(cast<ArrayType>(T)->getElementType()); break; + case Type::ConstantArrayWithExpr: + case Type::ConstantArrayWithoutExpr: case Type::ConstantArray: { const ConstantArrayType *CAT = cast<ConstantArrayType>(T); - + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType()); Width = EltInfo.first*CAT->getSize().getZExtValue(); Align = EltInfo.second; @@ -485,7 +583,7 @@ ASTContext::getTypeInfo(const Type *T) { } case Type::ExtVector: case Type::Vector: { - std::pair<uint64_t, unsigned> EltInfo = + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(cast<VectorType>(T)->getElementType()); Width = EltInfo.first*cast<VectorType>(T)->getNumElements(); Align = Width; @@ -520,6 +618,14 @@ ASTContext::getTypeInfo(const Type *T) { Width = Target.getWCharWidth(); Align = Target.getWCharAlign(); break; + case BuiltinType::Char16: + Width = Target.getChar16Width(); + Align = Target.getChar16Align(); + break; + case BuiltinType::Char32: + Width = Target.getChar32Width(); + Align = Target.getChar32Align(); + break; case BuiltinType::UShort: case BuiltinType::Short: Width = Target.getShortWidth(); @@ -570,12 +676,7 @@ ASTContext::getTypeInfo(const Type *T) { Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8); Align = Width; break; - case Type::ExtQual: - // FIXME: Pointers into different addr spaces could have different sizes and - // alignment requirements: getPointerInfo should take an AddrSpace. - return getTypeInfo(QualType(cast<ExtQualType>(T)->getBaseType(), 0)); case Type::ObjCObjectPointer: - case Type::ObjCQualifiedInterface: Width = Target.getPointerWidth(0); Align = Target.getPointerAlign(0); break; @@ -604,7 +705,7 @@ ASTContext::getTypeInfo(const Type *T) { // If we ever want to support other ABIs this needs to be abstracted. QualType Pointee = cast<MemberPointerType>(T)->getPointeeType(); - std::pair<uint64_t, unsigned> PtrDiffInfo = + std::pair<uint64_t, unsigned> PtrDiffInfo = getTypeInfo(getPointerDiffType()); Width = PtrDiffInfo.first; if (Pointee->isFunctionType()) @@ -615,7 +716,7 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. - std::pair<uint64_t, unsigned> EltInfo = + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(cast<ComplexType>(T)->getElementType()); Width = EltInfo.first*2; Align = EltInfo.second; @@ -637,7 +738,7 @@ ASTContext::getTypeInfo(const Type *T) { Align = 1; break; } - + if (const EnumType *ET = dyn_cast<EnumType>(TT)) return getTypeInfo(ET->getDecl()->getIntegerType()); @@ -648,6 +749,10 @@ ASTContext::getTypeInfo(const Type *T) { break; } + case Type::Elaborated: { + return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr()); + } + case Type::Typedef: { const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) { @@ -671,16 +776,16 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr()); - + case Type::TemplateSpecialization: - assert(getCanonicalType(T) != T && + assert(getCanonicalType(T) != T && "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)); } - + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); return std::make_pair(Width, Align); } @@ -693,7 +798,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { unsigned ABIAlign = getTypeAlign(T); // Double and long long should be naturally aligned if possible. - if (const ComplexType* CT = T->getAsComplexType()) + if (const ComplexType* CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong)) @@ -702,102 +807,6 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { return ABIAlign; } - -/// LayoutField - Field layout. -void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo, - bool IsUnion, unsigned StructPacking, - ASTContext &Context) { - unsigned FieldPacking = StructPacking; - uint64_t FieldOffset = IsUnion ? 0 : Size; - uint64_t FieldSize; - unsigned FieldAlign; - - // FIXME: Should this override struct packing? Probably we want to - // take the minimum? - if (const PackedAttr *PA = FD->getAttr<PackedAttr>()) - FieldPacking = PA->getAlignment(); - - if (const Expr *BitWidthExpr = FD->getBitWidth()) { - // TODO: Need to check this algorithm on other targets! - // (tested on Linux-X86) - FieldSize = BitWidthExpr->EvaluateAsInt(Context).getZExtValue(); - - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(FD->getType()); - uint64_t TypeSize = FieldInfo.first; - - // Determine the alignment of this bitfield. The packing - // attributes define a maximum and the alignment attribute defines - // a minimum. - // FIXME: What is the right behavior when the specified alignment - // is smaller than the specified packing? - FieldAlign = FieldInfo.second; - if (FieldPacking) - FieldAlign = std::min(FieldAlign, FieldPacking); - if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - - // Check if we need to add padding to give the field the correct - // alignment. - if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - - // Padding members don't affect overall alignment - if (!FD->getIdentifier()) - FieldAlign = 1; - } else { - if (FD->getType()->isIncompleteArrayType()) { - // This is a flexible array member; we can't directly - // query getTypeInfo about these, so we figure it out here. - // Flexible array members don't have any size, but they - // have to be aligned appropriately for their element type. - FieldSize = 0; - const ArrayType* ATy = Context.getAsArrayType(FD->getType()); - FieldAlign = Context.getTypeAlign(ATy->getElementType()); - } else if (const ReferenceType *RT = FD->getType()->getAsReferenceType()) { - unsigned AS = RT->getPointeeType().getAddressSpace(); - FieldSize = Context.Target.getPointerWidth(AS); - FieldAlign = Context.Target.getPointerAlign(AS); - } else { - std::pair<uint64_t, unsigned> FieldInfo = - Context.getTypeInfo(FD->getType()); - FieldSize = FieldInfo.first; - FieldAlign = FieldInfo.second; - } - - // Determine the alignment of this bitfield. The packing - // attributes define a maximum and the alignment attribute defines - // a minimum. Additionally, the packing alignment must be at least - // a byte for non-bitfields. - // - // FIXME: What is the right behavior when the specified alignment - // is smaller than the specified packing? - if (FieldPacking) - FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking)); - if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) - FieldAlign = std::max(FieldAlign, AA->getAlignment()); - - // Round up the current record size to the field's alignment boundary. - FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); - } - - // Place this field at the current location. - FieldOffsets[FieldNo] = FieldOffset; - - // Reserve space for this field. - if (IsUnion) { - Size = std::max(Size, FieldSize); - } else { - Size = FieldOffset + FieldSize; - } - - // Remember the next available offset. - NextOffset = Size; - - // Remember max struct/class alignment. - Alignment = std::max(Alignment, FieldAlign); -} - static void CollectLocalObjCIvars(ASTContext *Ctx, const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl<FieldDecl*> &Fields) { @@ -836,7 +845,7 @@ void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, E = PD->prop_end(); I != E; ++I) if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) Ivars.push_back(Ivar); - + // Also look into nested protocols. for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), E = PD->protocol_end(); P != E; ++P) @@ -876,8 +885,7 @@ unsigned ASTContext::CountProtocolSynthesizedIvars(const ObjCProtocolDecl *PD) { return count; } -unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) -{ +unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(), E = OI->prop_end(); I != E; ++I) { @@ -894,6 +902,52 @@ unsigned ASTContext::CountSynthesizedIvars(const ObjCInterfaceDecl *OI) return count; } +/// \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; +} + +/// \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; +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -905,14 +959,14 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, assert(!D->isForwardDecl() && "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. - ObjCContainerDecl *Key = + ObjCContainerDecl *Key = Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) return *Entry; - unsigned FieldCount = D->ivar_size(); // Add in synthesized ivar count if laying out an implementation. if (Impl) { + unsigned FieldCount = D->ivar_size(); unsigned SynthCount = CountSynthesizedIvars(D); FieldCount += SynthCount; // If there aren't any sythesized ivars then reuse the interface @@ -923,40 +977,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, return getObjCLayout(D, 0); } - ASTRecordLayout *NewEntry = NULL; - if (ObjCInterfaceDecl *SD = D->getSuperClass()) { - const ASTRecordLayout &SL = getASTObjCInterfaceLayout(SD); - unsigned Alignment = SL.getAlignment(); - - // We start laying out ivars not at the end of the superclass - // structure, but at the next byte following the last field. - uint64_t Size = llvm::RoundUpToAlignment(SL.NextOffset, 8); + const ASTRecordLayout *NewEntry = + ASTRecordLayoutBuilder::ComputeLayout(*this, D, Impl); + ObjCLayouts[Key] = NewEntry; - ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(Size, Alignment); - NewEntry->InitializeLayout(FieldCount); - } else { - ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(); - NewEntry->InitializeLayout(FieldCount); - } - - unsigned StructPacking = 0; - if (const PackedAttr *PA = D->getAttr<PackedAttr>()) - StructPacking = PA->getAlignment(); - - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), - AA->getAlignment())); - - // Layout each ivar sequentially. - unsigned i = 0; - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - ShallowCollectObjCIvars(D, Ivars, Impl); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); - - // Finally, round the size of the total struct up to the alignment of the - // struct itself. - NewEntry->FinalizeLayout(); return *NewEntry; } @@ -978,37 +1002,15 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { assert(D && "Cannot get layout of forward declarations!"); // Look up this layout, if already laid out, return what we have. - const ASTRecordLayout *&Entry = ASTRecordLayouts[D]; + // Note that we can't save a reference to the entry because this function + // is recursive. + const ASTRecordLayout *Entry = ASTRecordLayouts[D]; if (Entry) return *Entry; - // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can - // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into. - ASTRecordLayout *NewEntry = new ASTRecordLayout(); - Entry = NewEntry; - - // FIXME: Avoid linear walk through the fields, if possible. - NewEntry->InitializeLayout(std::distance(D->field_begin(), D->field_end())); - bool IsUnion = D->isUnion(); - - unsigned StructPacking = 0; - if (const PackedAttr *PA = D->getAttr<PackedAttr>()) - StructPacking = PA->getAlignment(); + const ASTRecordLayout *NewEntry = + ASTRecordLayoutBuilder::ComputeLayout(*this, D); + ASTRecordLayouts[D] = NewEntry; - if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) - NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), - AA->getAlignment())); - - // Layout each field, for now, just sequentially, respecting alignment. In - // the future, this will need to be tweakable by targets. - unsigned FieldIdx = 0; - for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); - Field != FieldEnd; (void)++Field, ++FieldIdx) - NewEntry->LayoutField(*Field, FieldIdx, IsUnion, StructPacking, *this); - - // Finally, round the size of the total struct up to the alignment of the - // struct itself. - NewEntry->FinalizeLayout(getLangOptions().CPlusPlus); return *NewEntry; } @@ -1016,102 +1018,111 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // Type creation/memoization methods //===----------------------------------------------------------------------===// +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; + } + + ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals); + 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); +} + QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { QualType CanT = getCanonicalType(T); if (CanT.getAddressSpace() == AddressSpace) return T; - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - QualType::GCAttrTypes GCAttr = QualType::GCNone; - Type *TypeNode = T.getTypePtr(); - - if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) { - // If this type already has an address space specified, it cannot get - // another one. - assert(EQT->getAddressSpace() == 0 && - "Type cannot be in multiple addr spaces!"); - GCAttr = EQT->getObjCGCAttr(); - TypeNode = EQT->getBaseType(); - } - - // Check if we've already instantiated this type. - llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); - void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - QualType Canonical; - if (!TypeNode->isCanonical()) { - Canonical = getAddrSpaceQualType(CanT, AddressSpace); - - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; - } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); + // 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); + + return getExtQualType(TypeNode, Quals); } QualType ASTContext::getObjCGCQualType(QualType T, - QualType::GCAttrTypes GCAttr) { + Qualifiers::GC GCAttr) { QualType CanT = getCanonicalType(T); if (CanT.getObjCGCAttr() == GCAttr) return T; - + if (T->isPointerType()) { - QualType Pointee = T->getAsPointerType()->getPointeeType(); - if (Pointee->isPointerType()) { + QualType Pointee = T->getAs<PointerType>()->getPointeeType(); + if (Pointee->isAnyPointerType()) { QualType ResultType = getObjCGCQualType(Pointee, GCAttr); return getPointerType(ResultType); } } - // If we are composing extended qualifiers together, merge together into one - // ExtQualType node. - unsigned CVRQuals = T.getCVRQualifiers(); - Type *TypeNode = T.getTypePtr(); - unsigned AddressSpace = 0; - - if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) { - // If this type already has an address space specified, it cannot get - // another one. - assert(EQT->getObjCGCAttr() == QualType::GCNone && - "Type cannot be in multiple addr spaces!"); - AddressSpace = EQT->getAddressSpace(); - TypeNode = EQT->getBaseType(); - } - - // Check if we've already instantiated an gc qual'd type of this type. - llvm::FoldingSetNodeID ID; - ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); - void *InsertPos = 0; - if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) - return QualType(EXTQy, CVRQuals); - - // If the base type isn't canonical, this won't be a canonical type either, - // so fill in the canonical type field. - // FIXME: Isn't this also not canonical if the base type is a array - // or pointer type? I can't find any documentation for objc_gc, though... - QualType Canonical; - if (!T->isCanonical()) { - Canonical = getObjCGCQualType(CanT, GCAttr); - - // Update InsertPos, the previous call could have invalidated it. - ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); - assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an ObjCGC specified, it cannot get + // another one. + assert(!Quals.hasObjCGCAttr() && + "Type cannot have multiple ObjCGCs!"); + Quals.addObjCGCAttr(GCAttr); + + return getExtQualType(TypeNode, Quals); +} + +QualType ASTContext::getNoReturnType(QualType T) { + QualType ResultType; + if (T->isPointerType()) { + QualType Pointee = T->getAs<PointerType>()->getPointeeType(); + ResultType = getNoReturnType(Pointee); + ResultType = getPointerType(ResultType); + } else if (T->isBlockPointerType()) { + QualType Pointee = T->getAs<BlockPointerType>()->getPointeeType(); + ResultType = getNoReturnType(Pointee); + ResultType = getBlockPointerType(ResultType); + } else { + assert (T->isFunctionType() + && "can't noreturn qualify non-pointer to function or block type"); + + if (const FunctionNoProtoType *FNPT = T->getAs<FunctionNoProtoType>()) { + ResultType = getFunctionNoProtoType(FNPT->getResultType(), true); + } 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); + } } - ExtQualType *New = - new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); - ExtQualTypes.InsertNode(New, InsertPos); - Types.push_back(New); - return QualType(New, CVRQuals); + + return getQualifiedType(ResultType, T.getQualifiers()); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1121,22 +1132,22 @@ QualType ASTContext::getComplexType(QualType T) { // structure. llvm::FoldingSetNodeID ID; ComplexType::Profile(ID, T); - + void *InsertPos = 0; if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(CT, 0); - + // 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()) { Canonical = getComplexType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - ComplexType *New = new (*this,8) ComplexType(T, Canonical); + ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical); Types.push_back(New); ComplexTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1158,28 +1169,28 @@ QualType ASTContext::getPointerType(QualType T) { // structure. llvm::FoldingSetNodeID ID; PointerType::Profile(ID, T); - + void *InsertPos = 0; if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - + // 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()) { Canonical = getPointerType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - PointerType *New = new (*this,8) PointerType(T, Canonical); + PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical); Types.push_back(New); PointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); } -/// getBlockPointerType - Return the uniqued reference to the type for +/// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) { assert(T->isFunctionType() && "block of function types only"); @@ -1187,24 +1198,25 @@ QualType ASTContext::getBlockPointerType(QualType T) { // structure. llvm::FoldingSetNodeID ID; BlockPointerType::Profile(ID, T); - + void *InsertPos = 0; if (BlockPointerType *PT = BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - - // If the block pointee type isn't canonical, this won't be a canonical + + // If the block 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()) { Canonical = getBlockPointerType(getCanonicalType(T)); - + // Get the new insert position for the node we care about. BlockPointerType *NewIP = BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - BlockPointerType *New = new (*this,8) BlockPointerType(T, Canonical); + BlockPointerType *New + = new (*this, TypeAlignment) BlockPointerType(T, Canonical); Types.push_back(New); BlockPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1235,7 +1247,8 @@ QualType ASTContext::getLValueReferenceType(QualType T) { assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical); + LValueReferenceType *New + = new (*this, TypeAlignment) LValueReferenceType(T, Canonical); Types.push_back(New); LValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1266,7 +1279,8 @@ QualType ASTContext::getRValueReferenceType(QualType T) { assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical); + RValueReferenceType *New + = new (*this, TypeAlignment) RValueReferenceType(T, Canonical); Types.push_back(New); RValueReferenceTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1274,8 +1288,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) { /// getMemberPointerType - Return the uniqued reference to the type for a /// member pointer to the specified type, in the specified class. -QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) -{ +QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1297,15 +1310,16 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - MemberPointerType *New = new (*this,8) MemberPointerType(T, Cls, Canonical); + MemberPointerType *New + = new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical); Types.push_back(New); MemberPointerTypes.InsertNode(New, InsertPos); return QualType(New, 0); } -/// getConstantArrayType - Return the unique reference to the type for an +/// getConstantArrayType - Return the unique reference to the type for an /// array of the specified element type. -QualType ASTContext::getConstantArrayType(QualType EltTy, +QualType ASTContext::getConstantArrayType(QualType EltTy, const llvm::APInt &ArySizeIn, ArrayType::ArraySizeModifier ASM, unsigned EltTypeQuals) { @@ -1316,44 +1330,93 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // the target. llvm::APInt ArySize(ArySizeIn); ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); - + llvm::FoldingSetNodeID ID; ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals); - + void *InsertPos = 0; - if (ConstantArrayType *ATP = + if (ConstantArrayType *ATP = ConstantArrayTypes.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()) { - Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, + Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize, ASM, EltTypeQuals); // Get the new insert position for the node we care about. - ConstantArrayType *NewIP = + ConstantArrayType *NewIP = ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - - ConstantArrayType *New = - new(*this,8)ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + + ConstantArrayType *New = new(*this,TypeAlignment) + ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } +/// getConstantArrayWithExprType - Return a reference to the type for +/// an array of the specified element type. +QualType +ASTContext::getConstantArrayWithExprType(QualType EltTy, + const llvm::APInt &ArySizeIn, + Expr *ArySizeExpr, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals, + SourceRange Brackets) { + // 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())); + + // Compute the canonical ConstantArrayType. + QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), + ArySize, ASM, EltTypeQuals); + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + ConstantArrayWithExprType *New = new(*this, TypeAlignment) + ConstantArrayWithExprType(EltTy, Canonical, ArySize, ArySizeExpr, + ASM, EltTypeQuals, Brackets); + Types.push_back(New); + return QualType(New, 0); +} + +/// getConstantArrayWithoutExprType - Return a reference to the type for +/// an array of the specified element type. +QualType +ASTContext::getConstantArrayWithoutExprType(QualType EltTy, + const llvm::APInt &ArySizeIn, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + // 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())); + + // Compute the canonical ConstantArrayType. + QualType Canonical = getConstantArrayType(getCanonicalType(EltTy), + ArySize, ASM, EltTypeQuals); + ConstantArrayWithoutExprType *New = new(*this, TypeAlignment) + ConstantArrayWithoutExprType(EltTy, Canonical, ArySize, ASM, EltTypeQuals); + Types.push_back(New); + return QualType(New, 0); +} + /// getVariableArrayType - Returns a non-unique reference to the type for a /// variable array of the specified element type. -QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, +QualType ASTContext::getVariableArrayType(QualType EltTy, + Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { + unsigned EltTypeQuals, + SourceRange Brackets) { // Since we don't unique expressions, it isn't possible to unique VLA's // that have an expression provided for their size. - VariableArrayType *New = - new(*this,8)VariableArrayType(EltTy,QualType(), NumElts, ASM, EltTypeQuals); + VariableArrayType *New = new(*this, TypeAlignment) + VariableArrayType(EltTy, QualType(), NumElts, ASM, EltTypeQuals, Brackets); VariableArrayTypes.push_back(New); Types.push_back(New); @@ -1362,22 +1425,46 @@ QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, /// getDependentSizedArrayType - Returns a non-unique reference to /// the type for a dependently-sized array of the specified element -/// type. FIXME: We will need these to be uniqued, or at least -/// comparable, at some point. -QualType ASTContext::getDependentSizedArrayType(QualType EltTy, Expr *NumElts, +/// type. +QualType ASTContext::getDependentSizedArrayType(QualType EltTy, + Expr *NumElts, ArrayType::ArraySizeModifier ASM, - unsigned EltTypeQuals) { - assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && + unsigned EltTypeQuals, + SourceRange Brackets) { + assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && "Size must be type- or value-dependent!"); - // Since we don't unique expressions, it isn't possible to unique - // dependently-sized array types. + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM, + EltTypeQuals, NumElts); - DependentSizedArrayType *New = - new (*this,8) DependentSizedArrayType(EltTy, QualType(), NumElts, - ASM, EltTypeQuals); + 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. + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, QualType(Canon, 0), + NumElts, ASM, EltTypeQuals, Brackets); + } else { + QualType CanonEltTy = getCanonicalType(EltTy); + if (CanonEltTy == EltTy) { + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, QualType(), + NumElts, ASM, EltTypeQuals, Brackets); + DependentSizedArrayTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts, + ASM, EltTypeQuals, + SourceRange()); + New = new (*this, TypeAlignment) + DependentSizedArrayType(*this, EltTy, Canon, + NumElts, ASM, EltTypeQuals, Brackets); + } + } - DependentSizedArrayTypes.push_back(New); Types.push_back(New); return QualType(New, 0); } @@ -1389,7 +1476,7 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals); void *InsertPos = 0; - if (IncompleteArrayType *ATP = + if (IncompleteArrayType *ATP = IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(ATP, 0); @@ -1407,8 +1494,8 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - IncompleteArrayType *New = new (*this,8) IncompleteArrayType(EltTy, Canonical, - ASM, EltTypeQuals); + IncompleteArrayType *New = new (*this, TypeAlignment) + IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals); IncompleteArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); @@ -1419,13 +1506,13 @@ QualType ASTContext::getIncompleteArrayType(QualType EltTy, /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { BuiltinType *baseType; - + baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); - + // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::Vector); + VectorType::Profile(ID, vecType, NumElts, Type::Vector); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1435,12 +1522,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { QualType Canonical; if (!vecType->isCanonical()) { Canonical = getVectorType(getCanonicalType(vecType), NumElts); - + // Get the new insert position for the node we care about. VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - VectorType *New = new (*this,8) VectorType(vecType, NumElts, Canonical); + VectorType *New = new (*this, TypeAlignment) + VectorType(vecType, NumElts, Canonical); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -1450,13 +1538,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { /// the specified element type and size. VectorType must be a built-in type. QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { BuiltinType *baseType; - + baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type"); - + // Check if we've already instantiated a vector of this type. llvm::FoldingSetNodeID ID; - VectorType::Profile(ID, vecType, NumElts, Type::ExtVector); + VectorType::Profile(ID, vecType, NumElts, Type::ExtVector); void *InsertPos = 0; if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(VTP, 0); @@ -1466,53 +1554,79 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { QualType Canonical; if (!vecType->isCanonical()) { Canonical = getExtVectorType(getCanonicalType(vecType), NumElts); - + // Get the new insert position for the node we care about. VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - ExtVectorType *New = new (*this,8) ExtVectorType(vecType, NumElts, Canonical); + ExtVectorType *New = new (*this, TypeAlignment) + ExtVectorType(vecType, NumElts, Canonical); VectorTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); } -QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, +QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, Expr *SizeExpr, SourceLocation AttrLoc) { - DependentSizedExtVectorType *New = - new (*this,8) DependentSizedExtVectorType(vecType, QualType(), - SizeExpr, AttrLoc); + llvm::FoldingSetNodeID ID; + DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType), + SizeExpr); + + 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. + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(Canon, 0), + SizeExpr, AttrLoc); + } else { + QualType CanonVecTy = getCanonicalType(vecType); + if (CanonVecTy == vecType) { + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr, + AttrLoc); + DependentSizedExtVectorTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc); + } + } - DependentSizedExtVectorTypes.push_back(New); Types.push_back(New); return QualType(New, 0); } /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) { +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionNoProtoType::Profile(ID, ResultTy); - + FunctionNoProtoType::Profile(ID, ResultTy, NoReturn); + void *InsertPos = 0; - if (FunctionNoProtoType *FT = + if (FunctionNoProtoType *FT = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(FT, 0); - + QualType Canonical; if (!ResultTy->isCanonical()) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy)); - + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); + // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; } - - FunctionNoProtoType *New =new(*this,8)FunctionNoProtoType(ResultTy,Canonical); + + FunctionNoProtoType *New = new (*this, TypeAlignment) + FunctionNoProtoType(ResultTy, Canonical, NoReturn); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1524,16 +1638,22 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray) { + const QualType *ExArray, bool NoReturn) { + if (LangOpts.CPlusPlus) { + for (unsigned i = 0; i != NumArgs; ++i) + assert(!ArgArray[i].hasQualifiers() && + "C++ arguments can't have toplevel qualifiers!"); + } + // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - NumExs, ExArray); + NumExs, ExArray, NoReturn); void *InsertPos = 0; - if (FunctionProtoType *FTP = + if (FunctionProtoType *FTP = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(FTP, 0); @@ -1556,7 +1676,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, - isVariadic, TypeQuals); + isVariadic, TypeQuals, false, + false, 0, 0, NoReturn); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1567,13 +1688,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // FunctionProtoType objects are allocated with extra bytes after them // for two variable size arrays (for parameter and exception types) at the // end of them. - FunctionProtoType *FTP = + FunctionProtoType *FTP = (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + NumArgs*sizeof(QualType) + - NumExs*sizeof(QualType), 8); + NumExs*sizeof(QualType), TypeAlignment); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical); + ExArray, NumExs, Canonical, NoReturn); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -1584,27 +1705,26 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { assert(Decl && "Passed null for Decl param"); if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) return getTypedefType(Typedef); else if (isa<TemplateTypeParmDecl>(Decl)) { assert(false && "Template type parameter types are always available."); - } else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl)) + } else if (ObjCInterfaceDecl *ObjCInterface + = dyn_cast<ObjCInterfaceDecl>(Decl)) return getObjCInterfaceType(ObjCInterface); if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else - Decl->TypeForDecl = new (*this,8) RecordType(Record); - } - else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); + } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; else - Decl->TypeForDecl = new (*this,8) EnumType(Enum); - } - else + Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Enum); + } else assert(false && "TypeDecl without a type?"); if (!PrevDecl) Types.push_back(Decl->TypeForDecl); @@ -1615,45 +1735,36 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { /// specified typename decl. QualType ASTContext::getTypedefType(TypedefDecl *Decl) { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - QualType Canonical = getCanonicalType(Decl->getUnderlyingType()); - Decl->TypeForDecl = new(*this,8) TypedefType(Type::Typedef, Decl, Canonical); - Types.push_back(Decl->TypeForDecl); - return QualType(Decl->TypeForDecl, 0); -} -/// getObjCInterfaceType - Return the unique reference to the type for the -/// specified ObjC interface decl. -QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) { - if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); - - ObjCInterfaceDecl *OID = const_cast<ObjCInterfaceDecl*>(Decl); - Decl->TypeForDecl = new(*this,8) ObjCInterfaceType(Type::ObjCInterface, OID); + QualType Canonical = getCanonicalType(Decl->getUnderlyingType()); + Decl->TypeForDecl = new(*this, TypeAlignment) + TypedefType(Type::Typedef, Decl, Canonical); Types.push_back(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } /// \brief Retrieve the template type parameter type for a template -/// parameter or parameter pack with the given depth, index, and (optionally) +/// parameter or parameter pack with the given depth, index, and (optionally) /// name. -QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, +QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, IdentifierInfo *Name) { llvm::FoldingSetNodeID ID; TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name); void *InsertPos = 0; - TemplateTypeParmType *TypeParm + TemplateTypeParmType *TypeParm = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); if (TypeParm) return QualType(TypeParm, 0); - + if (Name) { QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); - TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack, - Name, Canon); + TypeParm = new (*this, TypeAlignment) + TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon); } else - TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, ParameterPack); + TypeParm = new (*this, TypeAlignment) + TemplateTypeParmType(Depth, Index, ParameterPack); Types.push_back(TypeParm); TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos); @@ -1661,54 +1772,83 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, return QualType(TypeParm, 0); } -QualType +QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { if (!Canon.isNull()) Canon = getCanonicalType(Canon); + else { + // Build the canonical template specialization type. + 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])); - llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, Template, Args, NumArgs); + // Determine whether this canonical template specialization type already + // exists. + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, CanonTemplate, + CanonArgs.data(), NumArgs, *this); - void *InsertPos = 0; - TemplateSpecializationType *Spec - = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + void *InsertPos = 0; + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); - if (Spec) - return QualType(Spec, 0); - - void *Mem = Allocate((sizeof(TemplateSpecializationType) + + if (!Spec) { + // Allocate a new canonical template specialization type. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + TypeAlignment); + Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, + CanonArgs.data(), NumArgs, + Canon); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + } + + if (Canon.isNull()) + Canon = QualType(Spec, 0); + assert(Canon->isDependentType() && + "Non-dependent template-id type must have a canonical type"); + } + + // 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. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), - 8); - Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); - Types.push_back(Spec); - TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + TypeAlignment); + TemplateSpecializationType *Spec + = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs, + Canon); - return QualType(Spec, 0); + Types.push_back(Spec); + return QualType(Spec, 0); } -QualType +QualType ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType) { llvm::FoldingSetNodeID ID; QualifiedNameType::Profile(ID, NNS, NamedType); void *InsertPos = 0; - QualifiedNameType *T + QualifiedNameType *T = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); - T = new (*this) QualifiedNameType(NNS, NamedType, + T = new (*this) QualifiedNameType(NNS, NamedType, getCanonicalType(NamedType)); Types.push_back(T); QualifiedNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); } -QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, +QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); @@ -1723,7 +1863,7 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, TypenameType::Profile(ID, NNS, Name); void *InsertPos = 0; - TypenameType *T + TypenameType *T = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); @@ -1731,11 +1871,11 @@ QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, T = new (*this) TypenameType(NNS, Name, Canon); Types.push_back(T); TypenameTypes.InsertNode(T, InsertPos); - return QualType(T, 0); + return QualType(T, 0); } -QualType -ASTContext::getTypenameType(NestedNameSpecifier *NNS, +QualType +ASTContext::getTypenameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *TemplateId, QualType Canon) { assert(NNS->isDependent() && "nested-name-specifier must be dependent"); @@ -1745,7 +1885,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) { const TemplateSpecializationType *CanonTemplateId - = CanonType->getAsTemplateSpecializationType(); + = CanonType->getAs<TemplateSpecializationType>(); assert(CanonTemplateId && "Canonical type must also be a template specialization type"); Canon = getTypenameType(CanonNNS, CanonTemplateId); @@ -1756,7 +1896,7 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, TypenameType::Profile(ID, NNS, TemplateId); void *InsertPos = 0; - TypenameType *T + TypenameType *T = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); @@ -1764,7 +1904,26 @@ ASTContext::getTypenameType(NestedNameSpecifier *NNS, T = new (*this) TypenameType(NNS, TemplateId, Canon); Types.push_back(T); TypenameTypes.InsertNode(T, InsertPos); - return QualType(T, 0); + return QualType(T, 0); +} + +QualType +ASTContext::getElaboratedType(QualType UnderlyingType, + ElaboratedType::TagKind Tag) { + llvm::FoldingSetNodeID ID; + ElaboratedType::Profile(ID, UnderlyingType, Tag); + + 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); } /// CmpProtocolNames - Comparison predicate for sorting protocols @@ -1777,7 +1936,7 @@ static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, unsigned &NumProtocols) { ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; - + // Sort protocols, keyed by name. std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames); @@ -1788,15 +1947,15 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, /// getObjCObjectPointerType - Return a ObjCObjectPointerType type for /// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **Protocols, +QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, + ObjCProtocolDecl **Protocols, unsigned NumProtocols) { // Sort the protocol list alphabetically to canonicalize it. if (NumProtocols) SortAndUniqueProtocols(Protocols, NumProtocols); llvm::FoldingSetNodeID ID; - ObjCObjectPointerType::Profile(ID, Decl, Protocols, NumProtocols); + ObjCObjectPointerType::Profile(ID, InterfaceT, Protocols, NumProtocols); void *InsertPos = 0; if (ObjCObjectPointerType *QT = @@ -1804,46 +1963,89 @@ QualType ASTContext::getObjCObjectPointerType(ObjCInterfaceDecl *Decl, return QualType(QT, 0); // No Match; - ObjCObjectPointerType *QType = - new (*this,8) ObjCObjectPointerType(Decl, Protocols, NumProtocols); - + ObjCObjectPointerType *QType = new (*this, TypeAlignment) + ObjCObjectPointerType(InterfaceT, Protocols, NumProtocols); + Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } -/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for -/// the given interface decl and the conforming protocol list. -QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, +/// 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, ObjCProtocolDecl **Protocols, unsigned NumProtocols) { - // Sort the protocol list alphabetically to canonicalize it. - SortAndUniqueProtocols(Protocols, NumProtocols); - + if (NumProtocols) + // Sort the protocol list alphabetically to canonicalize it. + SortAndUniqueProtocols(Protocols, NumProtocols); + llvm::FoldingSetNodeID ID; - ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); - + ObjCInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); + void *InsertPos = 0; - if (ObjCQualifiedInterfaceType *QT = - ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + if (ObjCInterfaceType *QT = + ObjCInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - + // No Match; - ObjCQualifiedInterfaceType *QType = - new (*this,8) ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); + ObjCInterfaceType *QType = new (*this, TypeAlignment) + ObjCInterfaceType(const_cast<ObjCInterfaceDecl*>(Decl), + Protocols, NumProtocols); + Types.push_back(QType); + ObjCInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +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); - ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + ObjCProtocolListTypes.InsertNode(QType, InsertPos); return QualType(QType, 0); } /// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique /// TypeOfExprType AST's (since expression's are never shared). For example, /// multiple declarations that refer to "typeof(x)" all contain different -/// DeclRefExpr's. This doesn't effect the type checker, since it operates +/// DeclRefExpr's. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { - QualType Canonical = getCanonicalType(tofExpr->getType()); - TypeOfExprType *toe = new (*this,8) TypeOfExprType(tofExpr, Canonical); + TypeOfExprType *toe; + if (tofExpr->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentTypeOfExprType::Profile(ID, *this, tofExpr); + + 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. + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, + QualType((TypeOfExprType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon + = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr); + DependentTypeOfExprTypes.InsertNode(Canon, InsertPos); + toe = Canon; + } + } else { + QualType Canonical = getCanonicalType(tofExpr->getType()); + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical); + } Types.push_back(toe); return QualType(toe, 0); } @@ -1851,11 +2053,11 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) { /// 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 -/// an issue. This doesn't effect the type checker, since it operates +/// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getTypeOfType(QualType tofType) { QualType Canonical = getCanonicalType(tofType); - TypeOfType *tot = new (*this,8) TypeOfType(tofType, Canonical); + TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); Types.push_back(tot); return QualType(tot, 0); } @@ -1865,7 +2067,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) { static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { if (e->isTypeDependent()) return Context.DependentTy; - + // 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)) { @@ -1881,39 +2083,63 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) { // return type of that function. if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens())) return CE->getCallReturnType(); - + QualType T = e->getType(); - - // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is + + // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is // defined as T&, otherwise decltype(e) is defined as T. if (e->isLvalue(Context) == Expr::LV_Valid) T = Context.getLValueReferenceType(T); - + return T; } /// 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 -/// an issue. This doesn't effect the type checker, since it operates +/// an issue. This doesn't effect the type checker, since it operates /// on canonical type's (which are always unique). QualType ASTContext::getDecltypeType(Expr *e) { - QualType T = getDecltypeForExpr(e, *this); - DecltypeType *dt = new (*this, 8) DecltypeType(e, getCanonicalType(T)); + DecltypeType *dt; + if (e->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentDecltypeType::Profile(ID, *this, e); + + 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. + dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy, + QualType((DecltypeType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); + DependentDecltypeTypes.InsertNode(Canon, InsertPos); + dt = Canon; + } + } else { + QualType T = getDecltypeForExpr(e, *this); + dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T)); + } Types.push_back(dt); return QualType(dt, 0); } /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. -QualType ASTContext::getTagDeclType(TagDecl *Decl) { +QualType ASTContext::getTagDeclType(const TagDecl *Decl) { assert (Decl); - return getTypeDeclType(Decl); + // FIXME: What is the design on getTagDeclType when it requires casting + // away const? mutable? + return getTypeDeclType(const_cast<TagDecl*>(Decl)); } -/// 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>. +/// 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>. QualType ASTContext::getSizeType() const { return getFromTargetType(Target.getSizeType()); } @@ -1948,99 +2174,143 @@ QualType ASTContext::getPointerDiffType() const { /// 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. -QualType ASTContext::getCanonicalType(QualType T) { - QualType CanType = T.getTypePtr()->getCanonicalTypeInternal(); - - // If the result has type qualifiers, make sure to canonicalize them as well. - unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers(); - if (TypeQuals == 0) return CanType; +CanQualType ASTContext::getCanonicalType(QualType T) { + 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. + + // If there are no new qualifiers to push down, stop here. + if (!Quals.hasQualifiers()) + return CanQualType::CreateUnsafe(CanType); - // If the type qualifiers are on an array type, get the canonical type of the - // array with the qualifiers applied to the element type. + // If the type qualifiers are on an array type, get the canonical + // type of the array with the qualifiers applied to the element + // type. ArrayType *AT = dyn_cast<ArrayType>(CanType); if (!AT) - return CanType.getQualifiedType(TypeQuals); - + return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals)); + // Get the canonical version of the element with the extra qualifiers on it. // This can recursively sink qualifiers through multiple levels of arrays. - QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals); + QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals); NewEltTy = getCanonicalType(NewEltTy); - + if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) - return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(), - CAT->getIndexTypeQualifier()); + return CanQualType::CreateUnsafe( + getConstantArrayType(NewEltTy, CAT->getSize(), + CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers())); if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) - return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier()); - + return CanQualType::CreateUnsafe( + getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeCVRQualifiers())); + if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT)) - return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), - DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier()); + return CanQualType::CreateUnsafe( + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr() ? + DSAT->getSizeExpr()->Retain() : 0, + DSAT->getSizeModifier(), + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); VariableArrayType *VAT = cast<VariableArrayType>(AT); - return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), - VAT->getSizeModifier(), - VAT->getIndexTypeQualifier()); -} - -Decl *ASTContext::getCanonicalDecl(Decl *D) { - if (!D) - return 0; - - if (TagDecl *Tag = dyn_cast<TagDecl>(D)) { - QualType T = getTagDeclType(Tag); - return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType) - ->getDecl()); - } - - if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) { - while (Template->getPreviousDeclaration()) - Template = Template->getPreviousDeclaration(); - return Template; - } - - if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { - while (Function->getPreviousDeclaration()) - Function = Function->getPreviousDeclaration(); - return const_cast<FunctionDecl *>(Function); - } - - if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) { - while (FunTmpl->getPreviousDeclaration()) - FunTmpl = FunTmpl->getPreviousDeclaration(); - return FunTmpl; - } - - if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { - while (Var->getPreviousDeclaration()) - Var = Var->getPreviousDeclaration(); - return const_cast<VarDecl *>(Var); - } - - return D; + return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy, + VAT->getSizeExpr() ? + VAT->getSizeExpr()->Retain() : 0, + VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange())); } 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()) - return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template))); + return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); + + // If this template name refers to a set of overloaded function templates, + /// the canonical template name merely stores the set of function templates. + 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) + CanonOvl = OverloadedFunctionDecl::Create(*this, + Ovl->getDeclContext(), + Ovl->getDeclName()); + + CanonOvl->addOverload( + AnyFunctionDecl::getFromNamedDecl(cast<NamedDecl>(Canon))); + } + } + + return TemplateName(CanonOvl? CanonOvl : Ovl); + } DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); return DTN->CanonicalTemplateName; } +TemplateArgument +ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + return Arg; + + case TemplateArgument::Expression: + // FIXME: Build canonical expression? + return Arg; + + case TemplateArgument::Declaration: + return TemplateArgument(SourceLocation(), + Arg.getAsDecl()->getCanonicalDecl()); + + case TemplateArgument::Integral: + return TemplateArgument(SourceLocation(), + *Arg.getAsIntegral(), + getCanonicalType(Arg.getIntegralType())); + + case TemplateArgument::Type: + return TemplateArgument(SourceLocation(), + getCanonicalType(Arg.getAsType())); + + case TemplateArgument::Pack: { + // FIXME: Allocate in ASTContext + TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()]; + unsigned Idx = 0; + for (TemplateArgument::pack_iterator A = Arg.pack_begin(), + AEnd = Arg.pack_end(); + A != AEnd; (void)++A, ++Idx) + CanonArgs[Idx] = getCanonicalTemplateArgument(*A); + + TemplateArgument Result; + Result.setArgumentPack(CanonArgs, Arg.pack_size(), false); + return Result; + } + } + + // Silence GCC warning + assert(false && "Unhandled template argument kind"); + return TemplateArgument(); +} + NestedNameSpecifier * ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { - if (!NNS) + if (!NNS) return 0; switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: // Canonicalize the prefix but keep the identifier the same. - return NestedNameSpecifier::Create(*this, + return NestedNameSpecifier::Create(*this, getCanonicalNestedNameSpecifier(NNS->getPrefix()), NNS->getAsIdentifier()); @@ -2052,14 +2322,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); - NestedNameSpecifier *Prefix = 0; - - // FIXME: This isn't the right check! - if (T->isDependentType()) - Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); - - return NestedNameSpecifier::Create(*this, Prefix, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, + return NestedNameSpecifier::Create(*this, 0, + NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, T.getTypePtr()); } @@ -2075,81 +2339,65 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { const ArrayType *ASTContext::getAsArrayType(QualType T) { // Handle the non-qualified case efficiently. - if (T.getCVRQualifiers() == 0) { + if (!T.hasQualifiers()) { // Handle the common positive case fast. if (const ArrayType *AT = dyn_cast<ArrayType>(T)) return AT; } - - // Handle the common negative case fast, ignoring CVR qualifiers. + + // Handle the common negative case fast. QualType CType = T->getCanonicalTypeInternal(); - - // Make sure to look through type qualifiers (like ExtQuals) for the negative - // test. - if (!isa<ArrayType>(CType) && - !isa<ArrayType>(CType.getUnqualifiedType())) + if (!isa<ArrayType>(CType)) return 0; - - // Apply any CVR qualifiers from the array type to the element type. This + + // Apply any qualifiers from the array type to the element type. This // 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." - + // 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 - // we must propagate them down into the elemeng type. - unsigned CVRQuals = T.getCVRQualifiers(); - unsigned AddrSpace = 0; - Type *Ty = T.getTypePtr(); - - // Rip through ExtQualType's and typedefs to get to a concrete type. - while (1) { - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(Ty)) { - AddrSpace = EXTQT->getAddressSpace(); - Ty = EXTQT->getBaseType(); - } else { - T = Ty->getDesugaredType(); - if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0) - break; - CVRQuals |= T.getCVRQualifiers(); - Ty = T.getTypePtr(); - } - } - + // we must propagate them down into the element type. + + QualifierCollector Qs; + const Type *Ty = Qs.strip(T.getDesugaredType()); + // If we have a simple case, just return now. const ArrayType *ATy = dyn_cast<ArrayType>(Ty); - if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0)) + if (ATy == 0 || Qs.empty()) return ATy; - + // 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. - QualType NewEltTy = ATy->getElementType(); - if (AddrSpace) - NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace); - NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals); - + QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs); + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), - CAT->getIndexTypeQualifier())); + CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy)) return cast<ArrayType>(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), - IAT->getIndexTypeQualifier())); + IAT->getIndexTypeCVRQualifiers())); - if (const DependentSizedArrayType *DSAT + if (const DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(ATy)) return cast<ArrayType>( - getDependentSizedArrayType(NewEltTy, - DSAT->getSizeExpr(), + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr() ? + DSAT->getSizeExpr()->Retain() : 0, DSAT->getSizeModifier(), - DSAT->getIndexTypeQualifier())); - + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); + const VariableArrayType *VAT = cast<VariableArrayType>(ATy); - return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + return cast<ArrayType>(getVariableArrayType(NewEltTy, + VAT->getSizeExpr() ? + VAT->getSizeExpr()->Retain() : 0, VAT->getSizeModifier(), - VAT->getIndexTypeQualifier())); + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange())); } @@ -2166,30 +2414,53 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { // (C99 6.7.3p8). const ArrayType *PrettyArrayType = getAsArrayType(Ty); assert(PrettyArrayType && "Not an array type!"); - + QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); // int x[restrict 4] -> int *restrict - return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); + return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); } -QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) { - QualType ElemTy = VAT->getElementType(); - - if (const VariableArrayType *VAT = getAsVariableArrayType(ElemTy)) - return getBaseElementType(VAT); - +QualType ASTContext::getBaseElementType(QualType QT) { + QualifierCollector Qs; + while (true) { + const Type *UT = Qs.strip(QT); + if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { + QT = AT->getElementType(); + } else { + return Qs.apply(QT); + } + } +} + +QualType ASTContext::getBaseElementType(const ArrayType *AT) { + QualType ElemTy = AT->getElementType(); + + if (const ArrayType *AT = getAsArrayType(ElemTy)) + return getBaseElementType(AT); + return ElemTy; } +/// getConstantArrayElementCount - Returns number of constant array elements. +uint64_t +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; +} + /// getFloatingRank - Return a relative rank for floating point types. /// This routine will assert if passed a built-in type that isn't a float. static FloatingRank getFloatingRank(QualType T) { - if (const ComplexType *CT = T->getAsComplexType()) + if (const ComplexType *CT = T->getAs<ComplexType>()) return getFloatingRank(CT->getElementType()); - assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type"); - switch (T->getAsBuiltinType()->getKind()) { + assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type"); + switch (T->getAs<BuiltinType>()->getKind()) { default: assert(0 && "getFloatingRank(): not a floating type"); case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; @@ -2197,8 +2468,8 @@ static FloatingRank getFloatingRank(QualType T) { } } -/// getFloatingTypeOfSizeWithinDomain - Returns a real floating -/// point or a complex type (based on typeDomain/typeSize). +/// getFloatingTypeOfSizeWithinDomain - Returns a real floating +/// point or a complex type (based on typeDomain/typeSize). /// 'typeDomain' is a real floating point or complex type. /// 'typeSize' is a real floating point or complex type. QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, @@ -2225,11 +2496,11 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, /// 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 -/// LHS < RHS, return -1. +/// LHS < RHS, return -1. int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { FloatingRank LHSR = getFloatingRank(LHS); FloatingRank RHSR = getFloatingRank(RHS); - + if (LHSR == RHSR) return 0; if (LHSR > RHSR) @@ -2245,6 +2516,15 @@ unsigned ASTContext::getIntegerRank(Type *T) { if (EnumType* ET = dyn_cast<EnumType>(T)) T = ET->getDecl()->getIntegerType().getTypePtr(); + if (T->isSpecificBuiltinType(BuiltinType::WChar)) + T = getFromTargetType(Target.getWCharType()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char16)) + T = getFromTargetType(Target.getChar16Type()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char32)) + T = getFromTargetType(Target.getChar32Type()).getTypePtr(); + // 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. @@ -2278,117 +2558,163 @@ unsigned ASTContext::getIntegerRank(Type *T) { } } -/// getIntegerTypeOrder - Returns the highest ranked integer type: +/// \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(); +} + +/// 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; +} + +/// getIntegerTypeOrder - Returns the highest ranked integer type: /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If -/// LHS < RHS, return -1. +/// LHS < RHS, return -1. int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { Type *LHSC = getCanonicalType(LHS).getTypePtr(); Type *RHSC = getCanonicalType(RHS).getTypePtr(); if (LHSC == RHSC) return 0; - + bool LHSUnsigned = LHSC->isUnsignedIntegerType(); bool RHSUnsigned = RHSC->isUnsignedIntegerType(); - + unsigned LHSRank = getIntegerRank(LHSC); unsigned RHSRank = getIntegerRank(RHSC); - + if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned. if (LHSRank == RHSRank) return 0; return LHSRank > RHSRank ? 1 : -1; } - + // 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; - + // 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 - // powers of two larger than each other, this is always safe. + // powers of two larger than each other, this is always safe. return -1; } // If the unsigned [RHS] type is larger, return it. if (RHSRank >= LHSRank) return -1; - + // 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 - // powers of two larger than each other, this is always safe. + // powers of two larger than each other, this is always safe. return 1; } -// getCFConstantStringType - Return the type used for constant CFStrings. +// getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() { if (!CFConstantStringTypeDecl) { - CFConstantStringTypeDecl = - RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + CFConstantStringTypeDecl = + RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("NSConstantString")); QualType FieldTypes[4]; - + // const int *isa; - FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + FieldTypes[0] = getPointerType(IntTy.withConst()); // int flags; FieldTypes[1] = IntTy; // const char *str; - FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + FieldTypes[2] = getPointerType(CharTy.withConst()); // long length; - FieldTypes[3] = LongTy; - + FieldTypes[3] = LongTy; + // Create fields for (unsigned i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, SourceLocation(), 0, - FieldTypes[i], /*BitWidth=*/0, + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); CFConstantStringTypeDecl->addDecl(Field); } CFConstantStringTypeDecl->completeDefinition(*this); } - + return getTagDeclType(CFConstantStringTypeDecl); } void ASTContext::setCFConstantStringType(QualType T) { - const RecordType *Rec = T->getAsRecordType(); + const RecordType *Rec = T->getAs<RecordType>(); assert(Rec && "Invalid CFConstantStringType"); CFConstantStringTypeDecl = Rec->getDecl(); } -QualType ASTContext::getObjCFastEnumerationStateType() -{ +QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), &Idents.get("__objcFastEnumerationState")); - + QualType FieldTypes[] = { UnsignedLongTy, - getPointerType(ObjCIdType), + getPointerType(ObjCIdTypedefType), getPointerType(UnsignedLongTy), getConstantArrayType(UnsignedLongTy, llvm::APInt(32, 5), ArrayType::Normal, 0) }; - + for (size_t i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, - ObjCFastEnumerationStateTypeDecl, - SourceLocation(), 0, - FieldTypes[i], /*BitWidth=*/0, + FieldDecl *Field = FieldDecl::Create(*this, + ObjCFastEnumerationStateTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*DInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } - + ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); } - + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); } void ASTContext::setObjCFastEnumerationStateType(QualType T) { - const RecordType *Rec = T->getAsRecordType(); + const RecordType *Rec = T->getAs<RecordType>(); assert(Rec && "Invalid ObjCFAstEnumerationStateType"); ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); } @@ -2399,7 +2725,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { if (const TypedefType *TT = dyn_cast<TypedefType>(T)) if (IdentifierInfo *II = TT->getDecl()->getIdentifier()) return II->isStr("BOOL"); - + return false; } @@ -2407,7 +2733,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) { /// purpose. int ASTContext::getObjCEncodingTypeSize(QualType type) { uint64_t sz = getTypeSize(type); - + // Make all integer and enum types at least as large as an int if (sz > 0 && type->isIntegralType()) sz = std::max(sz, getTypeSize(IntTy)); @@ -2419,7 +2745,7 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) { /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. -void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, +void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string& S) { // FIXME: This is not very efficient. // Encode type qualifer, 'in', 'inout', etc. for the return type. @@ -2444,13 +2770,13 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, S += llvm::utostr(ParmOffset); S += "@0:"; S += llvm::utostr(PtrSize); - + // Argument types. ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { ParmVarDecl *PVDecl = *PI; - QualType PType = PVDecl->getOriginalType(); + QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of @@ -2472,11 +2798,11 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, /// property declaration. If non-NULL, Container must be either an /// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be /// NULL when getting encodings for protocol properties. -/// 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 +/// 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 /// these attributes are defined by the following enumeration: /// @code /// enum PropertyAttributes { @@ -2493,7 +2819,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, /// kPropertyNonAtomic = 'N' // property non-atomic /// }; /// @endcode -void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, +void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, const Decl *Container, std::string& S) { // Collect information from the property implementation decl(s). @@ -2502,7 +2828,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, // FIXME: Duplicated code due to poor abstraction. if (Container) { - if (const ObjCCategoryImplDecl *CID = + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(Container)) { for (ObjCCategoryImplDecl::propimpl_iterator i = CID->propimpl_begin(), e = CID->propimpl_end(); @@ -2529,7 +2855,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, SynthesizePID = PID; } } - } + } } } @@ -2539,7 +2865,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, // Encode result type. // GCC has some special rules regarding encoding of properties which // closely resembles encoding of ivars. - getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0, + getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0, true /* outermost type */, true /* encoding for property */); @@ -2549,7 +2875,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, switch (PD->getSetterKind()) { case ObjCPropertyDecl::Assign: break; case ObjCPropertyDecl::Copy: S += ",C"; break; - case ObjCPropertyDecl::Retain: S += ",&"; break; + case ObjCPropertyDecl::Retain: S += ",&"; break; } } @@ -2560,7 +2886,7 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) S += ",N"; - + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { S += ",G"; S += PD->getGetterName().getAsString(); @@ -2581,17 +2907,17 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, } /// getLegacyIntegralTypeEncoding - -/// Another legacy compatibility encoding: 32-bit longs are encoded as -/// 'l' or 'L' , but not always. For typedefs, we need to use +/// Another legacy compatibility encoding: 32-bit longs are encoded as +/// 'l' or 'L' , but not always. For typedefs, we need to use /// 'i' or 'I' instead if encoding a struct field, or a pointer! /// void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { - if (dyn_cast<TypedefType>(PointeeTy.getTypePtr())) { - if (const BuiltinType *BT = PointeeTy->getAsBuiltinType()) { + if (isa<TypedefType>(PointeeTy.getTypePtr())) { + if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) { if (BT->getKind() == BuiltinType::ULong && ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) PointeeTy = UnsignedIntTy; - else + else if (BT->getKind() == BuiltinType::Long && ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) PointeeTy = IntTy; @@ -2605,11 +2931,11 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S, // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, true, true, Field, + getObjCEncodingForTypeImpl(T, S, true, true, Field, true /* outermost type */); } -static void EncodeBitField(const ASTContext *Context, std::string& S, +static void EncodeBitField(const ASTContext *Context, std::string& S, const FieldDecl *FD) { const Expr *E = FD->getBitWidth(); assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); @@ -2625,83 +2951,66 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const FieldDecl *FD, bool OutermostType, bool EncodingProperty) { - if (const BuiltinType *BT = T->getAsBuiltinType()) { - if (FD && FD->isBitField()) { - EncodeBitField(this, S, FD); - } - else { - char encoding; - switch (BT->getKind()) { - default: assert(0 && "Unhandled builtin type kind"); - 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; - case BuiltinType::ULong: - encoding = - (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q'; - break; - 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; - case BuiltinType::Long: - encoding = - (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + if (const BuiltinType *BT = T->getAs<BuiltinType>()) { + if (FD && FD->isBitField()) + return EncodeBitField(this, S, FD); + char encoding; + switch (BT->getKind()) { + default: assert(0 && "Unhandled builtin type kind"); + 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; + case BuiltinType::ULong: + encoding = + (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q'; 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; - } - - S += encoding; + 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; + case BuiltinType::Long: + encoding = + (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + 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; } - } else if (const ComplexType *CT = T->getAsComplexType()) { + + S += encoding; + return; + } + + if (const ComplexType *CT = T->getAs<ComplexType>()) { S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, false); - } else if (T->isObjCQualifiedIdType()) { - getObjCEncodingForTypeImpl(getObjCIdType(), S, - ExpandPointedToStructures, - ExpandStructures, FD); - if (FD || EncodingProperty) { - // Note that we do extended encoding of protocol qualifer list - // Only when doing ivar or property encoding. - const ObjCObjectPointerType *QIDT = T->getAsObjCQualifiedIdType(); - S += '"'; - for (ObjCObjectPointerType::qual_iterator I = QIDT->qual_begin(), - E = QIDT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } return; } - else if (const PointerType *PT = T->getAsPointerType()) { + + if (const PointerType *PT = T->getAs<PointerType>()) { QualType PointeeTy = PT->getPointeeType(); 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! - // Also, do not emit the 'r' for anything but the outermost type! - if (dyn_cast<TypedefType>(T.getTypePtr())) { + // Also, do not emit the 'r' for anything but the outermost type! + if (isa<TypedefType>(T.getTypePtr())) { if (OutermostType && T.isConstQualified()) { isReadOnly = true; S += 'r'; } - } - else if (OutermostType) { + } else if (OutermostType) { QualType P = PointeeTy; - while (P->getAsPointerType()) - P = P->getAsPointerType()->getPointeeType(); + while (P->getAs<PointerType>()) + P = P->getAs<PointerType>()->getPointeeType(); if (P.isConstQualified()) { isReadOnly = true; S += 'r'; @@ -2718,46 +3027,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S.replace(S.end()-2, S.end(), replace); } } - if (isObjCIdStructType(PointeeTy)) { - S += '@'; - return; - } - else if (PointeeTy->isObjCInterfaceType()) { - if (!EncodingProperty && - isa<TypedefType>(PointeeTy.getTypePtr())) { - // Another historical/compatibility reason. - // We encode the underlying type which comes out as - // {...}; - S += '^'; - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, - NULL); - return; - } - S += '@'; - if (FD || EncodingProperty) { - const ObjCInterfaceType *OIT = - PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType(); - ObjCInterfaceDecl *OI = OIT->getDecl(); - S += '"'; - S += OI->getNameAsCString(); - for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(), - E = OIT->qual_end(); I != E; ++I) { - S += '<'; - S += (*I)->getNameAsString(); - S += '>'; - } - S += '"'; - } - return; - } else if (isObjCClassStructType(PointeeTy)) { - S += '#'; - return; - } else if (isObjCSelType(PointeeTy)) { + if (isObjCSelType(PointeeTy)) { S += ':'; return; } - + if (PointeeTy->isCharType()) { // char pointer types should be encoded as '*' unless it is a // type that has been typedef'd to 'BOOL'. @@ -2765,26 +3039,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '*'; return; } + } else if (const RecordType *RTy = PointeeTy->getAs<RecordType>()) { + // 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... } - S += '^'; getLegacyIntegralTypeEncoding(PointeeTy); - getObjCEncodingForTypeImpl(PointeeTy, S, - false, ExpandPointedToStructures, + getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, NULL); - } else if (const ArrayType *AT = - // Ignore type qualifiers etc. - dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { + return; + } + + if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { if (isa<IncompleteArrayType>(AT)) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; - getObjCEncodingForTypeImpl(AT->getElementType(), S, + getObjCEncodingForTypeImpl(AT->getElementType(), S, false, ExpandStructures, FD); } else { S += '['; - + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) S += llvm::utostr(CAT->getSize().getZExtValue()); else { @@ -2792,14 +3079,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, assert(isa<VariableArrayType>(AT) && "Unknown array type!"); S += '0'; } - - getObjCEncodingForTypeImpl(AT->getElementType(), S, + + getObjCEncodingForTypeImpl(AT->getElementType(), S, false, ExpandStructures, FD); S += ']'; } - } else if (T->getAsFunctionType()) { + return; + } + + if (T->getAs<FunctionType>()) { S += '?'; - } else if (const RecordType *RTy = T->getAsRecordType()) { + return; + } + + if (const RecordType *RTy = T->getAs<RecordType>()) { RecordDecl *RDecl = RTy->getDecl(); S += RDecl->isUnion() ? '(' : '{'; // Anonymous structures print as '?' @@ -2818,30 +3111,39 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += Field->getNameAsString(); S += '"'; } - + // Special case bit-fields. if (Field->isBitField()) { - getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, (*Field)); } else { QualType qt = Field->getType(); getLegacyIntegralTypeEncoding(qt); - getObjCEncodingForTypeImpl(qt, S, false, true, + getObjCEncodingForTypeImpl(qt, S, false, true, FD); } } } S += RDecl->isUnion() ? ')' : '}'; - } else if (T->isEnumeralType()) { + return; + } + + if (T->isEnumeralType()) { if (FD && FD->isBitField()) EncodeBitField(this, S, FD); else S += 'i'; - } else if (T->isBlockPointerType()) { + return; + } + + if (T->isBlockPointerType()) { S += "@?"; // Unlike a pointer-to-function, which is "^?". - } else if (T->isObjCInterfaceType()) { + return; + } + + if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { // @encode(class_name) - ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl(); + ObjCInterfaceDecl *OI = OIT->getDecl(); S += '{'; const IdentifierInfo *II = OI->getIdentifier(); S += II->getName(); @@ -2850,19 +3152,78 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, CollectObjCIvars(OI, RecFields); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { if (RecFields[i]->isBitField()) - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, RecFields[i]); else - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, FD); } S += '}'; + return; } - else - assert(0 && "@encode for type not implemented!"); + + if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) { + if (OPT->isObjCIdType()) { + S += '@'; + return; + } + + if (OPT->isObjCClassType()) { + S += '#'; + return; + } + + if (OPT->isObjCQualifiedIdType()) { + getObjCEncodingForTypeImpl(getObjCIdType(), S, + ExpandPointedToStructures, + ExpandStructures, FD); + if (FD || EncodingProperty) { + // Note that we do extended encoding of protocol qualifer list + // Only when doing ivar or property encoding. + S += '"'; + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + QualType PointeeTy = OPT->getPointeeType(); + if (!EncodingProperty && + isa<TypedefType>(PointeeTy.getTypePtr())) { + // Another historical/compatibility reason. + // We encode the underlying type which comes out as + // {...}; + S += '^'; + getObjCEncodingForTypeImpl(PointeeTy, S, + false, ExpandPointedToStructures, + NULL); + return; + } + + S += '@'; + if (FD || EncodingProperty) { + S += '"'; + S += OPT->getInterfaceDecl()->getNameAsCString(); + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + assert(0 && "@encode for type not implemented!"); } -void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, +void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, std::string& S) const { if (QT & Decl::OBJC_TQ_In) S += 'n'; @@ -2878,46 +3239,26 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, S += 'V'; } -void ASTContext::setBuiltinVaListType(QualType T) -{ +void ASTContext::setBuiltinVaListType(QualType T) { assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); - + BuiltinVaListType = T; } -void ASTContext::setObjCIdType(QualType T) -{ - ObjCIdType = T; - - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_object *id; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - // User error - caller will issue diagnostics. - if (!ptr) - return; - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - // User error - caller will issue diagnostics. - if (!rec) - return; - IdStructType = rec; +void ASTContext::setObjCIdType(QualType T) { + ObjCIdTypedefType = T; } -void ASTContext::setObjCSelType(QualType T) -{ +void ASTContext::setObjCSelType(QualType T) { ObjCSelType = T; - const TypedefType *TT = T->getAsTypedefType(); + const TypedefType *TT = T->getAs<TypedefType>(); if (!TT) return; TypedefDecl *TD = TT->getDecl(); // typedef struct objc_selector *SEL; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>(); if (!ptr) return; const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); @@ -2926,38 +3267,24 @@ void ASTContext::setObjCSelType(QualType T) SelStructType = rec; } -void ASTContext::setObjCProtoType(QualType QT) -{ +void ASTContext::setObjCProtoType(QualType QT) { ObjCProtoType = QT; } -void ASTContext::setObjCClassType(QualType T) -{ - ObjCClassType = T; - - const TypedefType *TT = T->getAsTypedefType(); - if (!TT) - return; - TypedefDecl *TD = TT->getDecl(); - - // typedef struct objc_class *Class; - const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); - assert(ptr && "'Class' incorrectly typed"); - const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); - assert(rec && "'Class' incorrectly typed"); - ClassStructType = rec; +void ASTContext::setObjCClassType(QualType T) { + ObjCClassTypedefType = T; } void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { - assert(ObjCConstantStringType.isNull() && + assert(ObjCConstantStringType.isNull() && "'NSConstantString' type already set!"); - + ObjCConstantStringType = getObjCInterfaceType(Decl); } /// \brief Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) { llvm::FoldingSetNodeID ID; @@ -2974,11 +3301,31 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, return TemplateName(QTN); } +/// \brief Retrieve the template name that represents a qualified +/// template name such as \c std::vector. +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + OverloadedFunctionDecl *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); +} + /// \brief Retrieve the template name that represents a dependent /// template name such as \c MetaFun::template apply. -TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, const IdentifierInfo *Name) { - assert(NNS->isDependent() && "Nested name specifier must be dependent"); + assert((!NNS || NNS->isDependent()) && + "Nested name specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateName::Profile(ID, NNS, Name); @@ -3007,7 +3354,7 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, /// is actually a value of type @c TargetInfo::IntType. QualType ASTContext::getFromTargetType(unsigned Type) const { switch (Type) { - case TargetInfo::NoInt: return QualType(); + case TargetInfo::NoInt: return QualType(); case TargetInfo::SignedShort: return ShortTy; case TargetInfo::UnsignedShort: return UnsignedShortTy; case TargetInfo::SignedInt: return IntTy; @@ -3029,6 +3376,7 @@ QualType ASTContext::getFromTargetType(unsigned Type) const { /// 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. +/// FIXME: Move to Type. /// bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { @@ -3036,68 +3384,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (TD->getAttr<ObjCNSObjectAttr>()) return true; } - return false; -} - -/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer -/// to an object type. This includes "id" and "Class" (two 'special' pointers -/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified -/// ID type). -bool ASTContext::isObjCObjectPointerType(QualType Ty) const { - if (Ty->isObjCQualifiedIdType()) - return true; - - // Blocks are objects. - if (Ty->isBlockPointerType()) - return true; - - // All other object types are pointers. - const PointerType *PT = Ty->getAsPointerType(); - if (PT == 0) - return false; - - // If this a pointer to an interface (e.g. NSString*), it is ok. - if (PT->getPointeeType()->isObjCInterfaceType() || - // If is has NSObject attribute, OK as well. - isObjCNSObjectType(Ty)) - return true; - - // Check to see if this is 'id' or 'Class', both of which are typedefs for - // pointer types. This looks for the typedef specifically, not for the - // underlying type. Iteratively strip off typedefs so that we can handle - // typedefs of typedefs. - while (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { - if (Ty.getUnqualifiedType() == getObjCIdType() || - Ty.getUnqualifiedType() == getObjCClassType()) - return true; - - Ty = TDT->getDecl()->getUnderlyingType(); - } - return false; } /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's /// garbage collection attribute. /// -QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { - QualType::GCAttrTypes GCAttrs = QualType::GCNone; +Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const { + Qualifiers::GC GCAttrs = Qualifiers::GCNone; if (getLangOptions().ObjC1 && getLangOptions().getGCMode() != LangOptions::NonGC) { GCAttrs = Ty.getObjCGCAttr(); // Default behavious under objective-c's gc is for objective-c pointers - // (or pointers to them) be treated as though they were declared + // (or pointers to them) be treated as though they were declared // as __strong. - if (GCAttrs == QualType::GCNone) { - if (isObjCObjectPointerType(Ty)) - GCAttrs = QualType::Strong; + if (GCAttrs == Qualifiers::GCNone) { + if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + GCAttrs = Qualifiers::Strong; else if (Ty->isPointerType()) - return getObjCGCAttrKind(Ty->getAsPointerType()->getPointeeType()); + return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType()); } // Non-pointers have none gc'able attribute regardless of the attribute // set on them. - else if (!Ty->isPointerType() && !isObjCObjectPointerType(Ty)) - return QualType::GCNone; + else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType()) + return Qualifiers::GCNone; } return GCAttrs; } @@ -3106,7 +3416,7 @@ QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { // Type Compatibility Testing //===----------------------------------------------------------------------===// -/// areCompatVectorTypes - Return true if the two specified vector types are +/// areCompatVectorTypes - Return true if the two specified vector types are /// compatible. static bool areCompatVectorTypes(const VectorType *LHS, const VectorType *RHS) { @@ -3115,46 +3425,207 @@ static bool areCompatVectorTypes(const VectorType *LHS, LHS->getNumElements() == RHS->getNumElements(); } +//===----------------------------------------------------------------------===// +// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. +//===----------------------------------------------------------------------===// + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +bool ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) { + if (lProto == rProto) + return true; + for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), + E = rProto->protocol_end(); PI != E; ++PI) + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + return false; +} + +/// 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. + if (lhs->isVoidPointerType() || + lhs->isObjCIdType() || lhs->isObjCClassType()) + return true; + else if (rhs->isVoidPointerType() || + rhs->isObjCIdType() || rhs->isObjCClassType()) + return true; + + if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { + const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + + if (!rhsOPT) return false; + + if (rhsOPT->qual_empty()) { + // If the RHS is a unqualified interface pointer "NSString*", + // 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. + if (!rhsID->ClassImplementsProtocol(*I, true)) + return false; + } + } + // If there are no qualifiers and no interface, we have an 'id'. + return true; + } + // Both the right and left sides have qualifiers. + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->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 = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + // If the RHS is a qualified interface pointer "NSString<P>*", + // 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. + if (rhsID->ClassImplementsProtocol(*I, true)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + + return true; + } + + const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); + assert(rhsQID && "One of the LHS/RHS should be id<x>"); + + if (const ObjCObjectPointerType *lhsOPT = + 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. + if (lhsID->ClassImplementsProtocol(*I, true)) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; + } + // Both the right and left sides have qualifiers. + 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()) + return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false); + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (LHS && RHS) // We have 2 user-defined types. + return canAssignObjCInterfaces(LHS, RHS); + + return false; +} + bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, const ObjCInterfaceType *RHS) { // Verify that the base decls are compatible: the RHS must be a subclass of // the LHS. if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) return false; - + // RHS must have a superset of the protocols in the LHS. If the LHS is not // protocol qualified at all, then we are good. - if (!isa<ObjCQualifiedInterfaceType>(LHS)) + if (LHS->getNumProtocols() == 0) return true; - + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it // isn't a superset. - if (!isa<ObjCQualifiedInterfaceType>(RHS)) + if (RHS->getNumProtocols() == 0) return true; // FIXME: should return false! - - // Finally, we must have two protocol-qualified interfaces. - const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS); - const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS); - - // All LHS protocols must have a presence on the RHS. - assert(LHSP->qual_begin() != LHSP->qual_end() && "Empty LHS protocol list?"); - - for (ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(), - LHSPE = LHSP->qual_end(); + + for (ObjCInterfaceType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); LHSPI != LHSPE; LHSPI++) { bool RHSImplementsProtocol = false; // If the RHS doesn't implement the protocol on the left, the types // are incompatible. - for (ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(), - RHSPE = RHSP->qual_end(); - !RHSImplementsProtocol && (RHSPI != RHSPE); RHSPI++) { - if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) + for (ObjCInterfaceType::qual_iterator RHSPI = RHS->qual_begin(), + RHSPE = RHS->qual_end(); + RHSPI != RHSPE; RHSPI++) { + if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) { RHSImplementsProtocol = true; + break; + } } // FIXME: For better diagnostics, consider passing back the protocol name. if (!RHSImplementsProtocol) @@ -3166,38 +3637,27 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { // get the "pointed to" types - const PointerType *LHSPT = LHS->getAsPointerType(); - const PointerType *RHSPT = RHS->getAsPointerType(); - - if (!LHSPT || !RHSPT) - return false; - - QualType lhptee = LHSPT->getPointeeType(); - QualType rhptee = RHSPT->getPointeeType(); - const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); - // ID acts sort of like void* for ObjC interfaces - if (LHSIface && isObjCIdStructType(rhptee)) - return true; - if (RHSIface && isObjCIdStructType(lhptee)) - return true; - if (!LHSIface || !RHSIface) + const ObjCObjectPointerType *LHSOPT = LHS->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHS->getAs<ObjCObjectPointerType>(); + + if (!LHSOPT || !RHSOPT) return false; - return canAssignObjCInterfaces(LHSIface, RHSIface) || - canAssignObjCInterfaces(RHSIface, LHSIface); + + return canAssignObjCInterfaces(LHSOPT, RHSOPT) || + canAssignObjCInterfaces(RHSOPT, LHSOPT); } -/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, +/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, /// both shall have the identically qualified version of a compatible type. -/// C99 6.2.7p1: Two types have compatible types if their types are the +/// C99 6.2.7p1: Two types have compatible types if their types are the /// same. See 6.7.[2,3,5] for additional rules. bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { - const FunctionType *lbase = lhs->getAsFunctionType(); - const FunctionType *rbase = rhs->getAsFunctionType(); + const FunctionType *lbase = lhs->getAs<FunctionType>(); + const FunctionType *rbase = rhs->getAs<FunctionType>(); const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase); bool allLTypes = true; @@ -3210,6 +3670,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allLTypes = false; if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) allRTypes = false; + // FIXME: double check this + bool NoReturn = lbase->getNoReturnAttr() || rbase->getNoReturnAttr(); + if (NoReturn != lbase->getNoReturnAttr()) + allLTypes = false; + if (NoReturn != rbase->getNoReturnAttr()) + allRTypes = false; if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -3244,7 +3710,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allLTypes) return lhs; if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), - lproto->isVariadic(), lproto->getTypeQuals()); + lproto->isVariadic(), lproto->getTypeQuals(), + NoReturn); } if (lproto) allRTypes = false; @@ -3270,13 +3737,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allLTypes) return lhs; if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), - proto->getNumArgs(), lproto->isVariadic(), - lproto->getTypeQuals()); + proto->getNumArgs(), proto->isVariadic(), + proto->getTypeQuals(), NoReturn); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType); + return getFunctionNoProtoType(retType, NoReturn); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { @@ -3289,9 +3756,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // enough that they should be handled separately. // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really* // shouldn't be going through here! - if (const ReferenceType *RT = LHS->getAsReferenceType()) + if (const ReferenceType *RT = LHS->getAs<ReferenceType>()) LHS = RT->getPointeeType(); - if (const ReferenceType *RT = RHS->getAsReferenceType()) + if (const ReferenceType *RT = RHS->getAs<ReferenceType>()) RHS = RT->getPointeeType(); QualType LHSCan = getCanonicalType(LHS), @@ -3301,11 +3768,38 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSCan == RHSCan) return LHS; - // If the qualifiers are different, the types aren't compatible - // Note that we handle extended qualifiers later, in the - // case for ExtQualType. - if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers()) + // 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); + } return QualType(); + } + + // Okay, qualifiers are equal. Type::TypeClass LHSClass = LHSCan->getTypeClass(); Type::TypeClass RHSClass = RHSCan->getTypeClass(); @@ -3315,120 +3809,25 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; - // Strip off objc_gc attributes off the top level so they can be merged. - // This is a complete mess, but the attribute itself doesn't make much sense. - if (RHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCLHSAttr = LHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCLHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCLHSAttr != GCAttr && - LHSCan->isPointerType() && !isObjCObjectPointerType(LHSCan) && - !isObjCIdStructType(LHSCan->getAsPointerType()->getPointeeType()))) - return QualType(); - - RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(), - RHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - if (LHSClass == Type::ExtQual) { - QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr(); - if (GCAttr != QualType::GCNone) { - QualType::GCAttrTypes GCRHSAttr = RHSCan.getObjCGCAttr(); - // __weak attribute must appear on both declarations. __strong - // __strong attribue is redundant if other decl is an objective-c - // object pointer (or decorated with __strong attribute); otherwise - // issue error. - if ((GCAttr == QualType::Weak && GCRHSAttr != GCAttr) || - (GCAttr == QualType::Strong && GCRHSAttr != GCAttr && - RHSCan->isPointerType() && !isObjCObjectPointerType(RHSCan) && - !isObjCIdStructType(RHSCan->getAsPointerType()->getPointeeType()))) - return QualType(); - - LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(), - LHS.getCVRQualifiers()); - QualType Result = mergeTypes(LHS, RHS); - if (!Result.isNull()) { - if (Result.getObjCGCAttr() == QualType::GCNone) - Result = getObjCGCQualType(Result, GCAttr); - else if (Result.getObjCGCAttr() != GCAttr) - Result = QualType(); - } - return Result; - } - } - // Same as above for arrays if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; - + // Canonicalize ExtVector -> Vector. if (LHSClass == Type::ExtVector) LHSClass = Type::Vector; if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; - - // Consider qualified interfaces and interfaces the same. - if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface; - if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface; // If the canonical type classes don't match. if (LHSClass != RHSClass) { - const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); - - // 'id' and 'Class' act sort of like void* for ObjC interfaces - if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS))) - return LHS; - if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS))) - return RHS; - - // ID is compatible with all qualified id types. - if (LHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = RHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return LHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return LHS; - } - } - if (RHS->isObjCQualifiedIdType()) { - if (const PointerType *PT = LHS->getAsPointerType()) { - QualType pType = PT->getPointeeType(); - if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) - return RHS; - // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). - // Unfortunately, this API is part of Sema (which we don't have access - // to. Need to refactor. The following check is insufficient, since we - // need to make sure the class implements the protocol. - if (pType->isObjCInterfaceType()) - return RHS; - } - } // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, - // a signed integer type, or an unsigned integer type. - if (const EnumType* ETy = LHS->getAsEnumType()) { + // a signed integer type, or an unsigned integer type. + if (const EnumType* ETy = LHS->getAs<EnumType>()) { if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) return RHS; } - if (const EnumType* ETy = RHS->getAsEnumType()) { + if (const EnumType* ETy = RHS->getAs<EnumType>()) { if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType()) return LHS; } @@ -3456,15 +3855,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { case Type::VariableArray: case Type::FunctionProto: case Type::ExtVector: - case Type::ObjCQualifiedInterface: assert(false && "Types are eliminated above"); return QualType(); case Type::Pointer: { // Merge two pointer types, while trying to preserve typedef info - QualType LHSPointee = LHS->getAsPointerType()->getPointeeType(); - QualType RHSPointee = RHS->getAsPointerType()->getPointeeType(); + QualType LHSPointee = LHS->getAs<PointerType>()->getPointeeType(); + QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType(); QualType ResultType = mergeTypes(LHSPointee, RHSPointee); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) @@ -3476,8 +3874,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { case Type::BlockPointer: { // Merge two block pointer types, while trying to preserve typedef info - QualType LHSPointee = LHS->getAsBlockPointerType()->getPointeeType(); - QualType RHSPointee = RHS->getAsBlockPointerType()->getPointeeType(); + QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType(); + QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType(); QualType ResultType = mergeTypes(LHSPointee, RHSPointee); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) @@ -3525,15 +3923,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { } if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS; - return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(),0); + return getIncompleteArrayType(ResultType, + ArrayType::ArraySizeModifier(), 0); } case Type::FunctionNoProto: return mergeFunctionTypes(LHS, RHS); case Type::Record: case Type::Enum: - // FIXME: Why are these compatible? - if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS; - if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS; return QualType(); case Type::Builtin: // Only exactly equal builtin types are compatible, which is tested above. @@ -3543,56 +3939,31 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); case Type::Vector: // FIXME: The merged type should be an ExtVector! - if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType())) + if (areCompatVectorTypes(LHS->getAs<VectorType>(), RHS->getAs<VectorType>())) return LHS; return QualType(); case Type::ObjCInterface: { // Check if the interfaces are assignment compatible. // FIXME: This should be type compatibility, e.g. whether // "LHS x; RHS x;" at global scope is legal. - const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); - const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); + const ObjCInterfaceType* LHSIface = LHS->getAs<ObjCInterfaceType>(); + const ObjCInterfaceType* RHSIface = RHS->getAs<ObjCInterfaceType>(); if (LHSIface && RHSIface && canAssignObjCInterfaces(LHSIface, RHSIface)) return LHS; return QualType(); } - case Type::ObjCObjectPointer: - // FIXME: finish - // Distinct qualified id's are not compatible. + case Type::ObjCObjectPointer: { + if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(), + RHS->getAs<ObjCObjectPointerType>())) + return LHS; + return QualType(); + } case Type::FixedWidthInt: // Distinct fixed-width integers are not compatible. return QualType(); - case Type::ExtQual: - // FIXME: ExtQual types can be compatible even if they're not - // identical! - return QualType(); - // First attempt at an implementation, but I'm not really sure it's - // right... -#if 0 - ExtQualType* LQual = cast<ExtQualType>(LHSCan); - ExtQualType* RQual = cast<ExtQualType>(RHSCan); - if (LQual->getAddressSpace() != RQual->getAddressSpace() || - LQual->getObjCGCAttr() != RQual->getObjCGCAttr()) - return QualType(); - QualType LHSBase, RHSBase, ResultType, ResCanUnqual; - LHSBase = QualType(LQual->getBaseType(), 0); - RHSBase = QualType(RQual->getBaseType(), 0); - ResultType = mergeTypes(LHSBase, RHSBase); - if (ResultType.isNull()) return QualType(); - ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType(); - if (LHSCan.getUnqualifiedType() == ResCanUnqual) - return LHS; - if (RHSCan.getUnqualifiedType() == ResCanUnqual) - return RHS; - ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace()); - ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr()); - ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers()); - return ResultType; -#endif - case Type::TemplateSpecialization: assert(false && "Dependent types have no size"); break; @@ -3617,9 +3988,9 @@ unsigned ASTContext::getIntWidth(QualType T) { QualType ASTContext::getCorrespondingUnsignedType(QualType T) { assert(T->isSignedIntegerType() && "Unexpected type"); - if (const EnumType* ETy = T->getAsEnumType()) + if (const EnumType* ETy = T->getAs<EnumType>()) T = ETy->getDecl()->getIntegerType(); - const BuiltinType* BTy = T->getAsBuiltinType(); + const BuiltinType* BTy = T->getAs<BuiltinType>(); assert (BTy && "Unexpected signed integer type"); switch (BTy->getKind()) { case BuiltinType::Char_S: @@ -3652,18 +4023,18 @@ void ExternalASTSource::PrintStats() { } /// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the /// pointer over the consumed characters. This returns the resultant type. -static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, ASTContext::GetBuiltinTypeError &Error, bool AllowTypeModifiers = true) { // Modifiers. int HowLong = 0; bool Signed = false, Unsigned = false; - + // Read the modifiers first. bool Done = false; while (!Done) { switch (*Str++) { - default: Done = true; --Str; break; + default: Done = true; --Str; break; case 'S': assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); assert(!Signed && "Can't use 'S' modifier multiple times!"); @@ -3682,7 +4053,7 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, } QualType Type; - + // Read the base type. switch (*Str++) { default: assert(0 && "Unknown builtin type letter!"); @@ -3764,34 +4135,43 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, break; case 'V': { char *End; - unsigned NumElements = strtoul(Str, &End, 10); assert(End != Str && "Missing vector size"); - + Str = End; - + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); Type = Context.getVectorType(ElementType, NumElements); break; } - case 'P': { - IdentifierInfo *II = &Context.Idents.get("FILE"); - DeclContext::lookup_result Lookup - = Context.getTranslationUnitDecl()->lookup(II); - if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) { - Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first)); - break; + case 'X': { + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); + Type = Context.getComplexType(ElementType); + break; + } + case 'P': + Type = Context.getFILEType(); + if (Type.isNull()) { + Error = ASTContext::GE_Missing_stdio; + return QualType(); } - else { - Error = ASTContext::GE_Missing_FILE; + break; + case 'J': + if (Signed) + Type = Context.getsigjmp_bufType(); + else + Type = Context.getjmp_bufType(); + + if (Type.isNull()) { + Error = ASTContext::GE_Missing_setjmp; return QualType(); } + break; } - } - + if (!AllowTypeModifiers) return Type; - + Done = false; while (!Done) { switch (*Str++) { @@ -3804,11 +4184,11 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, break; // FIXME: There's no way to have a built-in with an rvalue ref arg. case 'C': - Type = Type.getQualifiedType(QualType::Const); + Type = Type.withConst(); break; } } - + return Type; } @@ -3816,9 +4196,9 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, QualType ASTContext::GetBuiltinType(unsigned id, GetBuiltinTypeError &Error) { const char *TypeStr = BuiltinInfo.GetTypeString(id); - + llvm::SmallVector<QualType, 8> ArgTypes; - + Error = GE_None; QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error); if (Error != GE_None) @@ -3831,7 +4211,7 @@ QualType ASTContext::GetBuiltinType(unsigned id, // Do array -> pointer decay. The builtin should use the decayed type. if (Ty->isArrayType()) Ty = getArrayDecayedType(Ty); - + ArgTypes.push_back(Ty); } @@ -3844,3 +4224,143 @@ QualType ASTContext::GetBuiltinType(unsigned id, return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), TypeStr[0] == '.', 0); } + +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; + + // 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; + + // At this point, we have two different arithmetic types. + + // 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. + if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { + // convert the rhs to the lhs complex type. + return lhs; + } + if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { + // convert the lhs to the rhs complex type. + return rhs; + } + // This handles complex/complex, complex/float, or float/complex. + // 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. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + int result = getFloatingTypeOrder(lhs, rhs); + + if (result > 0) { // The left side is bigger, convert rhs. + rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs); + } else if (result < 0) { // The right side is bigger, convert lhs. + lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs); + } + // 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; + } + if (lhs->isComplexIntegerType()) { + // 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) { + if (getIntegerTypeOrder(lhsComplexInt->getElementType(), + 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; +} diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index ac4cbb2d296e..20e1150b22c2 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -4,28 +4,31 @@ add_clang_library(clangAST APValue.cpp ASTConsumer.cpp ASTContext.cpp - CFG.cpp - DeclarationName.cpp - DeclBase.cpp + CXXInheritance.cpp Decl.cpp + DeclBase.cpp DeclCXX.cpp DeclGroup.cpp DeclObjC.cpp DeclPrinter.cpp DeclTemplate.cpp - ExprConstant.cpp + DeclarationName.cpp Expr.cpp ExprCXX.cpp + ExprConstant.cpp InheritViz.cpp NestedNameSpecifier.cpp ParentMap.cpp + RecordLayoutBuilder.cpp Stmt.cpp StmtDumper.cpp StmtIterator.cpp StmtPrinter.cpp + StmtProfile.cpp StmtViz.cpp TemplateName.cpp Type.cpp + TypeLoc.cpp ) add_dependencies(clangAST ClangDiagnosticAST) diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp new file mode 100644 index 000000000000..4a46eab2e603 --- /dev/null +++ b/lib/AST/CXXInheritance.cpp @@ -0,0 +1,244 @@ +//===------ CXXInheritance.cpp - C++ Inheritance ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" +#include <algorithm> +#include <set> + +using namespace clang; + +/// \brief Computes the set of declarations referenced by these base +/// paths. +void CXXBasePaths::ComputeDeclsFound() { + assert(NumDeclsFound == 0 && !DeclsFound && + "Already computed the set of declarations"); + + std::set<NamedDecl *> Decls; + for (CXXBasePaths::paths_iterator Path = begin(), PathEnd = end(); + Path != PathEnd; ++Path) + Decls.insert(*Path->Decls.first); + + NumDeclsFound = Decls.size(); + DeclsFound = new NamedDecl * [NumDeclsFound]; + std::copy(Decls.begin(), Decls.end(), DeclsFound); +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound; +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound + NumDeclsFound; +} + +/// isAmbiguous - Determines whether the set of paths provided is +/// ambiguous, i.e., there are two or more paths that refer to +/// different base class subobjects of the same type. BaseType must be +/// an unqualified, canonical class type. +bool CXXBasePaths::isAmbiguous(QualType BaseType) { + assert(BaseType->isCanonical() && "Base type must be the canonical type"); + assert(BaseType.hasQualifiers() == 0 && "Base type must be unqualified"); + std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; + return Subobjects.second + (Subobjects.first? 1 : 0) > 1; +} + +/// clear - Clear out all prior path information. +void CXXBasePaths::clear() { + Paths.clear(); + ClassSubobjects.clear(); + ScratchPath.clear(); + DetectedVirtual = 0; +} + +/// @brief Swaps the contents of this CXXBasePaths structure with the +/// contents of Other. +void CXXBasePaths::swap(CXXBasePaths &Other) { + std::swap(Origin, Other.Origin); + Paths.swap(Other.Paths); + ClassSubobjects.swap(Other.ClassSubobjects); + std::swap(FindAmbiguities, Other.FindAmbiguities); + std::swap(RecordPaths, Other.RecordPaths); + std::swap(DetectVirtual, Other.DetectVirtual); + std::swap(DetectedVirtual, Other.DetectedVirtual); +} + +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) { + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + return isDerivedFrom(Base, Paths); +} + +bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) { + if (getCanonicalDecl() == Base->getCanonicalDecl()) + return false; + + Paths.setOrigin(this); + return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); +} + +bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, + void *UserData, + CXXBasePaths &Paths) { + bool FoundPath = false; + + ASTContext &Context = getASTContext(); + for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); + BaseSpec != BaseSpecEnd; ++BaseSpec) { + // Find the record of the base class subobjects for this type. + QualType BaseType = Context.getCanonicalType(BaseSpec->getType()); + BaseType = BaseType.getUnqualifiedType(); + + // C++ [temp.dep]p3: + // In the definition of a class template or a member of a class template, + // if a base class of the class template depends on a template-parameter, + // the base class scope is not examined during unqualified name lookup + // either at the point of definition of the class template or member or + // during an instantiation of the class tem- plate or member. + if (BaseType->isDependentType()) + continue; + + // Determine whether we need to visit this base class at all, + // updating the count of subobjects appropriately. + std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType]; + bool VisitBase = true; + bool SetVirtual = false; + if (BaseSpec->isVirtual()) { + VisitBase = !Subobjects.first; + Subobjects.first = true; + if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) { + // If this is the first virtual we find, remember it. If it turns out + // there is no base path here, we'll reset it later. + Paths.DetectedVirtual = BaseType->getAs<RecordType>(); + SetVirtual = true; + } + } else + ++Subobjects.second; + + if (Paths.isRecordingPaths()) { + // Add this base specifier to the current path. + CXXBasePathElement Element; + Element.Base = &*BaseSpec; + Element.Class = this; + if (BaseSpec->isVirtual()) + Element.SubobjectNumber = 0; + else + Element.SubobjectNumber = Subobjects.second; + Paths.ScratchPath.push_back(Element); + } + + if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { + // We've found a path that terminates that this base. + FoundPath = true; + if (Paths.isRecordingPaths()) { + // We have a path. Make a copy of it before moving on. + Paths.Paths.push_back(Paths.ScratchPath); + } else if (!Paths.isFindingAmbiguities()) { + // We found a path and we don't care about ambiguities; + // return immediately. + return FoundPath; + } + } else if (VisitBase) { + CXXRecordDecl *BaseRecord + = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>() + ->getDecl()); + if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) { + // C++ [class.member.lookup]p2: + // A member name f in one sub-object B hides a member name f in + // a sub-object A if A is a base class sub-object of B. Any + // declarations that are so hidden are eliminated from + // consideration. + + // There is a path to a base class that meets the criteria. If we're + // not collecting paths or finding ambiguities, we're done. + FoundPath = true; + if (!Paths.isFindingAmbiguities()) + return FoundPath; + } + } + + // Pop this base specifier off the current path (if we're + // collecting paths). + if (Paths.isRecordingPaths()) + Paths.ScratchPath.pop_back(); + // If we set a virtual earlier, and this isn't a path, forget it again. + if (SetVirtual && !FoundPath) { + Paths.DetectedVirtual = 0; + } + } + + return FoundPath; +} + +bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *BaseRecord) { + assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && + "User data for FindBaseClass is not canonical!"); + return Specifier->getType()->getAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; +} + +bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} + +bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS)) + return true; + } + + return false; +} + +bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + // FIXME: Refactor the "is it a nested-name-specifier?" check + if (isa<TypedefDecl>(*Path.Decls.first) || + (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3d02150b65bf..429729ea3b0e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -16,11 +16,14 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/ErrorHandling.h" #include <vector> using namespace clang; @@ -34,11 +37,15 @@ void Attr::Destroy(ASTContext &C) { C.Deallocate((void*)this); } +/// \brief Return the TypeLoc wrapper for the type source info. +TypeLoc DeclaratorInfo::getTypeLoc() const { + return TypeLoc(Ty, (void*)(this + 1)); +} //===----------------------------------------------------------------------===// // Decl Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// - + TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C) TranslationUnitDecl(C); @@ -52,7 +59,7 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, void NamespaceDecl::Destroy(ASTContext& C) { // NamespaceDecl uses "NextDeclarator" to chain namespace declarations // together. They are all top-level Decls. - + this->~NamespaceDecl(); C.Deallocate((void *)this); } @@ -68,9 +75,9 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { case VarDecl::None: break; case VarDecl::Auto: return "auto"; break; case VarDecl::Extern: return "extern"; break; - case VarDecl::PrivateExtern: return "__private_extern__"; break; + case VarDecl::PrivateExtern: return "__private_extern__"; break; case VarDecl::Register: return "register"; break; - case VarDecl::Static: return "static"; break; + case VarDecl::Static: return "static"; break; } assert(0 && "Invalid storage class"); @@ -79,34 +86,45 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, StorageClass S, - Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg); + QualType T, DeclaratorInfo *DInfo, + StorageClass S, Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, DInfo, S, DefArg); } QualType ParmVarDecl::getOriginalType() const { - if (const OriginalParmVarDecl *PVD = + if (const OriginalParmVarDecl *PVD = dyn_cast<OriginalParmVarDecl>(this)) return PVD->OriginalType; return getType(); } -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (const Expr *E = getUninstantiatedDefaultArg()) + return E->getSourceRange(); + + return SourceRange(); +} - Init = I; +void VarDecl::setInit(ASTContext &C, Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); } -bool VarDecl::isExternC(ASTContext &Context) const { + Init = I; +} + +bool VarDecl::isExternC() const { + ASTContext &Context = getASTContext(); if (!Context.getLangOptions().CPlusPlus) - return (getDeclContext()->isTranslationUnit() && + return (getDeclContext()->isTranslationUnit() && getStorageClass() != Static) || (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) @@ -125,20 +143,19 @@ bool VarDecl::isExternC(ASTContext &Context) const { OriginalParmVarDecl *OriginalParmVarDecl::Create( ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, QualType OT, StorageClass S, - Expr *DefArg) { - return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg); + QualType T, DeclaratorInfo *DInfo, + QualType OT, StorageClass S, Expr *DefArg) { + return new (C) OriginalParmVarDecl(DC, L, Id, T, DInfo, OT, S, DefArg); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - DeclarationName N, QualType T, - StorageClass S, bool isInline, - bool hasWrittenPrototype, - SourceLocation TypeSpecStartLoc) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline, - TypeSpecStartLoc); + SourceLocation L, + DeclarationName N, QualType T, + DeclaratorInfo *DInfo, + StorageClass S, bool isInline, + bool hasWrittenPrototype) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, DInfo, S, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -148,16 +165,16 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { } FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, Expr *BW, - bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable); + IdentifierInfo *Id, QualType T, + DeclaratorInfo *DInfo, Expr *BW, bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, DInfo, BW, Mutable); } bool FieldDecl::isAnonymousStructOrUnion() const { if (!isImplicit() || getDeclName()) return false; - - if (const RecordType *Record = getType()->getAsRecordType()) + + if (const RecordType *Record = getType()->getAs<RecordType>()) return Record->getDecl()->isAnonymousStructOrUnion(); return false; @@ -182,9 +199,9 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, } EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, + IdentifierInfo *Id, SourceLocation TKL, EnumDecl *PrevDecl) { - EnumDecl *Enum = new (C) EnumDecl(DC, L, Id); + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL); C.getTypeDeclType(Enum, PrevDecl); return Enum; } @@ -210,6 +227,10 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, //===----------------------------------------------------------------------===// std::string NamedDecl::getQualifiedNameAsString() const { + return getQualifiedNameAsString(getASTContext().getLangOptions()); +} + +std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { std::vector<std::string> Names; std::string QualName; const DeclContext *Ctx = getDeclContext(); @@ -223,15 +244,14 @@ std::string NamedDecl::getQualifiedNameAsString() const { // scope class/struct/union. How do we handle this case? break; - if (const ClassTemplateSpecializationDecl *Spec + if (const ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - PrintingPolicy Policy(getASTContext().getLangOptions()); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), - Policy); + P); Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) Names.push_back(ND->getNameAsString()); @@ -253,7 +273,6 @@ std::string NamedDecl::getQualifiedNameAsString() const { return QualName; } - bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); @@ -263,7 +282,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() == cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace(); } - + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) // For function declarations, we keep track of redeclarations. return FD->getPreviousDeclaration() == OldD; @@ -275,11 +294,14 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { = dyn_cast<FunctionTemplateDecl>(OldD)) return FunctionTemplate->getTemplatedDecl() ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl()); - + // For method declarations, we keep track of redeclarations. if (isa<ObjCMethodDecl>(this)) return false; - + + if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD)) + return true; + // For non-function declarations, if the declarations are of the // same kind then this must be a redeclaration, or semantic analysis // would not have given us the new declaration. @@ -310,13 +332,23 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { } //===----------------------------------------------------------------------===// +// DeclaratorDecl Implementation +//===----------------------------------------------------------------------===// + +SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { + if (DeclInfo) + return DeclInfo->getTypeLoc().getTypeSpecRange().getBegin(); + return SourceLocation(); +} + +//===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, StorageClass S, - SourceLocation TypeSpecStartLoc) { - return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc); + IdentifierInfo *Id, QualType T, DeclaratorInfo *DInfo, + StorageClass S) { + return new (C) VarDecl(Var, DC, L, Id, T, DInfo, S); } void VarDecl::Destroy(ASTContext& C) { @@ -341,6 +373,31 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(getLocation(), getLocation()); } +VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return cast<VarDecl>(MSI->getInstantiatedFrom()); + + return 0; +} + +TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() { + if (MemberSpecializationInfo *MSI + = getASTContext().getInstantiatedFromStaticDataMember(this)) + return MSI->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() { + return getASTContext().getInstantiatedFromStaticDataMember(this); +} + +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); + assert(MSI && "Not an instantiated static data member?"); + MSI->setTemplateSpecializationKind(TSK); +} + bool VarDecl::isTentativeDefinition(ASTContext &Context) const { if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) return false; @@ -351,11 +408,19 @@ bool VarDecl::isTentativeDefinition(ASTContext &Context) const { } const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { - Def = this; - while (Def && !Def->getInit()) - Def = Def->getPreviousDeclaration(); + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; + + if (I != E) { + Def = *I; + return I->getInit(); + } + return 0; +} - return Def? Def->getInit() : 0; +VarDecl *VarDecl::getCanonicalDecl() { + return getFirstDeclaration(); } //===----------------------------------------------------------------------===// @@ -369,27 +434,39 @@ void FunctionDecl::Destroy(ASTContext& C) { for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) (*I)->Destroy(C); + FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); + if (FTSInfo) + C.Deallocate(FTSInfo); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); + if (MSInfo) + C.Deallocate(MSInfo); + C.Deallocate(ParamInfo); Decl::Destroy(C); } - -Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { - for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { - if (FD->Body) { - Definition = FD; - return FD->Body.get(getASTContext().getExternalSource()); - } - } - - return 0; +void FunctionDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); + if (TemplateArgs) + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs->getFlatArgumentList(), + TemplateArgs->flat_size(), + Policy); + } -Stmt *FunctionDecl::getBodyIfAvailable() const { - for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { - if (FD->Body && !FD->Body.isOffset()) { - return FD->Body.get(0); +Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body) { + Definition = *I; + return I->Body.get(getASTContext().getExternalSource()); } } @@ -403,21 +480,24 @@ void FunctionDecl::setBody(Stmt *B) { } bool FunctionDecl::isMain() const { - return getDeclContext()->getLookupContext()->isTranslationUnit() && + ASTContext &Context = getASTContext(); + return !Context.getLangOptions().Freestanding && + getDeclContext()->getLookupContext()->isTranslationUnit() && getIdentifier() && getIdentifier()->isStr("main"); } -bool FunctionDecl::isExternC(ASTContext &Context) const { +bool FunctionDecl::isExternC() const { + ASTContext &Context = getASTContext(); // In C, any non-static, non-overloadable function has external // linkage. if (!Context.getLangOptions().CPlusPlus) return getStorageClass() != Static && !getAttr<OverloadableAttr>(); - for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static && + return getStorageClass() != Static && !getAttr<OverloadableAttr>(); break; @@ -434,7 +514,7 @@ bool FunctionDecl::isGlobal() const { if (getStorageClass() == Static) return false; - for (const DeclContext *DC = getDeclContext(); + for (const DeclContext *DC = getDeclContext(); DC->isNamespace(); DC = DC->getParent()) { if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) { @@ -454,9 +534,10 @@ bool FunctionDecl::isGlobal() const { /// declared at translation scope or within an extern "C" block and /// its name matches with the name of a builtin. The returned value /// will be 0 for functions that do not correspond to a builtin, a -/// value of type \c Builtin::ID if in the target-independent range +/// value of type \c Builtin::ID if in the target-independent range /// \c [1,Builtin::First), or a target-specific builtin value. -unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { +unsigned FunctionDecl::getBuiltinID() const { + ASTContext &Context = getASTContext(); if (!getIdentifier() || !getIdentifier()->getBuiltinID()) return 0; @@ -481,7 +562,7 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { // If the function is in an extern "C" linkage specification and is // not marked "overloadable", it's the real function. if (isa<LinkageSpecDecl>(getDeclContext()) && - cast<LinkageSpecDecl>(getDeclContext())->getLanguage() + cast<LinkageSpecDecl>(getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c && !getAttr<OverloadableAttr>()) return BuiltinID; @@ -495,18 +576,18 @@ unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { /// based on its FunctionType. This is the length of the PararmInfo array /// after it has been created. unsigned FunctionDecl::getNumParams() const { - const FunctionType *FT = getType()->getAsFunctionType(); + const FunctionType *FT = getType()->getAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) return 0; return cast<FunctionProtoType>(FT)->getNumArgs(); - + } void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NumParams) { assert(ParamInfo == 0 && "Already has param info!"); assert(NumParams == getNumParams() && "Parameter count mismatch!"); - + // Zero params -> null pointer. if (NumParams) { void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); @@ -533,42 +614,87 @@ unsigned FunctionDecl::getMinRequiredArguments() const { return NumRequiredArgs; } -bool FunctionDecl::hasActiveGNUInlineAttribute(ASTContext &Context) const { - if (!isInline() || !hasAttr<GNUInlineAttr>()) +/// \brief For an inline function definition in C, determine whether the +/// definition will be externally visible. +/// +/// Inline function definitions are always available for inlining optimizations. +/// However, depending on the language dialect, declaration specifiers, and +/// attributes, the definition of an inline function may or may not be +/// "externally" visible to other translation units in the program. +/// +/// In C99, inline definitions are not externally visible by default. However, +/// if even one of the globa-scope declarations is marked "extern inline", the +/// inline definition becomes externally visible (C99 6.7.4p6). +/// +/// In GNU89 mode, or if the gnu_inline attribute is attached to the function +/// definition, we use the GNU semantics for inline, which are nearly the +/// opposite of C99 semantics. In particular, "inline" by itself will create +/// an externally visible symbol, but "extern inline" will not create an +/// externally visible symbol. +bool FunctionDecl::isInlineDefinitionExternallyVisible() const { + assert(isThisDeclarationADefinition() && "Must have the function definition"); + assert(isInline() && "Function must be inline"); + + if (!getASTContext().getLangOptions().C99 || hasAttr<GNUInlineAttr>()) { + // GNU inline semantics. Based on a number of examples, we came up with the + // following heuristic: if the "inline" keyword is present on a + // declaration of the function but "extern" is not present on that + // declaration, then the symbol is externally visible. Otherwise, the GNU + // "extern inline" semantics applies and the symbol is not externally + // visible. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + if (Redecl->isInline() && Redecl->getStorageClass() != Extern) + return true; + } + + // GNU "extern inline" semantics; no externally visible symbol. return false; - - for (const FunctionDecl *FD = getPreviousDeclaration(); FD; - FD = FD->getPreviousDeclaration()) { - if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>()) - return false; } - - return true; -} - -bool FunctionDecl::isExternGNUInline(ASTContext &Context) const { - if (!hasActiveGNUInlineAttribute(Context)) - return false; - - for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration()) - if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>()) - return true; - + + // C99 6.7.4p6: + // [...] If all of the file scope declarations for a function in a + // translation unit include the inline function specifier without extern, + // then the definition in that translation unit is an inline definition. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + // Only consider file-scope declarations in this test. + if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) + continue; + + if (!Redecl->isInline() || Redecl->getStorageClass() == Extern) + return true; // Not an inline definition + } + + // C99 6.7.4p6: + // An inline definition does not provide an external definition for the + // function, and does not forbid an external definition in another + // translation unit. return false; } -void +void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { - PreviousDeclaration = PrevDecl; - + redeclarable_base::setPreviousDeclaration(PrevDecl); + if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { - FunctionTemplateDecl *PrevFunTmpl + FunctionTemplateDecl *PrevFunTmpl = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); FunTmpl->setPreviousDeclaration(PrevFunTmpl); } } +const FunctionDecl *FunctionDecl::getCanonicalDecl() const { + return getFirstDeclaration(); +} + +FunctionDecl *FunctionDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + /// getOverloadedOperator - Which C++ overloaded operator this /// function represents, if any. OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { @@ -578,8 +704,29 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { return OO_None; } +FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) + return cast<FunctionDecl>(Info->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { + return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); +} + +void +FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); + MemberSpecializationInfo *Info + = new (getASTContext()) MemberSpecializationInfo(FD, TSK); + TemplateOrSpecialization = Info; +} + FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { - if (FunctionTemplateSpecializationInfo *Info + if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast<FunctionTemplateSpecializationInfo*>()) { return Info->Template.getPointer(); @@ -589,79 +736,151 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { - if (FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization - .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { return Info->TemplateArguments; } return 0; } -void +void FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateDecl *Template, const TemplateArgumentList *TemplateArgs, - void *InsertPos) { - FunctionTemplateSpecializationInfo *Info + void *InsertPos, + TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Must specify the type of function template specialization"); + FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); if (!Info) Info = new (Context) FunctionTemplateSpecializationInfo; - + Info->Function = this; Info->Template.setPointer(Template); - Info->Template.setInt(0); // Implicit instantiation, unless told otherwise + Info->Template.setInt(TSK - 1); Info->TemplateArguments = TemplateArgs; TemplateOrSpecialization = Info; - + // Insert this function template specialization into the set of known - // function template specialiations. - Template->getSpecializations().InsertNode(Info, InsertPos); + // function template specializations. + if (InsertPos) + Template->getSpecializations().InsertNode(Info, InsertPos); + else { + // Try to insert the new node. If there is an existing node, remove it + // first. + FunctionTemplateSpecializationInfo *Existing + = Template->getSpecializations().GetOrInsertNode(Info); + if (Existing) { + Template->getSpecializations().RemoveNode(Existing); + Template->getSpecializations().GetOrInsertNode(Info); + } + } } -bool FunctionDecl::isExplicitSpecialization() const { - // FIXME: check this property for explicit specializations of member - // functions of class templates. - FunctionTemplateSpecializationInfo *Info +TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { + // For a function template specialization, query the specialization + // information object. + FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (!Info) - return false; + if (FTSInfo) + return FTSInfo->getTemplateSpecializationKind(); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); + if (MSInfo) + return MSInfo->getTemplateSpecializationKind(); - return Info->isExplicitSpecialization(); + return TSK_Undeclared; } -void FunctionDecl::setExplicitSpecialization(bool ES) { - // FIXME: set this property for explicit specializations of member functions - // of class templates. - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (Info) - Info->setExplicitSpecialization(ES); +void +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + FTSInfo->setTemplateSpecializationKind(TSK); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + MSInfo->setTemplateSpecializationKind(TSK); + else + assert(false && "Function cannot have a template specialization kind"); +} + +bool FunctionDecl::isOutOfLine() const { + // FIXME: Should we restrict this to member functions? + if (Decl::isOutOfLine()) + return true; + + // If this function was instantiated from a member function of a + // class template, check whether that member function was defined out-of-line. + if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) { + const FunctionDecl *Definition; + if (FD->getBody(Definition)) + return Definition->isOutOfLine(); + } + + // If this function was instantiated from a function template, + // check whether that function template was defined out-of-line. + if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) { + const FunctionDecl *Definition; + if (FunTmpl->getTemplatedDecl()->getBody(Definition)) + return Definition->isOutOfLine(); + } + + return false; } //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// +SourceRange TagDecl::getSourceRange() const { + SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); + return SourceRange(TagKeywordLoc, E); +} + +TagDecl* TagDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + void TagDecl::startDefinition() { - TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->getAsTagType()->decl.setInt(1); + if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { + TagT->decl.setPointer(this); + TagT->decl.setInt(1); + } } void TagDecl::completeDefinition() { - assert((!TypeForDecl || - TypeForDecl->getAsTagType()->decl.getPointer() == this) && - "Attempt to redefine a tag definition?"); IsDefinition = true; - TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); - TagT->decl.setPointer(this); - TagT->decl.setInt(0); + if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { + assert(TagT->decl.getPointer() == this && + "Attempt to redefine a tag definition?"); + TagT->decl.setInt(0); + } } TagDecl* TagDecl::getDefinition(ASTContext& C) const { - QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this)); - TagDecl* D = cast<TagDecl>(T->getAsTagType()->getDecl()); - return D->isDefinition() ? D : 0; + if (isDefinition()) + return const_cast<TagDecl *>(this); + + for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); + R != REnd; ++R) + if (R->isDefinition()) + return *R; + + return 0; +} + +TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) { + switch (TypeSpec) { + default: llvm::llvm_unreachable("unexpected type specifier"); + case DeclSpec::TST_struct: return TK_struct; + case DeclSpec::TST_class: return TK_class; + case DeclSpec::TST_union: return TK_union; + case DeclSpec::TST_enum: return TK_enum; + } } //===----------------------------------------------------------------------===// @@ -669,18 +888,20 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { //===----------------------------------------------------------------------===// RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id) - : TagDecl(DK, TK, DC, L, Id) { + IdentifierInfo *Id, RecordDecl *PrevDecl, + SourceLocation TKL) + : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) { HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; + HasObjectMember = false; assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); } RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - RecordDecl* PrevDecl) { - - RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id); + SourceLocation TKL, RecordDecl* PrevDecl) { + + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL); C.getTypeDeclType(R, PrevDecl); return R; } @@ -693,7 +914,7 @@ void RecordDecl::Destroy(ASTContext& C) { } bool RecordDecl::isInjectedClassName() const { - return isImplicit() && getDeclName() && getDeclContext()->isRecord() && + return isImplicit() && getDeclName() && getDeclContext()->isRecord() && cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); } @@ -717,15 +938,15 @@ void BlockDecl::Destroy(ASTContext& C) { for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) (*I)->Destroy(C); - - C.Deallocate(ParamInfo); + + C.Deallocate(ParamInfo); Decl::Destroy(C); } void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, unsigned NParms) { assert(ParamInfo == 0 && "Already has param info!"); - + // Zero params -> null pointer. if (NParms) { NumParams = NParms; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 96ba19b9a6b9..224bf877ad24 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -62,12 +62,12 @@ bool Decl::CollectingStats(bool Enable) { void Decl::PrintStats() { fprintf(stderr, "*** Decl Stats:\n"); - + int totalDecls = 0; #define DECL(Derived, Base) totalDecls += n##Derived##s; #include "clang/AST/DeclNodes.def" fprintf(stderr, " %d decls total.\n", totalDecls); - + int totalBytes = 0; #define DECL(Derived, Base) \ if (n##Derived##s > 0) { \ @@ -77,7 +77,7 @@ void Decl::PrintStats() { (int)(n##Derived##s * sizeof(Derived##Decl))); \ } #include "clang/AST/DeclNodes.def" - + fprintf(stderr, "Total bytes = %d\n", totalBytes); } @@ -92,26 +92,26 @@ void Decl::addDeclKind(Kind k) { bool Decl::isTemplateParameterPack() const { if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) return TTP->isParameterPack(); - + return false; } bool Decl::isFunctionOrFunctionTemplate() const { if (const UsingDecl *UD = dyn_cast<UsingDecl>(this)) return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); - + return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); } //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// - + void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { SourceLocation TheLoc = Loc; if (TheLoc.isInvalid() && TheDecl) TheLoc = TheDecl->getLocation(); - + if (TheLoc.isValid()) { TheLoc.print(OS, SM); OS << ": "; @@ -123,7 +123,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { OS << " '" << DN->getQualifiedNameAsString() << '\''; OS << '\n'; } - + //===----------------------------------------------------------------------===// // Decl Implementation //===----------------------------------------------------------------------===// @@ -132,14 +132,14 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { Decl::~Decl() { if (isOutOfSemaDC()) delete getMultipleDC(); - + assert(!HasAttrs && "attributes should have been freed by Destroy"); } void Decl::setDeclContext(DeclContext *DC) { if (isOutOfSemaDC()) delete getMultipleDC(); - + DeclCtx = DC; } @@ -157,28 +157,39 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { } } +bool Decl::isInAnonymousNamespace() const { + const DeclContext *DC = getDeclContext(); + do { + if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) + if (ND->isAnonymousNamespace()) + return true; + } while ((DC = DC->getParent())); + + return false; +} + TranslationUnitDecl *Decl::getTranslationUnitDecl() { if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this)) return TUD; DeclContext *DC = getDeclContext(); assert(DC && "This decl is not contained in a translation unit!"); - + while (!DC->isTranslationUnit()) { DC = DC->getParent(); assert(DC && "This decl is not contained in a translation unit!"); } - + return cast<TranslationUnitDecl>(DC); } ASTContext &Decl::getASTContext() const { - return getTranslationUnitDecl()->getASTContext(); + return getTranslationUnitDecl()->getASTContext(); } unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { - default: + default: if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast) return IDNS_Ordinary; assert(0 && "Unknown decl kind!"); @@ -191,6 +202,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OriginalParmVar: case NonTypeTemplateParm: case Using: + case UnresolvedUsing: case ObjCMethod: case ObjCContainer: case ObjCCategory: @@ -198,10 +210,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProperty: case ObjCCompatibleAlias: return IDNS_Ordinary; - + case ObjCProtocol: return IDNS_ObjCProtocol; - + case ObjCImplementation: return IDNS_ObjCImplementation; @@ -212,13 +224,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCAtDefsField: case ObjCIvar: return IDNS_Member; - + case Record: case CXXRecord: case Enum: case TemplateTypeParm: return IDNS_Tag; - + case Namespace: case Template: case FunctionTemplate: @@ -226,8 +238,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case TemplateTemplateParm: case NamespaceAlias: return IDNS_Tag | IDNS_Ordinary; - + // Never have names. + case Friend: + case FriendTemplate: case LinkageSpec: case FileScopeAsm: case StaticAssert: @@ -250,41 +264,41 @@ void Decl::addAttr(Attr *NewAttr) { NewAttr->setNext(ExistingAttr); ExistingAttr = NewAttr; - + HasAttrs = true; } void Decl::invalidateAttrs() { if (!HasAttrs) return; - + HasAttrs = false; getASTContext().eraseDeclAttrs(this); } const Attr *Decl::getAttrsImpl() const { - assert(HasAttrs && "getAttrs() should verify this!"); + assert(HasAttrs && "getAttrs() should verify this!"); return getASTContext().getDeclAttrs(this); } void Decl::swapAttrs(Decl *RHS) { bool HasLHSAttr = this->HasAttrs; bool HasRHSAttr = RHS->HasAttrs; - + // Usually, neither decl has attrs, nothing to do. if (!HasLHSAttr && !HasRHSAttr) return; - + // If 'this' has no attrs, swap the other way. if (!HasLHSAttr) return RHS->swapAttrs(this); - + ASTContext &Context = getASTContext(); - + // Handle the case when both decls have attrs. if (HasRHSAttr) { std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); return; } - + // Otherwise, LHS has an attr and RHS doesn't. Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); Context.eraseDeclAttrs(this); @@ -300,7 +314,7 @@ void Decl::Destroy(ASTContext &C) { invalidateAttrs(); HasAttrs = false; } - + #if 0 // FIXME: Once ownership is fully understood, we can enable this code if (DeclContext *DC = dyn_cast<DeclContext>(this)) @@ -309,15 +323,15 @@ void Decl::Destroy(ASTContext &C) { // Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0 // within the loop, only the Destroy method for the first Decl // will deallocate all of the Decls in a chain. - + Decl* N = getNextDeclInContext(); - + while (N) { Decl* Tmp = N->getNextDeclInContext(); N->NextDeclInContext = 0; N->Destroy(C); N = Tmp; - } + } this->~Decl(); C.Deallocate((void *)this); @@ -377,8 +391,13 @@ SourceLocation Decl::getBodyRBrace() const { #ifndef NDEBUG void Decl::CheckAccessDeclContext() const { - assert((Access != AS_none || isa<TranslationUnitDecl>(this) || - !isa<CXXRecordDecl>(getDeclContext())) && + // If the decl is the toplevel translation unit or if we're not in a + // record decl context, we don't need to check anything. + if (isa<TranslationUnitDecl>(this) || + !isa<CXXRecordDecl>(getDeclContext())) + return; + + assert(Access != AS_none && "Access specifier is AS_none inside a record decl"); } @@ -413,6 +432,22 @@ void DeclContext::DestroyDecls(ASTContext &C) { (*D++)->Destroy(C); } +/// \brief Find the parent context of this context that will be +/// used for unqualified name lookup. +/// +/// Generally, the parent lookup context is the semantic context. However, for +/// a friend function the parent lookup context is the lexical context, which +/// is the class in which the friend is declared. +DeclContext *DeclContext::getLookupParent() { + // FIXME: Find a better way to identify friends + if (isa<FunctionDecl>(this)) + if (getParent()->getLookupContext()->isFileContext() && + getLexicalParent()->getLookupContext()->isRecord()) + return getLexicalParent(); + + return getParent(); +} + bool DeclContext::isDependentContext() const { if (isFileContext()) return false; @@ -427,7 +462,7 @@ bool DeclContext::isDependentContext() const { if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) if (Function->getDescribedFunctionTemplate()) return true; - + return getParent() && getParent()->isDependentContext(); } @@ -444,11 +479,21 @@ bool DeclContext::isTransparentContext() const { return false; } +bool DeclContext::Encloses(DeclContext *DC) { + if (getPrimaryContext() != this) + return getPrimaryContext()->Encloses(DC); + + for (; DC; DC = DC->getParent()) + if (DC->getPrimaryContext() == this) + return true; + return false; +} + DeclContext *DeclContext::getPrimaryContext() { switch (DeclKind) { case Decl::TranslationUnit: case Decl::LinkageSpec: - case Decl::Block: + case Decl::Block: // There is only one DeclContext for these entities. return this; @@ -473,8 +518,8 @@ DeclContext *DeclContext::getPrimaryContext() { if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. - if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAsTagType()) - if (TagT->isBeingDefined() || + if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAs<TagType>()) + if (TagT->isBeingDefined() || (TagT->getDecl() && TagT->getDecl()->isDefinition())) return TagT->getDecl(); return this; @@ -499,13 +544,13 @@ DeclContext *DeclContext::getNextContext() { /// \brief Load the declarations within this lexical storage from an /// external source. -void +void DeclContext::LoadLexicalDeclsFromExternalStorage() const { ExternalASTSource *Source = getParentASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); llvm::SmallVector<uint32_t, 64> Decls; - if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this), + if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this), Decls)) return; @@ -537,7 +582,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { LastDecl = PrevDecl; } -void +void DeclContext::LoadVisibleDeclsFromExternalStorage() const { DeclContext *This = const_cast<DeclContext *>(this); ExternalASTSource *Source = getParentASTContext().getExternalSource(); @@ -566,14 +611,14 @@ DeclContext::decl_iterator DeclContext::decls_begin() const { // FIXME: Check whether we need to load some declarations from // external storage. - return decl_iterator(FirstDecl); + return decl_iterator(FirstDecl); } DeclContext::decl_iterator DeclContext::decls_end() const { if (hasExternalLexicalStorage()) LoadLexicalDeclsFromExternalStorage(); - return decl_iterator(); + return decl_iterator(); } bool DeclContext::decls_empty() const { @@ -583,10 +628,10 @@ bool DeclContext::decls_empty() const { return !FirstDecl; } -void DeclContext::addDecl(Decl *D) { +void DeclContext::addHiddenDecl(Decl *D) { assert(D->getLexicalDeclContext() == this && "Decl inserted into wrong lexical context"); - assert(!D->getNextDeclInContext() && D != LastDecl && + assert(!D->getNextDeclInContext() && D != LastDecl && "Decl already inserted into a DeclContext"); if (FirstDecl) { @@ -595,6 +640,10 @@ void DeclContext::addDecl(Decl *D) { } else { FirstDecl = LastDecl = D; } +} + +void DeclContext::addDecl(Decl *D) { + addHiddenDecl(D); if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) ND->getDeclContext()->makeDeclVisibleInContext(ND); @@ -605,12 +654,15 @@ void DeclContext::addDecl(Decl *D) { /// transparent contexts nested within it). void DeclContext::buildLookup(DeclContext *DCtx) { for (; DCtx; DCtx = DCtx->getNextContext()) { - for (decl_iterator D = DCtx->decls_begin(), - DEnd = DCtx->decls_end(); + for (decl_iterator D = DCtx->decls_begin(), + DEnd = DCtx->decls_end(); D != DEnd; ++D) { - // Insert this declaration into the lookup structure + // Insert this declaration into the lookup structure, but only + // if it's semantically in its decl context. During non-lazy + // lookup building, this is implicitly enforced by addDecl. if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) - makeDeclVisibleInContextImpl(ND); + if (D->getDeclContext() == DCtx) + makeDeclVisibleInContextImpl(ND); // If this declaration is itself a transparent declaration context, // add its members (recursively). @@ -621,7 +673,7 @@ void DeclContext::buildLookup(DeclContext *DCtx) { } } -DeclContext::lookup_result +DeclContext::lookup_result DeclContext::lookup(DeclarationName Name) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) @@ -647,7 +699,7 @@ DeclContext::lookup(DeclarationName Name) { return Pos->second.getLookupResult(getParentASTContext()); } -DeclContext::lookup_const_result +DeclContext::lookup_const_result DeclContext::lookup(DeclarationName Name) const { return const_cast<DeclContext*>(this)->lookup(Name); } @@ -668,7 +720,7 @@ DeclContext *DeclContext::getEnclosingNamespaceContext() { return Ctx->getPrimaryContext(); } -void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { +void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? @@ -677,20 +729,20 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) { - PrimaryContext->makeDeclVisibleInContext(D); + PrimaryContext->makeDeclVisibleInContext(D, Recoverable); return; } // If we already have a lookup data structure, perform the insertion // into it. Otherwise, be lazy and don't build that structure until // someone asks for it. - if (LookupPtr) + if (LookupPtr || !Recoverable) makeDeclVisibleInContextImpl(D); // If we are a transparent context, insert into our parent context, // too. This operation is recursive. if (isTransparentContext()) - getParent()->makeDeclVisibleInContext(D); + getParent()->makeDeclVisibleInContext(D, Recoverable); } void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { @@ -720,14 +772,14 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // one, just replace it and return. if (DeclNameEntries.HandleRedeclaration(getParentASTContext(), D)) return; - + // Put this declaration into the appropriate slot. DeclNameEntries.AddSubsequentDecl(D); } /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. -DeclContext::udir_iterator_range +DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const { lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index b8b29528066d..457f4c85a047 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Expr.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -24,22 +25,32 @@ using namespace clang; //===----------------------------------------------------------------------===// CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) - : RecordDecl(K, TK, DC, L, Id), + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl *PrevDecl, + SourceLocation TKL) + : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), - Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false), - HasTrivialConstructor(true), HasTrivialDestructor(true), - Bases(0), NumBases(0), Conversions(DC, DeclarationName()), + Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), + Abstract(false), HasTrivialConstructor(true), + HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), + HasTrivialDestructor(true), ComputedVisibleConversions(false), + Bases(0), NumBases(0), VBases(0), NumVBases(0), + Conversions(DC, DeclarationName()), + VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation TKL, CXXRecordDecl* PrevDecl, bool DelayTypeCreation) { - CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id); + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id, + PrevDecl, TKL); + + // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) - C.getTypeDeclType(R, PrevDecl); + C.getTypeDeclType(R, PrevDecl); return R; } @@ -48,14 +59,15 @@ CXXRecordDecl::~CXXRecordDecl() { void CXXRecordDecl::Destroy(ASTContext &C) { C.Deallocate(Bases); + C.Deallocate(VBases); this->RecordDecl::Destroy(C); } -void +void CXXRecordDecl::setBases(ASTContext &C, - CXXBaseSpecifier const * const *Bases, + CXXBaseSpecifier const * const *Bases, unsigned NumBases) { - // C++ [dcl.init.aggr]p1: + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with [...] // no base classes [...]. Aggregate = false; @@ -63,39 +75,109 @@ CXXRecordDecl::setBases(ASTContext &C, if (this->Bases) C.Deallocate(this->Bases); + int vbaseCount = 0; + llvm::SmallVector<const CXXBaseSpecifier*, 8> UniqueVbases; + bool hasDirectVirtualBase = false; + this->Bases = new(C) CXXBaseSpecifier [NumBases]; this->NumBases = NumBases; - for (unsigned i = 0; i < NumBases; ++i) + for (unsigned i = 0; i < NumBases; ++i) { this->Bases[i] = *Bases[i]; + // Keep track of inherited vbases for this base class. + const CXXBaseSpecifier *Base = Bases[i]; + QualType BaseType = Base->getType(); + // Skip template types. + // FIXME. This means that this list must be rebuilt during template + // instantiation. + if (BaseType->isDependentType()) + continue; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + if (Base->isVirtual()) + hasDirectVirtualBase = true; + for (CXXRecordDecl::base_class_iterator VBase = + BaseClassDecl->vbases_begin(), + E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { + // Add this vbase to the array of vbases for current class if it is + // not already in the list. + // FIXME. Note that we do a linear search as number of such classes are + // very few. + int i; + for (i = 0; i < vbaseCount; ++i) + if (UniqueVbases[i]->getType() == VBase->getType()) + break; + if (i == vbaseCount) { + UniqueVbases.push_back(VBase); + ++vbaseCount; + } + } + } + if (hasDirectVirtualBase) { + // Iterate one more time through the direct bases and add the virtual + // base to the list of vritual bases for current class. + for (unsigned i = 0; i < NumBases; ++i) { + const CXXBaseSpecifier *VBase = Bases[i]; + if (!VBase->isVirtual()) + continue; + int j; + for (j = 0; j < vbaseCount; ++j) + if (UniqueVbases[j]->getType() == VBase->getType()) + break; + if (j == vbaseCount) { + UniqueVbases.push_back(VBase); + ++vbaseCount; + } + } + } + if (vbaseCount > 0) { + // build AST for inhireted, direct or indirect, virtual bases. + this->VBases = new (C) CXXBaseSpecifier [vbaseCount]; + this->NumVBases = vbaseCount; + for (int i = 0; i < vbaseCount; i++) { + QualType QT = UniqueVbases[i]->getType(); + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(QT->getAs<RecordType>()->getDecl()); + this->VBases[i] = + CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, + VBaseClassDecl->getTagKind() == RecordDecl::TK_class, + UniqueVbases[i]->getAccessSpecifier(), QT); + } + } } bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { - return getCopyConstructor(Context, QualType::Const) != 0; + return getCopyConstructor(Context, Qualifiers::Const) != 0; } -CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context, unsigned TypeQuals) const{ QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); - DeclarationName ConstructorName + DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned FoundTQs; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); Con != ConEnd; ++Con) { - if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, + // C++ [class.copy]p2: + // A non-template constructor for class X is a copy constructor if [...] + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, FoundTQs)) { - if (((TypeQuals & QualType::Const) == (FoundTQs & QualType::Const)) || - (!(TypeQuals & QualType::Const) && (FoundTQs & QualType::Const))) + if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || + (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) return cast<CXXConstructorDecl>(*Con); - + } } return 0; } -bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { +bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context, + const CXXMethodDecl *& MD) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -110,16 +192,17 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); if (Method->isStatic()) continue; - // TODO: Skip templates? Or is this implicitly done due to parameter types? + if (Method->getPrimaryTemplate()) + continue; const FunctionProtoType *FnType = - Method->getType()->getAsFunctionProtoType(); + Method->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no prototype."); // Don't assert on this; an invalid decl might have been left in the AST. if (FnType->getNumArgs() != 1 || FnType->isVariadic()) continue; bool AcceptsConst = true; QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) { + if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) { ArgType = Ref->getPointeeType(); // Is it a non-const lvalue reference? if (!ArgType.isConstQualified()) @@ -127,7 +210,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { } if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) continue; - + MD = Method; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; @@ -138,13 +221,13 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { } void -CXXRecordDecl::addedConstructor(ASTContext &Context, +CXXRecordDecl::addedConstructor(ASTContext &Context, CXXConstructorDecl *ConDecl) { assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl"); // Note that we have a user-declared constructor. UserDeclaredConstructor = true; - // C++ [dcl.init.aggr]p1: + // C++ [dcl.init.aggr]p1: // An aggregate is an array or a class (clause 9) with no // user-declared constructors (12.1) [...]. Aggregate = false; @@ -156,22 +239,34 @@ CXXRecordDecl::addedConstructor(ASTContext &Context, // C++ [class.ctor]p5: // A constructor is trivial if it is an implicitly-declared default // constructor. + // FIXME: C++0x: don't do this for "= default" default constructors. HasTrivialConstructor = false; - + // Note when we have a user-declared copy constructor, which will // suppress the implicit declaration of a copy constructor. - if (ConDecl->isCopyConstructor(Context)) + if (ConDecl->isCopyConstructor(Context)) { UserDeclaredCopyConstructor = true; + + // C++ [class.copy]p6: + // A copy constructor is trivial if it is implicitly declared. + // FIXME: C++0x: don't do this for "= default" copy constructors. + HasTrivialCopyConstructor = false; + } } void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. - const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); + const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + + // Copy assignment operators must be non-templates. + if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) + return; + QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) + if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); @@ -185,17 +280,212 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, // Suppress the implicit declaration of a copy constructor. UserDeclaredCopyAssignment = true; + // C++ [class.copy]p11: + // A copy assignment operator is trivial if it is implicitly declared. + // FIXME: C++0x: don't do this for "= default" copy operators. + HasTrivialCopyAssignment = false; + // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. PlainOldData = false; } -void CXXRecordDecl::addConversionFunction(ASTContext &Context, +void +CXXRecordDecl::collectConversionFunctions( + llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) +{ + OverloadedFunctionDecl *TopConversions = getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + TFunc = TopConversions->function_begin(), + TFuncEnd = TopConversions->function_end(); + TFunc != TFuncEnd; ++TFunc) { + NamedDecl *TopConv = TFunc->get(); + CanQualType TConvType; + if (FunctionTemplateDecl *TConversionTemplate = + dyn_cast<FunctionTemplateDecl>(TopConv)) + TConvType = + getASTContext().getCanonicalType( + TConversionTemplate->getTemplatedDecl()->getResultType()); + else + TConvType = + getASTContext().getCanonicalType( + cast<CXXConversionDecl>(TopConv)->getConversionType()); + ConversionsTypeSet.insert(TConvType); + } +} + +/// getNestedVisibleConversionFunctions - imports unique conversion +/// functions from base classes into the visible conversion function +/// list of the class 'RD'. This is a private helper method. +/// TopConversionsTypeSet is the set of conversion functions of the class +/// we are interested in. HiddenConversionTypes is set of conversion functions +/// of the immediate derived class which hides the conversion functions found +/// in current class. +void +CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, + const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet, + const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes) +{ + bool inTopClass = (RD == this); + QualType ClassType = getASTContext().getTypeDeclType(this); + if (const RecordType *Record = ClassType->getAs<RecordType>()) { + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + NamedDecl *Conv = Func->get(); + // Only those conversions not exact match of conversions in current + // class are candidateconversion routines. + CanQualType ConvType; + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast<FunctionTemplateDecl>(Conv)) + ConvType = + getASTContext().getCanonicalType( + ConversionTemplate->getTemplatedDecl()->getResultType()); + else + ConvType = + getASTContext().getCanonicalType( + cast<CXXConversionDecl>(Conv)->getConversionType()); + // We only add conversion functions found in the base class if they + // are not hidden by those found in HiddenConversionTypes which are + // the conversion functions in its derived class. + if (inTopClass || + (!TopConversionsTypeSet.count(ConvType) && + !HiddenConversionTypes.count(ConvType)) ) { + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast<FunctionTemplateDecl>(Conv)) + RD->addVisibleConversionFunction(ConversionTemplate); + else + RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv)); + } + } + } + + if (getNumBases() == 0 && getNumVBases() == 0) + return; + + llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; + if (!inTopClass) + collectConversionFunctions(ConversionFunctions); + + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), + E = vbases_end(); VBase != E; ++VBase) { + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + VBaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + + } + for (CXXRecordDecl::base_class_iterator Base = bases_begin(), + E = bases_end(); Base != E; ++Base) { + if (Base->isVirtual()) + continue; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + BaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + (inTopClass ? TopConversionsTypeSet : ConversionFunctions)); + + } +} + +/// getVisibleConversionFunctions - get all conversion functions visible +/// in current class; including conversion function templates. +OverloadedFunctionDecl * +CXXRecordDecl::getVisibleConversionFunctions() { + // If root class, all conversions are visible. + if (bases_begin() == bases_end()) + return &Conversions; + // If visible conversion list is already evaluated, return it. + if (ComputedVisibleConversions) + return &VisibleConversions; + llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet; + collectConversionFunctions(TopConversionsTypeSet); + getNestedVisibleConversionFunctions(this, TopConversionsTypeSet, + TopConversionsTypeSet); + ComputedVisibleConversions = true; + return &VisibleConversions; +} + +void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { + assert(!ConvDecl->getDescribedFunctionTemplate() && + "Conversion function templates should cast to FunctionTemplateDecl."); + VisibleConversions.addOverload(ConvDecl); +} + +void CXXRecordDecl::addVisibleConversionFunction( + FunctionTemplateDecl *ConvDecl) { + assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + VisibleConversions.addOverload(ConvDecl); +} + +void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) { + assert(!ConvDecl->getDescribedFunctionTemplate() && + "Conversion function templates should cast to FunctionTemplateDecl."); Conversions.addOverload(ConvDecl); } +void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { + assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + Conversions.addOverload(ConvDecl); +} + +CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>(); +} + +void +CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK) { + assert(TemplateOrInstantiation.isNull() && + "Previous template or instantiation?"); + assert(!isa<ClassTemplateSpecializationDecl>(this)); + TemplateOrInstantiation + = new (getASTContext()) MemberSpecializationInfo(RD, TSK); +} + +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void +CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + return; + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + return; + } + + assert(false && "Not a class template or member class specialization"); +} CXXConstructorDecl * CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { @@ -203,10 +493,14 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType.getUnqualifiedType())); - + DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = lookup(ConstructorName); Con != ConEnd; ++Con) { + // FIXME: In C++0x, a constructor template can be a default constructor. + if (isa<FunctionTemplateDecl>(*Con)) + continue; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); if (Constructor->isDefaultConstructor()) return Constructor; @@ -217,66 +511,105 @@ CXXRecordDecl::getDefaultConstructor(ASTContext &Context) { const CXXDestructorDecl * CXXRecordDecl::getDestructor(ASTContext &Context) { QualType ClassType = Context.getTypeDeclType(this); - - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName(ClassType); + + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); DeclContext::lookup_iterator I, E; - llvm::tie(I, E) = lookup(Name); + llvm::tie(I, E) = lookup(Name); assert(I != E && "Did not find a destructor!"); - + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); assert(++I == E && "Found more than one destructor!"); - + return Dtor; } CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isStatic, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline); + QualType T, DeclaratorInfo *DInfo, + bool isStatic, bool isInline) { + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, DInfo, + isStatic, isInline); } +bool CXXMethodDecl::isUsualDeallocationFunction() const { + if (getOverloadedOperator() != OO_Delete && + getOverloadedOperator() != OO_Array_Delete) + return false; + + // C++ [basic.stc.dynamic.deallocation]p2: + // If a class T has a member deallocation function named operator delete + // with exactly one parameter, then that function is a usual (non-placement) + // deallocation function. [...] + if (getNumParams() == 1) + return true; + + // C++ [basic.stc.dynamic.deallocation]p2: + // [...] If class T does not declare such an operator delete but does + // declare a member deallocation function named operator delete with + // exactly two parameters, the second of which has type std::size_t (18.1), + // then this function is a usual deallocation function. + ASTContext &Context = getASTContext(); + if (getNumParams() != 2 || + !Context.hasSameType(getParamDecl(1)->getType(), Context.getSizeType())) + return false; + + // This function is a usual deallocation function if there are no + // single-parameter deallocation functions of the same kind. + for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); + R.first != R.second; ++R.first) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first)) + if (FD->getNumParams() == 1) + return false; + } + + return true; +} -typedef llvm::DenseMap<const CXXMethodDecl*, - std::vector<const CXXMethodDecl *> *> +typedef llvm::DenseMap<const CXXMethodDecl*, + std::vector<const CXXMethodDecl *> *> OverriddenMethodsMapTy; +// FIXME: We hate static data. This doesn't survive PCH saving/loading, and +// the vtable building code uses it at CG time. static OverriddenMethodsMapTy *OverriddenMethods = 0; void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. - + if (!OverriddenMethods) OverriddenMethods = new OverriddenMethodsMapTy(); - + std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this]; if (!Methods) Methods = new std::vector<const CXXMethodDecl *>; - + Methods->push_back(MD); } CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { if (!OverriddenMethods) return 0; - + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end()) + if (it == OverriddenMethods->end() || it->second->empty()) return 0; + return &(*it->second)[0]; } CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { if (!OverriddenMethods) return 0; - + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); - if (it == OverriddenMethods->end()) + if (it == OverriddenMethods->end() || it->second->empty()) return 0; - return &(*it->second)[it->second->size()]; + return &(*it->second)[0] + it->second->size(); } QualType CXXMethodDecl::getThisType(ASTContext &C) const { @@ -292,40 +625,46 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate()) ClassTy = TD->getInjectedClassNameType(C); else - ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); - ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); - return C.getPointerType(ClassTy).withConst(); + ClassTy = C.getTagDeclType(getParent()); + ClassTy = C.getQualifiedType(ClassTy, + Qualifiers::fromCVRMask(getTypeQualifiers())); + return C.getPointerType(ClassTy); } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs, - SourceLocation L) - : Args(0), NumArgs(0), IdLoc(L) { + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R) + : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr()); assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); BaseOrMember |= 0x01; - + if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Expr*[NumArgs]; + // FIXME. Allocation via Context + this->Args = new Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } + CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, - SourceLocation L) - : Args(0), NumArgs(0), IdLoc(L) { + CXXConstructorDecl *C, + SourceLocation L, SourceLocation R) + : Args(0), NumArgs(0), CtorOrAnonUnion(), IdLoc(L), RParenLoc(R) { BaseOrMember = reinterpret_cast<uintptr_t>(Member); - assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); + assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); if (NumArgs > 0) { this->NumArgs = NumArgs; - this->Args = new Expr*[NumArgs]; + this->Args = new Stmt*[NumArgs]; for (unsigned Idx = 0; Idx < NumArgs; ++Idx) this->Args[Idx] = Args[Idx]; } + CtorOrAnonUnion = C; } CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { @@ -335,11 +674,12 @@ CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isExplicit, + QualType T, DeclaratorInfo *DInfo, + bool isExplicit, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline, + return new (C) CXXConstructorDecl(RD, L, N, T, DInfo, isExplicit, isInline, isImplicitlyDeclared); } @@ -348,11 +688,11 @@ bool CXXConstructorDecl::isDefaultConstructor() const { // A default constructor for a class X is a constructor of class // X that can be called without an argument. return (getNumParams() == 0) || - (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0); + (getNumParams() > 0 && getParamDecl(0)->hasDefaultArg()); } -bool -CXXConstructorDecl::isCopyConstructor(ASTContext &Context, +bool +CXXConstructorDecl::isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor @@ -360,42 +700,46 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context, // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). if ((getNumParams() < 1) || - (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg())) + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() != 0) || + (getDescribedFunctionTemplate() != 0)) return false; const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? Rvalue references don't count. const LValueReferenceType *ParamRefType = - Param->getType()->getAsLValueReferenceType(); + Param->getType()->getAs<LValueReferenceType>(); if (!ParamRefType) return false; // Is it a reference to our class type? - QualType PointeeType + CanQualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); - QualType ClassTy - = Context.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; + // FIXME: other qualifiers? + // We have a copy constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; } -bool CXXConstructorDecl::isConvertingConstructor() const { +bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { // C++ [class.conv.ctor]p1: // A constructor declared without the function-specifier explicit // that can be called with a single parameter specifies a // conversion from the type of its first parameter to the type of // its class. Such a constructor is called a converting // constructor. - if (isExplicit()) + if (isExplicit() && !AllowExplicit) return false; - return (getNumParams() == 0 && - getType()->getAsFunctionProtoType()->isVariadic()) || + return (getNumParams() == 0 && + getType()->getAs<FunctionProtoType>()->isVariadic()) || (getNumParams() == 1) || (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } @@ -403,42 +747,34 @@ bool CXXConstructorDecl::isConvertingConstructor() const { CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, + QualType T, bool isInline, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } void -CXXConstructorDecl::setBaseOrMemberInitializers( - ASTContext &C, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers) { - if (NumInitializers > 0) { - NumBaseOrMemberInitializers = NumInitializers; - BaseOrMemberInitializers = - new (C, 8) CXXBaseOrMemberInitializer*[NumInitializers]; - for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) - BaseOrMemberInitializers[Idx] = Initializers[Idx]; - } +CXXDestructorDecl::Destroy(ASTContext& C) { + C.Deallocate(BaseOrMemberDestructions); + CXXMethodDecl::Destroy(C); } void CXXConstructorDecl::Destroy(ASTContext& C) { C.Deallocate(BaseOrMemberInitializers); - this->~CXXMethodDecl(); - C.Deallocate((void *)this); + CXXMethodDecl::Destroy(C); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, - QualType T, bool isInline, bool isExplicit) { + QualType T, DeclaratorInfo *DInfo, + bool isInline, bool isExplicit) { assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit); + return new (C) CXXConversionDecl(RD, L, N, T, DInfo, isInline, isExplicit); } OverloadedFunctionDecl * @@ -447,13 +783,78 @@ OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, return new (C) OverloadedFunctionDecl(DC, N); } +OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) { + if (!ND) + return; + + if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND)) + D = ND; + else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) { + if (Ovl->size() != 0) { + D = ND; + Iter = Ovl->function_begin(); + } + } +} + void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) { Functions.push_back(F); this->setLocation(F.get()->getLocation()); } +OverloadIterator::reference OverloadIterator::operator*() const { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD; + + if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) + return FTD; + + assert(isa<OverloadedFunctionDecl>(D)); + return *Iter; +} + +OverloadIterator &OverloadIterator::operator++() { + if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { + D = 0; + return *this; + } + + if (++Iter == cast<OverloadedFunctionDecl>(D)->function_end()) + D = 0; + + return *this; +} + +bool OverloadIterator::Equals(const OverloadIterator &Other) const { + if (!D || !Other.D) + return D == Other.D; + + if (D != Other.D) + return false; + + return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter; +} + +FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + FriendUnion Friend, + SourceLocation FriendL) { +#ifndef NDEBUG + if (Friend.is<NamedDecl*>()) { + NamedDecl *D = Friend.get<NamedDecl*>(); + assert(isa<FunctionDecl>(D) || + isa<CXXRecordDecl>(D) || + isa<FunctionTemplateDecl>(D) || + isa<ClassTemplateDecl>(D)); + assert(D->getFriendObjectKind()); + } +#endif + + return new (C) FriendDecl(DC, L, Friend, FriendL); +} + LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, - DeclContext *DC, + DeclContext *DC, SourceLocation L, LanguageIDs Lang, bool Braces) { return new (C) LinkageSpecDecl(DC, L, Lang, Braces); @@ -467,19 +868,19 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdentLoc, NamespaceDecl *Used, DeclContext *CommonAncestor) { - return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, Qualifier, IdentLoc, Used, CommonAncestor); } -NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - SourceLocation AliasLoc, - IdentifierInfo *Alias, +NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation AliasLoc, + IdentifierInfo *Alias, SourceRange QualifierRange, NestedNameSpecifier *Qualifier, - SourceLocation IdentLoc, + SourceLocation IdentLoc, NamedDecl *Namespace) { - return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, + return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, Qualifier, IdentLoc, Namespace); } @@ -491,6 +892,17 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, TargetNNS, IsTypeNameArg); } +UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName, + bool IsTypeNameArg) { + return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS, + TargetNameLoc, TargetName, IsTypeNameArg); +} + StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, Expr *AssertExpr, StringLiteral *Message) { diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 54f13e14ba65..7f38ac1d9ad0 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -30,8 +30,8 @@ void ObjCListBase::Destroy(ASTContext &Ctx) { void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { assert(List == 0 && "Elements already set!"); if (Elts == 0) return; // Setting to an empty list is a noop. - - + + List = new (Ctx) void*[Elts]; NumElts = Elts; memcpy(List, InList, sizeof(void*)*Elts); @@ -54,29 +54,9 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { return 0; } -// Get the local instance method declared in this interface. -ObjCMethodDecl * -ObjCContainerDecl::getInstanceMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isInstanceMethod()) - return MD; - } - return 0; -} - -// Get the local class method declared in this interface. +// Get the local instance/class method declared in this interface. ObjCMethodDecl * -ObjCContainerDecl::getClassMethod(Selector Sel) const { +ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const { // Since instance & class methods can have the same name, the loop below // ensures we get the correct method. // @@ -88,7 +68,7 @@ ObjCContainerDecl::getClassMethod(Selector Sel) const { lookup_const_iterator Meth, MethEnd; for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) { ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isClassMethod()) + if (MD && MD->isInstanceMethod() == isInstance) return MD; } return 0; @@ -103,15 +83,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { for (prop_iterator I = prop_begin(), E = prop_end(); I != E; ++I) if ((*I)->getIdentifier() == PropertyId) return *I; - + const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this); if (PID) { - for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), E = PID->protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; } - + if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) { // Look through categories. for (ObjCCategoryDecl *Category = OID->getCategoryList(); @@ -138,6 +118,45 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return 0; } +void ObjCInterfaceDecl::mergeClassExtensionProtocolList( + ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + ASTContext &C) +{ + if (ReferencedProtocols.empty()) { + ReferencedProtocols.set(ExtList, ExtNum, C); + return; + } + // Check for duplicate protocol in class's protocol list. + // This is (O)2. But it is extremely rare and number of protocols in + // class or its extension are very few. + llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + for (unsigned i = 0; i < ExtNum; i++) { + bool protocolExists = false; + ObjCProtocolDecl *ProtoInExtension = ExtList[i]; + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) { + ObjCProtocolDecl *Proto = (*p); + if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) { + protocolExists = true; + break; + } + } + // Do we want to warn on a protocol in extension class which + // already exist in the class? Probably not. + if (!protocolExists) + ProtocolRefs.push_back(ProtoInExtension); + } + if (ProtocolRefs.empty()) + return; + // Merge ProtocolRefs into class's protocol list; + for (protocol_iterator p = protocol_begin(), e = protocol_end(); + p != e; p++) + ProtocolRefs.push_back(*p); + ReferencedProtocols.Destroy(C); + unsigned NumProtoRefs = ProtocolRefs.size(); + setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C); +} + ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { ObjCInterfaceDecl* ClassDecl = this; @@ -165,72 +184,37 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( return NULL; } -/// lookupInstanceMethod - This method returns an instance method by looking in +/// lookupMethod - This method returns an instance/class method by looking in /// the class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; +ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, + bool isInstance) const { + const ObjCInterfaceDecl* ClassDecl = this; ObjCMethodDecl *MethodDecl = 0; - + while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) + if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance))) return MethodDecl; - + // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = ClassDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; - - // Didn't find one yet - now look through categories. - ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); - while (CatDecl) { - if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; - - // Didn't find one yet - look through protocols. - const ObjCList<ObjCProtocolDecl> &Protocols = - CatDecl->getReferencedProtocols(); - for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), - E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; - CatDecl = CatDecl->getNextClassCategory(); - } - ClassDecl = ClassDecl->getSuperClass(); - } - return NULL; -} - -// lookupClassMethod - This method returns a class method by looking in the -// class, its categories, and its super classes (using a linear search). -ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { - ObjCInterfaceDecl* ClassDecl = this; - ObjCMethodDecl *MethodDecl = 0; - - while (ClassDecl != NULL) { - if ((MethodDecl = ClassDecl->getClassMethod(Sel))) - return MethodDecl; - // Didn't find one yet - look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(), - E = ClassDecl->protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) - return MethodDecl; - // Didn't find one yet - now look through categories. ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); while (CatDecl) { - if ((MethodDecl = CatDecl->getClassMethod(Sel))) + if ((MethodDecl = CatDecl->getMethod(Sel, isInstance))) return MethodDecl; - + // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = CatDecl->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; CatDecl = CatDecl->getNextClassCategory(); } @@ -239,14 +223,23 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { return NULL; } - +ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateInstanceMethod( + const Selector &Sel) { + ObjCMethodDecl *Method = 0; + if (ObjCImplementationDecl *ImpDecl = getImplementation()) + Method = ImpDecl->getInstanceMethod(Sel); + + if (!Method && getSuperClass()) + return getSuperClass()->lookupPrivateInstanceMethod(Sel); + return Method; +} //===----------------------------------------------------------------------===// // ObjCMethodDecl //===----------------------------------------------------------------------===// ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, - SourceLocation beginLoc, + SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, DeclContext *contextDecl, @@ -256,14 +249,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, ImplementationControl impControl) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, contextDecl, - isInstance, + isInstance, isVariadic, isSynthesized, impControl); } void ObjCMethodDecl::Destroy(ASTContext &C) { if (Body) Body->Destroy(C); if (SelfDecl) SelfDecl->Destroy(C); - + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) if (*I) (*I)->Destroy(C); @@ -272,7 +265,57 @@ void ObjCMethodDecl::Destroy(ASTContext &C) { Decl::Destroy(C); } -void ObjCMethodDecl::createImplicitParams(ASTContext &Context, +/// \brief A definition will return its interface declaration. +/// An interface declaration will return its definition. +/// Otherwise it will return itself. +ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { + ASTContext &Ctx = getASTContext(); + ObjCMethodDecl *Redecl = 0; + Decl *CtxD = cast<Decl>(getDeclContext()); + + if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } + + return Redecl ? Redecl : this; +} + +ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { + Decl *CtxD = cast<Decl>(getDeclContext()); + + if (ObjCImplementationDecl *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryClass()) + if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + } + + return this; +} + +void ObjCMethodDecl::createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *OID) { QualType selfTy; if (isInstanceMethod()) { @@ -280,49 +323,30 @@ void ObjCMethodDecl::createImplicitParams(ASTContext &Context, // of the interface (which has been reported). Recover gracefully. if (OID) { selfTy = Context.getObjCInterfaceType(OID); - selfTy = Context.getPointerType(selfTy); + selfTy = Context.getObjCObjectPointerType(selfTy); } else { selfTy = Context.getObjCIdType(); } } else // we have a factory method. selfTy = Context.getObjCClassType(); - setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy)); - setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), - &Context.Idents.get("_cmd"), + setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("_cmd"), Context.getObjCSelType())); } - - -/// getSynthesizedMethodSize - Compute size of synthesized method name -/// as done be the rewrite. -/// -unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { - // syntesized method name is a concatenation of -/+[class-name selector] - // Get length of this name. - unsigned length = 3; // _I_ or _C_ - length += getClassInterface()->getNameAsString().size()+1; // extra for _ - if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(getDeclContext())) - length += CID->getNameAsString().size()+1; - length += getSelector().getAsString().size(); // selector name - return length; -} - ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext())) return ID; if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext())) return CD->getClassInterface(); - if (ObjCImplementationDecl *IMD = - dyn_cast<ObjCImplementationDecl>(getDeclContext())) + if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(getDeclContext())) return IMD->getClassInterface(); - if (ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(getDeclContext())) - return CID->getClassInterface(); + + assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method"); assert(false && "unknown method context"); return 0; } @@ -334,7 +358,7 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation atLoc, - IdentifierInfo *Id, + IdentifierInfo *Id, SourceLocation ClassLoc, bool ForwardDecl, bool isInternal){ return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl, @@ -350,19 +374,28 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, ClassLoc(CLoc) { } -void ObjCInterfaceDecl::Destroy(ASTContext &C) { +void ObjCInterfaceDecl::Destroy(ASTContext &C) { for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I) if (*I) (*I)->Destroy(C); - + IVars.Destroy(C); // FIXME: CategoryList? - + // FIXME: Because there is no clear ownership // role between ObjCInterfaceDecls and the ObjCPropertyDecls that they // reference, we destroy ObjCPropertyDecls in ~TranslationUnit. Decl::Destroy(C); } +ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast<ObjCInterfaceDecl*>(this)); +} + +void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + /// FindCategoryDeclaration - Finds category declaration in the list of /// categories for this class and returns it. Name of the category is passed @@ -377,14 +410,79 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { return 0; } +ObjCMethodDecl * +ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel)) + return MD; + return 0; +} + +ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel)) + return MD; + return 0; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID) { + ObjCInterfaceDecl *IDecl = this; + // 1st, look up the class. + const ObjCList<ObjCProtocolDecl> &Protocols = + IDecl->getReferencedProtocols(); + + for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), + E = Protocols.end(); PI != E; ++PI) { + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + // This is dubious and is added to be compatible with gcc. In gcc, it is + // also allowed assigning a protocol-qualified 'id' type to a LHS object + // when protocol in qualified LHS is in list of protocols in the rhs 'id' + // object. This IMO, should be a bug. + // FIXME: Treat this as an extension, and flag this as an error when GCC + // extensions are not enabled. + if (RHSIsQualifiedID && + getASTContext().ProtocolCompatibleWithProtocol(*PI, lProto)) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory, + RHSIsQualifiedID); + + return false; +} + //===----------------------------------------------------------------------===// // ObjCIvarDecl //===----------------------------------------------------------------------===// ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, AccessControl ac, Expr *BW) { - return new (C) ObjCIvarDecl(DC, L, Id, T, ac, BW); + QualType T, DeclaratorInfo *DInfo, + AccessControl ac, Expr *BW) { + return new (C) ObjCIvarDecl(DC, L, Id, T, DInfo, ac, BW); } @@ -401,7 +499,7 @@ ObjCAtDefsFieldDecl void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { this->~ObjCAtDefsFieldDecl(); - C.Deallocate((void *)this); + C.Deallocate((void *)this); } //===----------------------------------------------------------------------===// @@ -409,7 +507,7 @@ void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { //===----------------------------------------------------------------------===// ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation L, IdentifierInfo *Id) { return new (C) ObjCProtocolDecl(DC, L, Id); } @@ -428,34 +526,21 @@ ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) if ((PDecl = (*I)->lookupProtocolNamed(Name))) return PDecl; - - return NULL; -} -// lookupInstanceMethod - Lookup a instance method in the protocol and protocols -// it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { - ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getInstanceMethod(Sel))) - return MethodDecl; - - for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupInstanceMethod(Sel))) - return MethodDecl; return NULL; } -// lookupInstanceMethod - Lookup a class method in the protocol and protocols +// lookupMethod - Lookup a instance/class method in the protocol and protocols // it inherited. -ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { +ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, + bool isInstance) const { ObjCMethodDecl *MethodDecl = NULL; - - if ((MethodDecl = getClassMethod(Sel))) + + if ((MethodDecl = getMethod(Sel, isInstance))) return MethodDecl; - + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) - if ((MethodDecl = (*I)->lookupClassMethod(Sel))) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) return MethodDecl; return NULL; } @@ -464,7 +549,7 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { // ObjCClassDecl //===----------------------------------------------------------------------===// -ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, +ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *const *Elts, unsigned nElts, ASTContext &C) : Decl(ObjCClass, DC, L) { @@ -480,7 +565,7 @@ ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, } void ObjCClassDecl::Destroy(ASTContext &C) { - + // FIXME: There is no clear ownership policy now for referenced // ObjCInterfaceDecls. Some of them can be forward declarations that // are never later defined (in which case the ObjCClassDecl owns them) @@ -488,7 +573,7 @@ void ObjCClassDecl::Destroy(ASTContext &C) { // we should have separate objects for forward declarations and definitions, // obviating this problem. Because of this situation, referenced // ObjCInterfaceDecls are destroyed in ~TranslationUnit. - + ForwardDecls.Destroy(C); Decl::Destroy(C); } @@ -501,14 +586,14 @@ ObjCForwardProtocolDecl:: ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, ASTContext &C) -: Decl(ObjCForwardProtocol, DC, L) { +: Decl(ObjCForwardProtocol, DC, L) { ReferencedProtocols.set(Elts, nElts, C); } ObjCForwardProtocolDecl * ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned NumElts) { return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C); @@ -529,6 +614,16 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryDecl(DC, L, Id); } +ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast<ObjCCategoryDecl*>(this)); +} + +void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + + //===----------------------------------------------------------------------===// // ObjCCategoryImplDecl //===----------------------------------------------------------------------===// @@ -540,6 +635,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); } +ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryClass() const { + return getClassInterface()->FindCategoryDeclaration(getIdentifier()); +} + void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { // FIXME: The context should be correct before we get here. @@ -547,6 +646,23 @@ void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { addDecl(property); } +void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { + ASTContext &Ctx = getASTContext(); + + if (ObjCImplementationDecl *ImplD + = dyn_cast_or_null<ObjCImplementationDecl>(this)) { + if (IFace) + Ctx.setObjCImplementation(IFace, ImplD); + + } else if (ObjCCategoryImplDecl *ImplD = + dyn_cast_or_null<ObjCCategoryImplDecl>(this)) { + if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier())) + Ctx.setObjCImplementation(CD, ImplD); + } + + ClassInterface = IFace; +} + /// FindPropertyImplIvarDecl - This method lookup the ivar in the list of /// properties implemented in this category @implementation block and returns /// the implemented property that uses it. @@ -576,56 +692,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } -// getInstanceMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCImplDecl::getInstanceMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); - Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isInstanceMethod()) - return MD; - } - return 0; -} - -// getClassMethod - This method returns an instance method by looking in -// the class implementation. Unlike interfaces, we don't look outside the -// implementation. -ObjCMethodDecl *ObjCImplDecl::getClassMethod(Selector Sel) const { - // Since instance & class methods can have the same name, the loop below - // ensures we get the correct method. - // - // @interface Whatever - // - (int) class_method; - // + (float) class_method; - // @end - // - lookup_const_iterator Meth, MethEnd; - for (llvm::tie(Meth, MethEnd) = lookup(Sel); - Meth != MethEnd; ++Meth) { - ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); - if (MD && MD->isClassMethod()) - return MD; - } - return 0; -} - //===----------------------------------------------------------------------===// // ObjCImplementationDecl //===----------------------------------------------------------------------===// ObjCImplementationDecl * -ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, +ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCInterfaceDecl *ClassInterface, ObjCInterfaceDecl *SuperDecl) { @@ -639,7 +711,7 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, ObjCCompatibleAliasDecl * ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, + IdentifierInfo *Id, ObjCInterfaceDecl* AliasedClass) { return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass); } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 12e89cd80d19..9d0d836cf62b 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -19,7 +19,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -34,8 +33,10 @@ namespace { llvm::raw_ostream& Indent(); void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); + void Print(AccessSpecifier AS); + public: - DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, + DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, const PrintingPolicy &Policy, unsigned Indentation = 0) : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } @@ -71,17 +72,19 @@ namespace { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + void VisitUsingDecl(UsingDecl *D); }; } -void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) { +void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const { print(Out, getASTContext().PrintingPolicy, Indentation); } void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy, - unsigned Indentation) { + unsigned Indentation) const { DeclPrinter Printer(Out, getASTContext(), Policy, Indentation); - Printer.Visit(this); + Printer.Visit(const_cast<Decl*>(this)); } static QualType GetBaseType(QualType T) { @@ -90,13 +93,13 @@ static QualType GetBaseType(QualType T) { while (!BaseType->isSpecifierType()) { if (isa<TypedefType>(BaseType)) break; - else if (const PointerType* PTy = BaseType->getAsPointerType()) + else if (const PointerType* PTy = BaseType->getAs<PointerType>()) BaseType = PTy->getPointeeType(); else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) BaseType = ATy->getElementType(); - else if (const FunctionType* FTy = BaseType->getAsFunctionType()) + else if (const FunctionType* FTy = BaseType->getAs<FunctionType>()) BaseType = FTy->getResultType(); - else if (const VectorType *VTy = BaseType->getAsVectorType()) + else if (const VectorType *VTy = BaseType->getAs<VectorType>()) BaseType = VTy->getElementType(); else assert(0 && "Unknown declarator!"); @@ -146,7 +149,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, } } -void Decl::dump() { +void Decl::dump() const { print(llvm::errs()); } @@ -164,6 +167,15 @@ void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) { } +void DeclPrinter::Print(AccessSpecifier AS) { + switch(AS) { + case AS_none: assert(0 && "No access specifier!"); break; + case AS_public: Out << "public"; break; + case AS_protected: Out << "protected"; break; + case AS_private: Out << " private"; break; + } +} + //---------------------------------------------------------------------------- // Common C declarations //---------------------------------------------------------------------------- @@ -172,6 +184,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { if (Indent) Indentation += Policy.Indentation; + bool PrintAccess = isa<CXXRecordDecl>(DC); + AccessSpecifier CurAS = AS_none; + llvm::SmallVector<Decl*, 2> Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { @@ -185,6 +200,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { continue; } + if (PrintAccess) { + AccessSpecifier AS = D->getAccess(); + + if (AS != CurAS) { + Print(AS); + Out << ":\n"; + CurAS = AS; + } + } + // The next bits of code handles stuff like "struct {int x;} a,b"; we're // forced to merge the declarations because there's no other way to // refer to the struct in question. This limited merging is safe without @@ -215,16 +240,16 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { } this->Indent(); Visit(*D); - - // FIXME: Need to be able to tell the DeclPrinter when + + // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = 0; - if (isa<FunctionDecl>(*D) && + if (isa<FunctionDecl>(*D) && cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) Terminator = 0; else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) Terminator = 0; else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) || - isa<ObjCImplementationDecl>(*D) || + isa<ObjCImplementationDecl>(*D) || isa<ObjCInterfaceDecl>(*D) || isa<ObjCProtocolDecl>(*D) || isa<ObjCCategoryImplDecl>(*D) || @@ -274,7 +299,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { Out << " "; Out << D->getNameAsString(); } - + if (D->isDefinition()) { Out << " {\n"; VisitDeclContext(D); @@ -290,7 +315,7 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { } } -void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { +void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!Policy.SuppressSpecifiers) { switch (D->getStorageClass()) { case FunctionDecl::None: break; @@ -307,7 +332,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { SubPolicy.SuppressSpecifiers = false; std::string Proto = D->getNameAsString(); if (isa<FunctionType>(D->getType().getTypePtr())) { - const FunctionType *AFT = D->getType()->getAsFunctionType(); + const FunctionType *AFT = D->getType()->getAs<FunctionType>(); const FunctionProtoType *FT = 0; if (D->hasWrittenPrototype()) @@ -321,7 +346,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (i) POut << ", "; ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); } - + if (FT->isVariadic()) { if (D->getNumParams()) POut << ", "; POut << "..."; @@ -335,7 +360,81 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } Proto += ")"; - AFT->getResultType().getAsStringInternal(Proto, Policy); + if (D->hasAttr<NoReturnAttr>()) + Proto += " __attribute((noreturn))"; + if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { + if (CDecl->getNumBaseOrMemberInitializers() > 0) { + Proto += " : "; + Out << Proto; + Proto.clear(); + for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), + E = CDecl->init_end(); + B != E; ++B) { + CXXBaseOrMemberInitializer * BMInitializer = (*B); + if (B != CDecl->init_begin()) + Out << ", "; + bool hasArguments = (BMInitializer->arg_begin() != + BMInitializer->arg_end()); + if (BMInitializer->isMemberInitializer()) { + FieldDecl *FD = BMInitializer->getMember(); + Out << FD->getNameAsString(); + } + else // FIXME. skip dependent types for now. + if (const RecordType *RT = + BMInitializer->getBaseClass()->getAs<RecordType>()) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(RT->getDecl()); + Out << BaseDecl->getNameAsString(); + } + if (hasArguments) { + Out << "("; + for (CXXBaseOrMemberInitializer::const_arg_iterator BE = + BMInitializer->const_arg_begin(), + EE = BMInitializer->const_arg_end(); BE != EE; ++BE) { + if (BE != BMInitializer->const_arg_begin()) + Out<< ", "; + const Expr *Exp = (*BE); + Exp->printPretty(Out, Context, 0, Policy, Indentation); + } + Out << ")"; + } else + Out << "()"; + } + } + } + else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) { + if (DDecl->getNumBaseOrMemberDestructions() > 0) { + // List order of base/member destruction for visualization purposes. + assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list"); + Proto += "/* : "; + for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(), + *E = DDecl->destr_end(); + B != E; ++B) { + uintptr_t BaseOrMember = (*B); + if (B != DDecl->destr_begin()) + Proto += ", "; + + if (DDecl->isMemberToDestroy(BaseOrMember)) { + FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember); + Proto += "~"; + Proto += FD->getNameAsString(); + } + else // FIXME. skip dependent types for now. + if (const RecordType *RT = + DDecl->getAnyBaseClassToDestroy(BaseOrMember) + ->getAs<RecordType>()) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(RT->getDecl()); + Proto += "~"; + Proto += BaseDecl->getNameAsString(); + } + Proto += "()"; + } + Proto += " */"; + } + } + else + AFT->getResultType().getAsStringInternal(Proto, Policy); } else { D->getType().getAsStringInternal(Proto, Policy); } @@ -423,7 +522,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { - assert(false && + assert(false && "OverloadedFunctionDecls aren't really decls and are never printed"); } @@ -453,28 +552,23 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << " "; Out << D->getNameAsString(); } - + if (D->isDefinition()) { // Print the base classes if (D->getNumBases()) { Out << " : "; - for(CXXRecordDecl::base_class_iterator Base = D->bases_begin(), - BaseEnd = D->bases_end(); - Base != BaseEnd; ++Base) { + for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(), + BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) { if (Base != D->bases_begin()) Out << ", "; if (Base->isVirtual()) Out << "virtual "; - switch(Base->getAccessSpecifierAsWritten()) { - case AS_none: break; - case AS_public: Out << "public "; break; - case AS_protected: Out << "protected "; break; - case AS_private: Out << " private "; break; - } - - Out << Base->getType().getAsString(Policy); + AccessSpecifier AS = Base->getAccessSpecifierAsWritten(); + if (AS != AS_none) + Print(AS); + Out << " " << Base->getType().getAsString(Policy); } } @@ -483,7 +577,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << " {\n"; VisitDeclContext(D); Indent() << "}"; - } + } } void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { @@ -507,17 +601,17 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << "template <"; - + TemplateParameterList *Params = D->getTemplateParameters(); for (unsigned i = 0, e = Params->size(); i != e; ++i) { if (i != 0) Out << ", "; - + const Decl *Param = Params->getParam(i); - if (const TemplateTypeParmDecl *TTP = + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { - - QualType ParamType = + + QualType ParamType = Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP)); if (TTP->wasDeclaredWithTypename()) @@ -527,14 +621,14 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { if (TTP->isParameterPack()) Out << "... "; - + Out << ParamType.getAsString(Policy); if (TTP->hasDefaultArgument()) { Out << " = "; Out << TTP->getDefaultArgument().getAsString(Policy); }; - } else if (const NonTypeTemplateParmDecl *NTTP = + } else if (const NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { Out << NTTP->getType().getAsString(Policy); @@ -542,15 +636,15 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { Out << ' '; Out << Name->getName(); } - + if (NTTP->hasDefaultArgument()) { Out << " = "; - NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, + NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, Indentation); } } } - + Out << "> "; Visit(D->getTemplatedDecl()); @@ -572,29 +666,29 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isInstanceMethod()) Out << "- "; - else + else Out << "+ "; if (!OMD->getResultType().isNull()) Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; - + std::string name = OMD->getSelector().getAsString(); std::string::size_type pos, lastPos = 0; for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), E = OMD->param_end(); PI != E; ++PI) { - // FIXME: selector is missing here! + // FIXME: selector is missing here! pos = name.find_first_of(":", lastPos); Out << " " << name.substr(lastPos, pos - lastPos); Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" - << (*PI)->getNameAsString(); + << (*PI)->getNameAsString(); lastPos = pos + 1; } - + if (OMD->param_begin() == OMD->param_end()) Out << " " << name; - + if (OMD->isVariadic()) Out << ", ..."; - + if (OMD->getBody()) { Out << ' '; OMD->getBody()->printPretty(Out, Context, 0, Policy); @@ -623,7 +717,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Out << "@interface " << I << " : " << SID->getNameAsString(); else Out << "@interface " << I; - + // Protocols? const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); if (!Protocols.empty()) { @@ -631,22 +725,22 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { E = Protocols.end(); I != E; ++I) Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); } - + if (!Protocols.empty()) Out << "> "; - + if (OID->ivar_size() > 0) { Out << "{\n"; Indentation += Policy.Indentation; for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), E = OID->ivar_end(); I != E; ++I) { Indent() << (*I)->getType().getAsString(Policy) - << ' ' << (*I)->getNameAsString() << ";\n"; + << ' ' << (*I)->getNameAsString() << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; } - + VisitDeclContext(OID, false); Out << "@end"; // FIXME: implement the rest... @@ -654,7 +748,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { Out << "@protocol "; - for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; @@ -671,7 +765,7 @@ void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { Out << "@implementation " << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + << '(' << PID->getNameAsString() << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -679,18 +773,18 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " + Out << "@interface " << PID->getClassInterface()->getNameAsString() << '(' << PID->getNameAsString() << ")\n"; VisitDeclContext(PID, false); Out << "@end"; - + // FIXME: implement the rest... } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID->getNameAsString() - << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; + Out << "@compatibility_alias " << AID->getNameAsString() + << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -700,17 +794,17 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { Out << "@required\n"; else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional) Out << "@optional\n"; - + Out << "@property"; if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { bool first = true; Out << " ("; - if (PDecl->getPropertyAttributes() & + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) { Out << (first ? ' ' : ',') << "readonly"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { Out << (first ? ' ' : ',') << "getter = " << PDecl->getGetterName().getAsString(); @@ -721,29 +815,29 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { << PDecl->getSetterName().getAsString(); first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { Out << (first ? ' ' : ',') << "assign"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) { Out << (first ? ' ' : ',') << "readwrite"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { Out << (first ? ' ' : ',') << "retain"; first = false; } - + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { Out << (first ? ' ' : ',') << "copy"; first = false; } - - if (PDecl->getPropertyAttributes() & + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) { Out << (first ? ' ' : ',') << "nonatomic"; first = false; @@ -763,3 +857,15 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { if (PID->getPropertyIvarDecl()) Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); } + +void DeclPrinter::VisitUsingDecl(UsingDecl *D) { + Out << "using "; + D->getTargetNestedNameDecl()->print(Out, Policy); + Out << D->getTargetDecl()->getNameAsString(); +} + +void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { + Out << "using "; + D->getTargetNestedNameSpecifier()->print(Out, Policy); + Out << D->getTargetName().getAsString(); +} diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index f1bd1b67d21e..7836b3f827ce 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -25,7 +25,7 @@ using namespace clang; TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, - Decl **Params, unsigned NumParams, + NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumParams(NumParams) { @@ -35,31 +35,32 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, TemplateParameterList * TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, Decl **Params, + SourceLocation LAngleLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) { - unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams; + unsigned Size = sizeof(TemplateParameterList) + + sizeof(NamedDecl *) * NumParams; unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment; void *Mem = C.Allocate(Size, Align); - return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, + return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, NumParams, RAngleLoc); } unsigned TemplateParameterList::getMinRequiredArguments() const { unsigned NumRequiredArgs = size(); - iterator Param = const_cast<TemplateParameterList *>(this)->end(), + iterator Param = const_cast<TemplateParameterList *>(this)->end(), ParamBegin = const_cast<TemplateParameterList *>(this)->begin(); while (Param != ParamBegin) { --Param; - + if (!(*Param)->isTemplateParameterPack() && - !(isa<TemplateTypeParmDecl>(*Param) && + !(isa<TemplateTypeParmDecl>(*Param) && cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) && !(isa<NonTypeTemplateParmDecl>(*Param) && cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) && !(isa<TemplateTemplateParmDecl>(*Param) && cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument())) break; - + --NumRequiredArgs; } @@ -94,16 +95,23 @@ void FunctionTemplateDecl::Destroy(ASTContext &C) { Spec != SpecEnd; ++Spec) C.Deallocate(&*Spec); } - + Decl::Destroy(C); } +FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() { + FunctionTemplateDecl *FunTmpl = this; + while (FunTmpl->getPreviousDeclaration()) + FunTmpl = FunTmpl->getPreviousDeclaration(); + return FunTmpl; +} + FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { // Find the first declaration of this function template. FunctionTemplateDecl *First = this; while (First->getPreviousDeclaration()) First = First->getPreviousDeclaration(); - + if (First->CommonOrPrev.isNull()) { // FIXME: Allocate with the ASTContext First->CommonOrPrev = new Common; @@ -115,6 +123,13 @@ FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// +ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() { + ClassTemplateDecl *Template = this; + while (Template->getPreviousDeclaration()) + Template = Template->getPreviousDeclaration(); + return Template; +} + ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -128,7 +143,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, else CommonPtr = new (C) Common; - return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, + return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, CommonPtr); } @@ -147,6 +162,21 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecialization(QualType T) { + ASTContext &Context = getASTContext(); + typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + partial_spec_iterator; + for (partial_spec_iterator P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (Context.hasSameType(Context.getTypeDeclType(&*P), T)) + return &*P; + } + + return 0; +} + QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; @@ -157,52 +187,32 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { // better to fix that redundancy. TemplateParameterList *Params = getTemplateParameters(); - llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs; TemplateArgs.reserve(Params->size()); - CanonTemplateArgs.reserve(Params->size()); - - for (TemplateParameterList::iterator - Param = Params->begin(), ParamEnd = Params->end(); + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); Param != ParamEnd; ++Param) { if (isa<TemplateTypeParmDecl>(*Param)) { QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); - TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), + TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), ParamType)); - CanonTemplateArgs.push_back( - TemplateArgument((*Param)->getLocation(), - Context.getCanonicalType(ParamType))); - } else if (NonTypeTemplateParmDecl *NTTP = + } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - // FIXME: Build canonical expression, too! Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), NTTP->getLocation(), NTTP->getType()->isDependentType(), /*Value-dependent=*/true); TemplateArgs.push_back(TemplateArgument(E)); - CanonTemplateArgs.push_back(TemplateArgument(E)); - } else { + } else { TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); - CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), - Context.getCanonicalDecl(TTP))); } } - // FIXME: I should really move the "build-the-canonical-type" logic - // into ASTContext::getTemplateSpecializationType. - TemplateName Name = TemplateName(this); - QualType CanonType = Context.getTemplateSpecializationType( - Context.getCanonicalTemplateName(Name), - &CanonTemplateArgs[0], - CanonTemplateArgs.size()); - CommonPtr->InjectedClassNameType - = Context.getTemplateSpecializationType(Name, + = Context.getTemplateSpecializationType(TemplateName(this), &TemplateArgs[0], - TemplateArgs.size(), - CanonType); + TemplateArgs.size()); return CommonPtr->InjectedClassNameType; } @@ -227,14 +237,13 @@ NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - SourceLocation TypeSpecStartLoc) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, - TypeSpecStartLoc); + DeclaratorInfo *DInfo) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, DInfo); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); + : SourceLocation(); } //===----------------------------------------------------------------------===// @@ -251,7 +260,7 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { return DefaultArgument? DefaultArgument->getSourceRange().getBegin() - : SourceLocation(); + : SourceLocation(); } //===----------------------------------------------------------------------===// @@ -264,10 +273,10 @@ TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { } /// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, +void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, bool CopyArgs) { assert(isNull() && "Must call setArgumentPack on a null argument"); - + Kind = Pack; Args.NumArgs = NumArgs; Args.CopyArgs = CopyArgs; @@ -275,7 +284,8 @@ void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, Args.Args = args; return; } - + + // FIXME: Allocate in ASTContext Args.Args = new TemplateArgument[NumArgs]; for (unsigned I = 0; I != Args.NumArgs; ++I) Args.Args[I] = args[I]; @@ -292,21 +302,21 @@ void TemplateArgumentListBuilder::Append(const TemplateArgument& Arg) { assert(Arg.getAsType()->isCanonical() && "Type must be canonical!"); break; } - + assert(NumFlatArgs < MaxFlatArgs && "Argument list builder is full!"); - assert(!StructuredArgs && + assert(!StructuredArgs && "Can't append arguments when an argument pack has been added!"); - + if (!FlatArgs) FlatArgs = new TemplateArgument[MaxFlatArgs]; - + FlatArgs[NumFlatArgs++] = Arg; } void TemplateArgumentListBuilder::BeginPack() { assert(!AddingToPack && "Already adding to pack!"); assert(!StructuredArgs && "Argument list already contains a pack!"); - + AddingToPack = true; PackBeginIndex = NumFlatArgs; } @@ -314,24 +324,24 @@ void TemplateArgumentListBuilder::BeginPack() { void TemplateArgumentListBuilder::EndPack() { assert(AddingToPack && "Not adding to pack!"); assert(!StructuredArgs && "Argument list already contains a pack!"); - + AddingToPack = false; StructuredArgs = new TemplateArgument[MaxStructuredArgs]; - + // First copy the flat entries over to the list (if any) for (unsigned I = 0; I != PackBeginIndex; ++I) { NumStructuredArgs++; StructuredArgs[I] = FlatArgs[I]; } - + // Next, set the pack. TemplateArgument *PackArgs = 0; unsigned NumPackArgs = NumFlatArgs - PackBeginIndex; if (NumPackArgs) PackArgs = &FlatArgs[PackBeginIndex]; - - StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, + + StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs, /*CopyArgs=*/false); } @@ -350,19 +360,25 @@ void TemplateArgumentListBuilder::ReleaseArgs() { TemplateArgumentList::TemplateArgumentList(ASTContext &Context, TemplateArgumentListBuilder &Builder, bool TakeArgs) - : FlatArguments(Builder.getFlatArguments(), TakeArgs), - NumFlatArguments(Builder.flatSize()), + : FlatArguments(Builder.getFlatArguments(), TakeArgs), + NumFlatArguments(Builder.flatSize()), StructuredArguments(Builder.getStructuredArguments(), TakeArgs), NumStructuredArguments(Builder.structuredSize()) { - + if (!TakeArgs) return; - + if (Builder.getStructuredArguments() == Builder.getFlatArguments()) StructuredArguments.setInt(0); Builder.ReleaseArgs(); } +TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other) + : FlatArguments(Other.FlatArguments.getPointer(), 1), + NumFlatArguments(Other.flat_size()), + StructuredArguments(Other.StructuredArguments.getPointer(), 1), + NumStructuredArguments(Other.NumStructuredArguments) { } + TemplateArgumentList::~TemplateArgumentList() { // FIXME: Deallocate template arguments } @@ -374,34 +390,66 @@ ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, - TemplateArgumentListBuilder &Builder) - : CXXRecordDecl(DK, - SpecializedTemplate->getTemplatedDecl()->getTagKind(), + TemplateArgumentListBuilder &Builder, + ClassTemplateSpecializationDecl *PrevDecl) + : CXXRecordDecl(DK, + SpecializedTemplate->getTemplatedDecl()->getTagKind(), DC, L, // FIXME: Should we use DeclarationName for the name of // class template specializations? - SpecializedTemplate->getIdentifier()), + SpecializedTemplate->getIdentifier(), + PrevDecl), SpecializedTemplate(SpecializedTemplate), TemplateArgs(Context, Builder, /*TakeArgs=*/true), SpecializationKind(TSK_Undeclared) { } - + ClassTemplateSpecializationDecl * -ClassTemplateSpecializationDecl::Create(ASTContext &Context, +ClassTemplateSpecializationDecl::Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl) { ClassTemplateSpecializationDecl *Result - = new (Context)ClassTemplateSpecializationDecl(Context, + = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, - DC, L, + DC, L, SpecializedTemplate, - Builder); + Builder, + PrevDecl); Context.getTypeDeclType(Result, PrevDecl); return Result; } +void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + C.Deallocate(PartialSpec); + + CXXRecordDecl::Destroy(C); +} + +void +ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); +} + +ClassTemplateDecl * +ClassTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<ClassTemplateDecl*>(); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// @@ -413,11 +461,27 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateArgumentListBuilder &Builder, ClassTemplatePartialSpecializationDecl *PrevDecl) { ClassTemplatePartialSpecializationDecl *Result - = new (Context)ClassTemplatePartialSpecializationDecl(Context, + = new (Context)ClassTemplatePartialSpecializationDecl(Context, DC, L, Params, SpecializedTemplate, - Builder); + Builder, PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getTypeDeclType(Result, PrevDecl); return Result; } + +//===----------------------------------------------------------------------===// +// FriendTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + DeclContext *DC, + SourceLocation L, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FLoc) { + FriendTemplateDecl *Result + = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc); + return Result; +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index a17abde77730..101ddd250933 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -23,7 +23,7 @@ namespace clang { /// CXXSpecialName - Records the type associated with one of the /// "special" kinds of declaration names in C++, e.g., constructors, /// destructors, and conversion functions. -class CXXSpecialName +class CXXSpecialName : public DeclarationNameExtra, public llvm::FoldingSetNode { public: /// Type - The type associated with this declaration name. @@ -40,7 +40,7 @@ public: }; /// CXXOperatorIdName - Contains extra information for the name of an -/// overloaded operator in C++, such as "operator+. +/// overloaded operator in C++, such as "operator+. class CXXOperatorIdName : public DeclarationNameExtra { public: /// FETokenInfo - Extra information associated with this operator @@ -93,13 +93,13 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case StoredDeclarationNameExtra: switch (getExtra()->ExtraKindOrNumArgs) { - case DeclarationNameExtra::CXXConstructor: + case DeclarationNameExtra::CXXConstructor: return CXXConstructorName; - case DeclarationNameExtra::CXXDestructor: + case DeclarationNameExtra::CXXDestructor: return CXXDestructorName; - case DeclarationNameExtra::CXXConversionFunction: + case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; case DeclarationNameExtra::CXXUsingDirective: @@ -107,7 +107,7 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { default: // Check if we have one of the CXXOperator* enumeration values. - if (getExtra()->ExtraKindOrNumArgs < + if (getExtra()->ExtraKindOrNumArgs < DeclarationNameExtra::CXXUsingDirective) return CXXOperatorName; @@ -135,7 +135,7 @@ std::string DeclarationName::getAsString() const { case CXXConstructorName: { QualType ClassType = getCXXNameType(); - if (const RecordType *ClassRec = ClassType->getAsRecordType()) + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) return ClassRec->getDecl()->getNameAsString(); return ClassType.getAsString(); } @@ -143,7 +143,7 @@ std::string DeclarationName::getAsString() const { case CXXDestructorName: { std::string Result = "~"; QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAsRecordType()) + if (const RecordType *Rec = Type->getAs<RecordType>()) Result += Rec->getDecl()->getNameAsString(); else Result += Type.getAsString(); @@ -159,7 +159,7 @@ std::string DeclarationName::getAsString() const { }; const char *OpName = OperatorNames[getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); - + std::string Result = "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') Result += ' '; @@ -170,7 +170,7 @@ std::string DeclarationName::getAsString() const { case CXXConversionFunctionName: { std::string Result = "operator "; QualType Type = getCXXNameType(); - if (const RecordType *Rec = Type->getAsRecordType()) + if (const RecordType *Rec = Type->getAs<RecordType>()) Result += Rec->getDecl()->getNameAsString(); else Result += Type.getAsString(); @@ -193,7 +193,7 @@ QualType DeclarationName::getCXXNameType() const { OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) { - unsigned value + unsigned value = CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction; return static_cast<OverloadedOperatorKind>(value); } else { @@ -276,7 +276,7 @@ DeclarationNameTable::DeclarationNameTable() { // Initialize the overloaded operator names. CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) { - CXXOperatorNames[Op].ExtraKindOrNumArgs + CXXOperatorNames[Op].ExtraKindOrNumArgs = Op + DeclarationNameExtra::CXXConversionFunction; CXXOperatorNames[Op].FETokenInfo = 0; } @@ -296,26 +296,24 @@ DeclarationNameTable::~DeclarationNameTable() { delete [] CXXOperatorNames; } -DeclarationName -DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, - QualType Ty) { +DeclarationName +DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty) { assert(Kind >= DeclarationName::CXXConstructorName && Kind <= DeclarationName::CXXConversionFunctionName && "Kind must be a C++ special name kind"); - assert(Ty->isCanonical() && - "Can only build C++ special names from canonical types"); - llvm::FoldingSet<CXXSpecialName> *SpecialNames + llvm::FoldingSet<CXXSpecialName> *SpecialNames = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); DeclarationNameExtra::ExtraKind EKind; switch (Kind) { - case DeclarationName::CXXConstructorName: + case DeclarationName::CXXConstructorName: EKind = DeclarationNameExtra::CXXConstructor; - assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified"); + assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified"); break; case DeclarationName::CXXDestructorName: EKind = DeclarationNameExtra::CXXDestructor; - assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified"); + assert(!Ty.hasQualifiers() && "Destructor type must be unqualified"); break; case DeclarationName::CXXConversionFunctionName: EKind = DeclarationNameExtra::CXXConversionFunction; @@ -342,12 +340,12 @@ DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, return DeclarationName(SpecialName); } -DeclarationName +DeclarationName DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { return DeclarationName(&CXXOperatorNames[(unsigned)Op]); } -unsigned +unsigned llvm::DenseMapInfo<clang::DeclarationName>:: getHashValue(clang::DeclarationName N) { return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr()); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 482e1062d88c..0e4a29f916fa 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -21,6 +22,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; @@ -28,34 +30,80 @@ using namespace clang; // Primary Expressions. //===----------------------------------------------------------------------===// -PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const { - return new (C) PredefinedExpr(Loc, getType(), Type); -} +// FIXME: Maybe this should use DeclPrinter with a special "print predefined +// expr" policy instead. +std::string PredefinedExpr::ComputeName(ASTContext &Context, IdentType IT, + const Decl *CurrentDecl) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { + if (IT != PrettyFunction) + return FD->getNameAsString(); -IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const { - return new (C) IntegerLiteral(Value, getType(), Loc); -} + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); -CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const { - return new (C) CharacterLiteral(Value, IsWide, getType(), Loc); -} + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isVirtual()) + Out << "virtual "; + } -FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const { - return new (C) FloatingLiteral(Value, IsExact, getType(), Loc); -} + PrintingPolicy Policy(Context.getLangOptions()); + Policy.SuppressTagKind = true; -ImaginaryLiteral* ImaginaryLiteral::Clone(ASTContext &C) const { - // FIXME: Use virtual Clone(), once it is available - Expr *ClonedVal = 0; - if (const IntegerLiteral *IntLit = dyn_cast<IntegerLiteral>(Val)) - ClonedVal = IntLit->Clone(C); - else - ClonedVal = cast<FloatingLiteral>(Val)->Clone(C); - return new (C) ImaginaryLiteral(ClonedVal, getType()); -} + std::string Proto = FD->getQualifiedNameAsString(Policy); + + const FunctionType *AFT = FD->getType()->getAs<FunctionType>(); + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast<FunctionProtoType>(AFT); + + Proto += "("; + if (FT) { + llvm::raw_string_ostream POut(Proto); + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { + if (i) POut << ", "; + std::string Param; + FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy); + POut << Param; + } + + if (FT->isVariadic()) { + if (FD->getNumParams()) POut << ", "; + POut << "..."; + } + } + Proto += ")"; -GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const { - return new (C) GNUNullExpr(getType(), TokenLoc); + AFT->getResultType().getAsStringInternal(Proto, Policy); + + Out << Proto; + + Out.flush(); + return Name.str().str(); + } + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) { + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); + Out << (MD->isInstanceMethod() ? '-' : '+'); + Out << '['; + Out << MD->getClassInterface()->getNameAsString(); + if (const ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) { + Out << '('; + Out << CID->getNameAsString(); + Out << ')'; + } + Out << ' '; + Out << MD->getSelector().getAsString(); + Out << ']'; + + Out.flush(); + return Name.str().str(); + } + if (isa<TranslationUnitDecl>(CurrentDecl) && IT == PrettyFunction) { + // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. + return "top level"; + } + return ""; } /// getValueAsApproximateDouble - This returns the value as an inaccurate @@ -72,7 +120,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const { StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, unsigned ByteLength, bool Wide, QualType Ty, - const SourceLocation *Loc, + const SourceLocation *Loc, unsigned NumStrs) { // Allocate enough space for the StringLiteral plus an array of locations for // any concatenated string tokens. @@ -80,7 +128,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, sizeof(SourceLocation)*(NumStrs-1), llvm::alignof<StringLiteral>()); StringLiteral *SL = new (Mem) StringLiteral(Ty); - + // OPTIMIZE: could allocate this appended to the StringLiteral. char *AStrData = new (C, 1) char[ByteLength]; memcpy(AStrData, StrData, ByteLength); @@ -106,25 +154,19 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { return SL; } -StringLiteral* StringLiteral::Clone(ASTContext &C) const { - return Create(C, StrData, ByteLength, IsWide, getType(), - TokLocs, NumConcatenated); -} - -void StringLiteral::Destroy(ASTContext &C) { +void StringLiteral::DoDestroy(ASTContext &C) { C.Deallocate(const_cast<char*>(StrData)); - this->~StringLiteral(); - C.Deallocate(this); + Expr::DoDestroy(C); } -void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) { +void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { if (StrData) C.Deallocate(const_cast<char*>(StrData)); - char *AStrData = new (C, 1) char[Len]; - memcpy(AStrData, Str, Len); + char *AStrData = new (C, 1) char[Str.size()]; + memcpy(AStrData, Str.data(), Str.size()); StrData = AStrData; - ByteLength = Len; + ByteLength = Str.size(); } /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it @@ -149,7 +191,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) { } } -UnaryOperator::Opcode +UnaryOperator::Opcode UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { switch (OO) { default: assert(false && "No unary operator for overloaded function"); @@ -185,11 +227,11 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, unsigned numargs, QualType t, SourceLocation rparenloc) - : Expr(SC, t, + : Expr(SC, t, fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), NumArgs(numargs) { - + SubExprs = new (C) Stmt*[numargs+1]; SubExprs[FN] = fn; for (unsigned i = 0; i != numargs; ++i) @@ -213,25 +255,33 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext &C, EmptyShell Empty) - : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) { +CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), SubExprs(0), NumArgs(0) { SubExprs = new (C) Stmt*[1]; } -void CallExpr::Destroy(ASTContext& C) { +void CallExpr::DoDestroy(ASTContext& C) { DestroyChildren(C); if (SubExprs) C.Deallocate(SubExprs); this->~CallExpr(); C.Deallocate(this); } +FunctionDecl *CallExpr::getDirectCallee() { + Expr *CEE = getCallee()->IgnoreParenCasts(); + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) + return dyn_cast<FunctionDecl>(DRE->getDecl()); + + return 0; +} + /// setNumArgs - This changes the number of arguments present in this call. /// Any orphaned expressions are deleted by this, and any new operands are set /// to null. void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { // No change, just return. if (NumArgs == getNumArgs()) return; - + // If shrinking # arguments, just delete the extras and forgot them. if (NumArgs < getNumArgs()) { for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) @@ -241,14 +291,14 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { } // Otherwise, we are growing the # arguments. New an bigger argument array. - Stmt **NewSubExprs = new Stmt*[NumArgs+1]; + Stmt **NewSubExprs = new (C) Stmt*[NumArgs+1]; // Copy over args. for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) NewSubExprs[i] = SubExprs[i]; // Null out new args. for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) NewSubExprs[i] = 0; - + if (SubExprs) C.Deallocate(SubExprs); SubExprs = NewSubExprs; this->NumArgs = NumArgs; @@ -258,37 +308,130 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { /// not, return 0. unsigned CallExpr::isBuiltinCall(ASTContext &Context) const { // All simple function calls (e.g. func()) are implicitly cast to pointer to - // function. As a result, we try and obtain the DeclRefExpr from the + // function. As a result, we try and obtain the DeclRefExpr from the // ImplicitCastExpr. const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee()); if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). return 0; - + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); if (!DRE) return 0; - + const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); if (!FDecl) return 0; - + if (!FDecl->getIdentifier()) return 0; - return FDecl->getBuiltinID(Context); + return FDecl->getBuiltinID(); } QualType CallExpr::getCallReturnType() const { QualType CalleeType = getCallee()->getType(); - if (const PointerType *FnTypePtr = CalleeType->getAsPointerType()) + if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>()) CalleeType = FnTypePtr->getPointeeType(); - else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType()) + else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>()) CalleeType = BPT->getPointeeType(); - - const FunctionType *FnType = CalleeType->getAsFunctionType(); + + const FunctionType *FnType = CalleeType->getAs<FunctionType>(); return FnType->getResultType(); } +MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, + SourceRange qualrange, NamedDecl *memberdecl, + SourceLocation l, bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, unsigned numtargs, + SourceLocation rangle, QualType ty) + : Expr(MemberExprClass, ty, + base->isTypeDependent() || (qual && qual->isDependent()), + base->isValueDependent() || (qual && qual->isDependent())), + Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), + HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) { + // Initialize the qualifier, if any. + if (HasQualifier) { + NameQualifier *NQ = getMemberQualifier(); + NQ->NNS = qual; + NQ->Range = qualrange; + } + + // Initialize the explicit template argument list, if any. + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = langle; + ETemplateArgs->RAngleLoc = rangle; + ETemplateArgs->NumTemplateArgs = numtargs; + + TemplateArgument *TemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < numtargs; ++I) + new (TemplateArgs + I) TemplateArgument(targs[I]); + } +} + +MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, + NestedNameSpecifier *qual, + SourceRange qualrange, + NamedDecl *memberdecl, + SourceLocation l, + bool has_explicit, + SourceLocation langle, + const TemplateArgument *targs, + unsigned numtargs, + SourceLocation rangle, + QualType ty) { + std::size_t Size = sizeof(MemberExpr); + if (qual != 0) + Size += sizeof(NameQualifier); + + if (has_explicit) + Size += sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgument) * numtargs; + + void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>()); + return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, + has_explicit, langle, targs, numtargs, rangle, + ty); +} + +const char *CastExpr::getCastKindName() const { + switch (getCastKind()) { + case CastExpr::CK_Unknown: + return "Unknown"; + case CastExpr::CK_BitCast: + return "BitCast"; + case CastExpr::CK_NoOp: + return "NoOp"; + case CastExpr::CK_DerivedToBase: + return "DerivedToBase"; + case CastExpr::CK_Dynamic: + return "Dynamic"; + case CastExpr::CK_ToUnion: + return "ToUnion"; + case CastExpr::CK_ArrayToPointerDecay: + return "ArrayToPointerDecay"; + case CastExpr::CK_FunctionToPointerDecay: + return "FunctionToPointerDecay"; + case CastExpr::CK_NullToMemberPointer: + return "NullToMemberPointer"; + case CastExpr::CK_BaseToDerivedMemberPointer: + return "BaseToDerivedMemberPointer"; + case CastExpr::CK_UserDefinedConversion: + return "UserDefinedConversion"; + case CastExpr::CK_ConstructorConversion: + return "ConstructorConversion"; + case CastExpr::CK_IntegralToPointer: + return "IntegralToPointer"; + case CastExpr::CK_PointerToIntegral: + return "PointerToIntegral"; + } + + assert(0 && "Unhandled cast kind!"); + return 0; +} + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { @@ -330,7 +473,7 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) { return ""; } -BinaryOperator::Opcode +BinaryOperator::Opcode BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { switch (OO) { default: assert(false && "Not an overloadable binary operator"); @@ -392,13 +535,13 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(SourceLocation lbraceloc, +InitListExpr::InitListExpr(SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), hasAnyTypeDependentArguments(initExprs, numInits), hasAnyValueDependentArguments(initExprs, numInits)), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); @@ -422,7 +565,7 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { InitExprs.back() = expr; return 0; } - + Expr *Result = cast_or_null<Expr>(InitExprs[Init]); InitExprs[Init] = expr; return Result; @@ -431,18 +574,18 @@ Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { /// getFunctionType - Return the underlying function type for this block. /// const FunctionType *BlockExpr::getFunctionType() const { - return getType()->getAsBlockPointerType()-> - getPointeeType()->getAsFunctionType(); + return getType()->getAs<BlockPointerType>()-> + getPointeeType()->getAs<FunctionType>(); } -SourceLocation BlockExpr::getCaretLocation() const { - return TheBlock->getCaretLocation(); +SourceLocation BlockExpr::getCaretLocation() const { + return TheBlock->getCaretLocation(); } -const Stmt *BlockExpr::getBody() const { +const Stmt *BlockExpr::getBody() const { return TheBlock->getBody(); } -Stmt *BlockExpr::getBody() { - return TheBlock->getBody(); +Stmt *BlockExpr::getBody() { + return TheBlock->getBody(); } @@ -460,7 +603,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // instantiating to void. if (isTypeDependent()) return false; - + switch (getStmtClass()) { default: Loc = getExprLoc(); @@ -471,7 +614,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, isUnusedResultAWarning(Loc, R1, R2); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); - + switch (UO->getOpcode()) { default: break; case UnaryOperator::PostInc: @@ -503,7 +646,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (BO->getOpcode() == BinaryOperator::Comma) return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); - + if (BO->isAssignmentOp()) return false; Loc = BO->getOperatorLoc(); @@ -518,7 +661,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // The condition must be evaluated, but if either the LHS or RHS is a // warning, warn about them. const ConditionalOperator *Exp = cast<ConditionalOperator>(this); - if (Exp->getLHS() && + if (Exp->getLHS() && Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) return true; return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); @@ -533,7 +676,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, R1 = SourceRange(Loc, Loc); R2 = cast<MemberExpr>(this)->getBase()->getSourceRange(); return true; - + case ArraySubscriptExprClass: // If the base pointer or element is to a volatile pointer/field, accessing // it is a side effect. @@ -549,26 +692,43 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXMemberCallExprClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); - const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); - if (const DeclRefExpr *CalleeDRE = dyn_cast<DeclRefExpr>(CalleeExpr)) { + if (const FunctionDecl *FD = CE->getDirectCallee()) { // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeDRE->getDecl())) - if (FD->getAttr<WarnUnusedResultAttr>() || - FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { - Loc = CE->getCallee()->getLocStart(); - R1 = CE->getCallee()->getSourceRange(); - - if (unsigned NumArgs = CE->getNumArgs()) - R2 = SourceRange(CE->getArg(0)->getLocStart(), - CE->getArg(NumArgs-1)->getLocEnd()); - return true; - } + // + // Note: If new cases are added here, DiagnoseUnusedExprResult should be + // updated to match for QoI. + if (FD->getAttr<WarnUnusedResultAttr>() || + FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { + Loc = CE->getCallee()->getLocStart(); + R1 = CE->getCallee()->getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getLocStart(), + CE->getArg(NumArgs-1)->getLocEnd()); + return true; + } } return false; } case ObjCMessageExprClass: return false; + + case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send. +#if 0 + const ObjCImplicitSetterGetterRefExpr *Ref = + cast<ObjCImplicitSetterGetterRefExpr>(this); + // FIXME: We really want the location of the '.' here. + Loc = Ref->getLocation(); + R1 = SourceRange(Ref->getLocation(), Ref->getLocation()); + if (Ref->getBase()) + R2 = Ref->getBase()->getSourceRange(); +#else + Loc = getExprLoc(); + R1 = getSourceRange(); +#endif + return true; + } case StmtExprClass: { // Statement exprs don't logically have side effects themselves, but are // sometimes used in macros in ways that give them a type that is unused. @@ -579,17 +739,16 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, if (!CS->body_empty()) if (const Expr *E = dyn_cast<Expr>(CS->body_back())) return E->isUnusedResultAWarning(Loc, R1, R2); - + Loc = cast<StmtExpr>(this)->getLParenLoc(); R1 = getSourceRange(); return true; } case CStyleCastExprClass: - // If this is a cast to void, check the operand. Otherwise, the result of - // the cast is unused. + // If this is an explicit cast to void, allow it. People do this when they + // think they know what they're doing :). if (getType()->isVoidType()) - return cast<CastExpr>(this)->getSubExpr() - ->isUnusedResultAWarning(Loc, R1, R2); + return false; Loc = cast<CStyleCastExpr>(this)->getLParenLoc(); R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); return true; @@ -602,7 +761,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); return true; - + case ImplicitCastExprClass: // Check the operand, since implicit casts are inserted by Sema return cast<ImplicitCastExpr>(this) @@ -617,6 +776,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // effects (e.g. a placement new with an uninitialized POD). case CXXDeleteExprClass: return false; + case CXXBindTemporaryExprClass: + return cast<CXXBindTemporaryExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); case CXXExprWithTemporariesClass: return cast<CXXExprWithTemporaries>(this) ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); @@ -628,14 +790,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { // C++ [temp.param]p6: // A non-type non-reference template-parameter is not an lvalue. - if (const NonTypeTemplateParmDecl *NTTParm + if (const NonTypeTemplateParmDecl *NTTParm = dyn_cast<NonTypeTemplateParmDecl>(Decl)) return NTTParm->getType()->isReferenceType(); return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl))); + (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl) || + isa<FunctionTemplateDecl>(Decl))); } /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an @@ -659,11 +822,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // first, check the type (C99 6.3.2.1). Expressions with function // type in C are not lvalues, but they can be lvalues in C++. - if (TR->isFunctionType()) + if (TR->isFunctionType() || TR == Ctx.OverloadTy) return LV_NotObjectType; // Allow qualified void which is an incomplete type other than void (yuck). - if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) + if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) return LV_IncompleteVoidType; return LV_Valid; @@ -680,7 +843,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx); return LV_Valid; - case DeclRefExprClass: + case DeclRefExprClass: case QualifiedDeclRefExprClass: { // C99 6.5.1p2 const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl(); if (DeclCanBeLvalue(RefdDecl, Ctx)) @@ -693,7 +856,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; break; } - case MemberExprClass: { + case MemberExprClass: { const MemberExpr *m = cast<MemberExpr>(this); if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4: NamedDecl *Member = m->getMemberDecl(); @@ -727,7 +890,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // Not an lvalue. return LV_InvalidExpression; - } + } // C99 6.5.2.3p4 return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); @@ -747,7 +910,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; break; case ImplicitCastExprClass: - return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid + return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid : LV_InvalidExpression; case ParenExprClass: // C99 6.5.1p5 return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx); @@ -760,16 +923,26 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return BinOp->getRHS()->isLvalue(Ctx); // C++ [expr.mptr.oper]p6 - if ((BinOp->getOpcode() == BinaryOperator::PtrMemD || - BinOp->getOpcode() == BinaryOperator::PtrMemI) && + // The result of a .* expression is an lvalue only if its first operand is + // an lvalue and its second operand is a pointer to data member. + if (BinOp->getOpcode() == BinaryOperator::PtrMemD && !BinOp->getType()->isFunctionType()) return BinOp->getLHS()->isLvalue(Ctx); + // The result of an ->* expression is an lvalue only if its second operand + // is a pointer to data member. + if (BinOp->getOpcode() == BinaryOperator::PtrMemI && + !BinOp->getType()->isFunctionType()) { + QualType Ty = BinOp->getRHS()->getType(); + if (Ty->isMemberPointerType() && !Ty->isMemberFunctionPointerType()) + return LV_Valid; + } + if (!BinOp->isAssignmentOp()) return LV_InvalidExpression; if (Ctx.getLangOptions().CPlusPlus) - // C++ [expr.ass]p1: + // C++ [expr.ass]p1: // The result of an assignment operation [...] is an lvalue. return LV_Valid; @@ -778,7 +951,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { // An assignment expression [...] is not an lvalue. return LV_InvalidExpression; } - case CallExprClass: + case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: { // C++0x [expr.call]p10 @@ -803,7 +976,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case ObjCPropertyRefExprClass: // FIXME: check if read-only property. return LV_Valid; - case ObjCKVCRefExprClass: // FIXME: check if read-only property. + case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property. return LV_Valid; case PredefinedExprClass: return LV_Valid; @@ -828,6 +1001,9 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { case CXXTypeidExprClass: // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ... return LV_Valid; + case CXXBindTemporaryExprClass: + return cast<CXXBindTemporaryExpr>(this)->getSubExpr()-> + isLvalueInternal(Ctx); case ConditionalOperatorClass: { // Complicated handling is only for C++. if (!Ctx.getLangOptions().CPlusPlus) @@ -862,15 +1038,15 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, /// does not have an incomplete type, does not have a const-qualified type, and -/// if it is a structure or union, does not have any member (including, +/// if it is a structure or union, does not have any member (including, /// recursively, any member or element of all contained aggregates or unions) /// with a const-qualified type. -Expr::isModifiableLvalueResult +Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { isLvalueResult lvalResult = isLvalue(Ctx); - + switch (lvalResult) { - case LV_Valid: + case LV_Valid: // C++ 3.10p11: Functions cannot be modified, but pointers to // functions can be modifiable. if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType()) @@ -900,74 +1076,37 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { // void takeclosure(void (^C)(void)); // void func() { int x = 1; takeclosure(^{ x = 7; }); } // - if (isa<BlockDeclRefExpr>(this)) { - const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this); + if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(this)) { if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl())) return MLV_NotBlockQualified; } + // Assigning to an 'implicit' property? + if (const ObjCImplicitSetterGetterRefExpr* Expr = + dyn_cast<ObjCImplicitSetterGetterRefExpr>(this)) { + if (Expr->getSetterMethod() == 0) + return MLV_NoSetterProperty; + } + QualType CT = Ctx.getCanonicalType(getType()); - + if (CT.isConstQualified()) return MLV_ConstQualified; if (CT->isArrayType()) return MLV_ArrayType; if (CT->isIncompleteType()) return MLV_IncompleteType; - - if (const RecordType *r = CT->getAsRecordType()) { - if (r->hasConstFields()) + + if (const RecordType *r = CT->getAs<RecordType>()) { + if (r->hasConstFields()) return MLV_ConstQualified; } - - // Assigning to an 'implicit' property? - else if (isa<ObjCKVCRefExpr>(this)) { - const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this); - if (KVCExpr->getSetterMethod() == 0) - return MLV_NoSetterProperty; - } - return MLV_Valid; -} -/// hasGlobalStorage - Return true if this expression has static storage -/// duration. This means that the address of this expression is a link-time -/// constant. -bool Expr::hasGlobalStorage() const { - switch (getStmtClass()) { - default: - return false; - case BlockExprClass: - return true; - case ParenExprClass: - return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage(); - case ImplicitCastExprClass: - return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage(); - case CompoundLiteralExprClass: - return cast<CompoundLiteralExpr>(this)->isFileScope(); - case DeclRefExprClass: - case QualifiedDeclRefExprClass: { - const Decl *D = cast<DeclRefExpr>(this)->getDecl(); - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) - return VD->hasGlobalStorage(); - if (isa<FunctionDecl>(D)) - return true; - return false; - } - case MemberExprClass: { - const MemberExpr *M = cast<MemberExpr>(this); - return !M->isArrow() && M->getBase()->hasGlobalStorage(); - } - case ArraySubscriptExprClass: - return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage(); - case PredefinedExprClass: - return true; - case CXXDefaultArgExprClass: - return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage(); - } + return MLV_Valid; } /// isOBJCGCCandidate - Check if an expression is objc gc'able. -/// +/// returns true, if it is; false otherwise. bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { switch (getStmtClass()) { default: @@ -989,11 +1128,10 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { if (VD->hasGlobalStorage()) return true; QualType T = VD->getType(); - // dereferencing to an object pointer is always a gc'able candidate - if (T->isPointerType() && - Ctx.isObjCObjectPointerType(T->getAsPointerType()->getPointeeType())) - return true; - + // dereferencing to a pointer is always a gc'able candidate, + // unless it is __weak. + return T->isPointerType() && + (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak); } return false; } @@ -1009,7 +1147,7 @@ Expr* Expr::IgnoreParens() { Expr* E = this; while (ParenExpr* P = dyn_cast<ParenExpr>(E)) E = P->getSubExpr(); - + return E; } @@ -1037,17 +1175,17 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { E = P->getSubExpr(); continue; } - + if (CastExpr *P = dyn_cast<CastExpr>(E)) { // We ignore integer <-> casts that are of the same width, ptr<->ptr and // ptr<->int casts of the same width. We also ignore all identify casts. Expr *SE = P->getSubExpr(); - + if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { E = SE; continue; } - + if ((E->getType()->isPointerType() || E->getType()->isIntegralType()) && (SE->getType()->isPointerType() || SE->getType()->isIntegralType()) && Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { @@ -1055,7 +1193,7 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { continue; } } - + return E; } } @@ -1094,6 +1232,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { switch (getStmtClass()) { default: break; case StringLiteralClass: + case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; case CompoundLiteralExprClass: { @@ -1110,22 +1249,31 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { const InitListExpr *Exp = cast<InitListExpr>(this); unsigned numInits = Exp->getNumInits(); for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx)) + if (!Exp->getInit(i)->isConstantInitializer(Ctx)) return false; } return true; } case ImplicitValueInitExprClass: return true; - case ParenExprClass: { + case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); - } case UnaryOperatorClass: { const UnaryOperator* Exp = cast<UnaryOperator>(this); if (Exp->getOpcode() == UnaryOperator::Extension) return Exp->getSubExpr()->isConstantInitializer(Ctx); break; } + case BinaryOperatorClass: { + // Special case &&foo - &&bar. It would be nice to generalize this somehow + // but this handles the common case. + const BinaryOperator *Exp = cast<BinaryOperator>(this); + if (Exp->getOpcode() == BinaryOperator::Sub && + isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && + isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) + return true; + break; + } case ImplicitCastExprClass: case CStyleCastExprClass: // Handle casts with a destination that's a struct or union; this @@ -1133,9 +1281,15 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { // cast-to-union extension. if (getType()->isRecordType()) return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + + // Integer->integer casts can be handled here, which is important for + // things like (int)(&&x-&&y). Scary but true. + if (getType()->isIntegerType() && + cast<CastExpr>(this)->getSubExpr()->getType()->isIntegerType()) + return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + break; } - return isEvaluatable(Ctx); } @@ -1152,9 +1306,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { // CheckICE - This function does the fundamental ICE checking: the returned // ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. // Note that to reduce code duplication, this helper does no evaluation -// itself; the caller checks whether the expression is evaluatable, and +// itself; the caller checks whether the expression is evaluatable, and // in the rare cases where CheckICE actually cares about the evaluated -// value, it calls into Evalute. +// value, it calls into Evalute. // // Meanings of Val: // 0: This expression is an ICE if it can be evaluated by Evaluate. @@ -1190,8 +1344,65 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } switch (E->getStmtClass()) { - default: +#define STMT(Node, Base) case Expr::Node##Class: +#define EXPR(Node, Base) +#include "clang/AST/StmtNodes.def" + case Expr::PredefinedExprClass: + case Expr::FloatingLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::StringLiteralClass: + case Expr::ArraySubscriptExprClass: + case Expr::MemberExprClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::VAArgExprClass: + case Expr::AddrLabelExprClass: + case Expr::StmtExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXTypeidExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXThrowExprClass: + case Expr::CXXConditionDeclExprClass: // FIXME: is this correct? + case Expr::CXXNewExprClass: + case Expr::CXXDeleteExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnresolvedFunctionNameExprClass: + case Expr::UnresolvedDeclRefExprClass: + case Expr::TemplateIdRefExprClass: + case Expr::CXXConstructExprClass: + case Expr::CXXBindTemporaryExprClass: + case Expr::CXXExprWithTemporariesClass: + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::CXXUnresolvedMemberExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCImplicitSetterGetterRefExprClass: + case Expr::ObjCSuperExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::BlockExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::NoStmtClass: + case Expr::ExprClass: return ICEDiag(2, E->getLocStart()); + + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + return NoDiag(); + case Expr::ParenExprClass: return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); case Expr::IntegerLiteralClass: @@ -1201,7 +1412,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::TypesCompatibleExprClass: case Expr::UnaryTypeTraitExprClass: return NoDiag(); - case Expr::CallExprClass: + case Expr::CallExprClass: case Expr::CXXOperatorCallExprClass: { const CallExpr *CE = cast<CallExpr>(E); if (CE->isBuiltinCall(Ctx)) @@ -1213,7 +1424,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); if (Ctx.getLangOptions().CPlusPlus && - E->getType().getCVRQualifiers() == QualType::Const) { + E->getType().getCVRQualifiers() == Qualifiers::Const) { // C++ 7.1.5.1p2 // A variable of non-volatile const-qualified integral or enumeration // type initialized by an ICE can be used in ICEs. @@ -1240,8 +1451,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::UnaryOperatorClass: { const UnaryOperator *Exp = cast<UnaryOperator>(E); switch (Exp->getOpcode()) { - default: + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + case UnaryOperator::Deref: return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: case UnaryOperator::LNot: case UnaryOperator::Plus: @@ -1269,8 +1486,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::BinaryOperatorClass: { const BinaryOperator *Exp = cast<BinaryOperator>(E); switch (Exp->getOpcode()) { - default: + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Assign: + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: return ICEDiag(2, E->getLocStart()); + case BinaryOperator::Mul: case BinaryOperator::Div: case BinaryOperator::Rem: @@ -1340,9 +1570,15 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } } } + case Expr::CastExprClass: case Expr::ImplicitCastExprClass: + case Expr::ExplicitCastExprClass: case Expr::CStyleCastExprClass: - case Expr::CXXFunctionalCastExprClass: { + case Expr::CXXFunctionalCastExprClass: + case Expr::CXXNamedCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: { const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); if (SubExpr->getType()->isIntegralType()) return CheckICE(SubExpr, Ctx); @@ -1352,7 +1588,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } case Expr::ConditionalOperatorClass: { const ConditionalOperator *Exp = cast<ConditionalOperator>(E); - // If the condition (ignoring parens) is a __builtin_constant_p call, + // If the condition (ignoring parens) is a __builtin_constant_p call, // then only the true side is actually considered in an integer constant // expression, and it is fully evaluated. This is an important GNU // extension. See GCC PR38377 for discussion. @@ -1392,6 +1628,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); } } + + // Silence a GCC warning + return ICEDiag(2, E->getLocStart()); } bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, @@ -1413,31 +1652,45 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. -bool Expr::isNullPointerConstant(ASTContext &Ctx) const -{ +bool Expr::isNullPointerConstant(ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const { + if (isValueDependent()) { + switch (NPC) { + case NPC_NeverValueDependent: + assert(false && "Unexpected value dependent expression!"); + // If the unthinkable happens, fall through to the safest alternative. + + case NPC_ValueDependentIsNull: + return isTypeDependent() || getType()->isIntegralType(); + + case NPC_ValueDependentIsNotNull: + return false; + } + } + // Strip off a cast to void*, if it exists. Except in C++. if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) { if (!Ctx.getLangOptions().CPlusPlus) { // Check that it is a cast to void*. - if (const PointerType *PT = CE->getType()->getAsPointerType()) { + if (const PointerType *PT = CE->getType()->getAs<PointerType>()) { QualType Pointee = PT->getPointeeType(); - if (Pointee.getCVRQualifiers() == 0 && + if (!Pointee.hasQualifiers() && Pointee->isVoidType() && // to void* CE->getSubExpr()->getType()->isIntegerType()) // from int. - return CE->getSubExpr()->isNullPointerConstant(Ctx); + return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } } } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) { // Ignore the ImplicitCastExpr type entirely. - return ICE->getSubExpr()->isNullPointerConstant(Ctx); + return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) { // Accept ((void*)0) as a null pointer constant, as many other // implementations do. - return PE->getSubExpr()->isNullPointerConstant(Ctx); - } else if (const CXXDefaultArgExpr *DefaultArg + return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { // See through default argument expressions - return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); } else if (isa<GNUNullExpr>(this)) { // The GNU __null extension is always a null pointer constant. return true; @@ -1448,9 +1701,10 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const return true; // This expression must be an integer type. - if (!getType()->isIntegerType()) + if (!getType()->isIntegerType() || + (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType())) return false; - + // If we have an integer constant expression, we need to *evaluate* it and // test for the value 0. llvm::APSInt Result; @@ -1458,7 +1712,7 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const } FieldDecl *Expr::getBitField() { - Expr *E = this->IgnoreParenCasts(); + Expr *E = this->IgnoreParens(); if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) @@ -1479,7 +1733,7 @@ bool ExtVectorElementExpr::isArrow() const { } unsigned ExtVectorElementExpr::getNumElements() const { - if (const VectorType *VT = getType()->getAsVectorType()) + if (const VectorType *VT = getType()->getAs<VectorType>()) return VT->getNumElements(); return 1; } @@ -1490,20 +1744,20 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { unsigned length = Accessor->getLength(); // Halving swizzles do not contain duplicate elements. - if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || !strcmp(compStr, "even") || !strcmp(compStr, "odd")) return false; - + // Advance past s-char prefix on hex swizzles. if (*compStr == 's' || *compStr == 'S') { compStr++; length--; } - + for (unsigned i = 0; i != length-1; i++) { const char *s = compStr+i; for (const char c = *s++; *s; s++) - if (c == *s) + if (c == *s) return true; } return false; @@ -1515,15 +1769,15 @@ void ExtVectorElementExpr::getEncodedElementAccess( const char *compStr = Accessor->getName(); if (*compStr == 's' || *compStr == 'S') compStr++; - + bool isHi = !strcmp(compStr, "hi"); bool isLo = !strcmp(compStr, "lo"); bool isEven = !strcmp(compStr, "even"); bool isOdd = !strcmp(compStr, "odd"); - + for (unsigned i = 0, e = getNumElements(); i != e; ++i) { uint64_t Index; - + if (isHi) Index = e + i; else if (isLo) @@ -1544,7 +1798,7 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1557,29 +1811,13 @@ ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, RBracloc = RBrac; } -ObjCStringLiteral* ObjCStringLiteral::Clone(ASTContext &C) const { - // Clone the string literal. - StringLiteral *NewString = - String ? cast<StringLiteral>(String)->Clone(C) : 0; - - return new (C) ObjCStringLiteral(NewString, getType(), AtLoc); -} - -ObjCSelectorExpr *ObjCSelectorExpr::Clone(ASTContext &C) const { - return new (C) ObjCSelectorExpr(getType(), SelName, AtLoc, RParenLoc); -} - -ObjCProtocolExpr *ObjCProtocolExpr::Clone(ASTContext &C) const { - return new (C) ObjCProtocolExpr(getType(), TheProtocol, AtLoc, RParenLoc); -} - -// constructor for class messages. +// constructor for class messages. // FIXME: clsName should be typed to ObjCInterfaceType ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1592,12 +1830,12 @@ ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, RBracloc = RBrac; } -// constructor for class messages. +// constructor for class messages. ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, QualType retType, ObjCMethodDecl *mproto, SourceLocation LBrac, SourceLocation RBrac, Expr **ArgExprs, unsigned nargs) -: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +: Expr(ObjCMessageExprClass, retType), SelName(selInfo), MethodProto(mproto) { NumArgs = nargs; SubExprs = new Stmt*[NumArgs+1]; @@ -1640,16 +1878,23 @@ bool ChooseExpr::isConditionTrue(ASTContext &C) const { return getCond()->EvaluateAsInt(C) != 0; } -void ShuffleVectorExpr::setExprs(Expr ** Exprs, unsigned NumExprs) { - if (NumExprs) - delete [] SubExprs; - - SubExprs = new Stmt* [NumExprs]; +void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, + unsigned NumExprs) { + if (SubExprs) C.Deallocate(SubExprs); + + SubExprs = new (C) Stmt* [NumExprs]; this->NumExprs = NumExprs; memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); } -void SizeOfAlignOfExpr::Destroy(ASTContext& C) { +void ShuffleVectorExpr::DoDestroy(ASTContext& C) { + DestroyChildren(C); + if (SubExprs) C.Deallocate(SubExprs); + this->~ShuffleVectorExpr(); + C.Deallocate(this); +} + +void SizeOfAlignOfExpr::DoDestroy(ASTContext& C) { // Override default behavior of traversing children. If this has a type // operand and the type is a variable-length array, the child iteration // will iterate over the size expression. However, this expression belongs @@ -1660,7 +1905,7 @@ void SizeOfAlignOfExpr::Destroy(ASTContext& C) { C.Deallocate(this); } else - Expr::Destroy(C); + Expr::DoDestroy(C); } //===----------------------------------------------------------------------===// @@ -1675,17 +1920,17 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { return getField()->getIdentifier(); } -DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, +DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, const Designator *Designators, - SourceLocation EqualOrColonLoc, + SourceLocation EqualOrColonLoc, bool GNUSyntax, - Expr **IndexExprs, + Expr **IndexExprs, unsigned NumIndexExprs, Expr *Init) - : Expr(DesignatedInitExprClass, Ty, + : Expr(DesignatedInitExprClass, Ty, Init->isTypeDependent(), Init->isValueDependent()), - EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), - NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { this->Designators = new Designator[NumDesignators]; // Record the initializer itself. @@ -1701,7 +1946,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, if (this->Designators[I].isArrayDesignator()) { // Compute type- and value-dependence. Expr *Index = IndexExprs[IndexIdx]; - ValueDependent = ValueDependent || + ValueDependent = ValueDependent || Index->isTypeDependent() || Index->isValueDependent(); // Copy the index expressions into permanent storage. @@ -1710,7 +1955,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, // Compute type- and value-dependence. Expr *Start = IndexExprs[IndexIdx]; Expr *End = IndexExprs[IndexIdx + 1]; - ValueDependent = ValueDependent || + ValueDependent = ValueDependent || Start->isTypeDependent() || Start->isValueDependent() || End->isTypeDependent() || End->isValueDependent(); @@ -1724,7 +1969,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, } DesignatedInitExpr * -DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, +DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, unsigned NumDesignators, Expr **IndexExprs, unsigned NumIndexExprs, SourceLocation ColonOrEqualLoc, @@ -1736,14 +1981,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, IndexExprs, NumIndexExprs, Init); } -DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, unsigned NumIndexExprs) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + sizeof(Stmt *) * (NumIndexExprs + 1), 8); return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); } -void DesignatedInitExpr::setDesignators(const Designator *Desigs, +void DesignatedInitExpr::setDesignators(const Designator *Desigs, unsigned NumDesigs) { if (Designators) delete [] Designators; @@ -1778,7 +2023,7 @@ Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) { } Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { - assert(D.Kind == Designator::ArrayRangeDesignator && + assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); char* Ptr = static_cast<char*>(static_cast<void *>(this)); Ptr += sizeof(DesignatedInitExpr); @@ -1787,7 +2032,7 @@ Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { } Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { - assert(D.Kind == Designator::ArrayRangeDesignator && + assert(D.Kind == Designator::ArrayRangeDesignator && "Requires array range designator"); char* Ptr = static_cast<char*>(static_cast<void *>(this)); Ptr += sizeof(DesignatedInitExpr); @@ -1797,8 +2042,8 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { /// \brief Replaces the designator at index @p Idx with the series /// of designators in [First, Last). -void DesignatedInitExpr::ExpandDesignator(unsigned Idx, - const Designator *First, +void DesignatedInitExpr::ExpandDesignator(unsigned Idx, + const Designator *First, const Designator *Last) { unsigned NumNewDesignators = Last - First; if (NumNewDesignators == 0) { @@ -1812,7 +2057,7 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx, return; } - Designator *NewDesignators + Designator *NewDesignators = new Designator[NumDesignators - 1 + NumNewDesignators]; std::copy(Designators, Designators + Idx, NewDesignators); std::copy(First, Last, NewDesignators + Idx); @@ -1823,13 +2068,29 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx, NumDesignators = NumDesignators - 1 + NumNewDesignators; } -void DesignatedInitExpr::Destroy(ASTContext &C) { +void DesignatedInitExpr::DoDestroy(ASTContext &C) { delete [] Designators; - Expr::Destroy(C); + Expr::DoDestroy(C); +} + +ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, + Expr **exprs, unsigned nexprs, + SourceLocation rparenloc) +: Expr(ParenListExprClass, QualType(), + hasAnyTypeDependentArguments(exprs, nexprs), + hasAnyValueDependentArguments(exprs, nexprs)), + NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { + + Exprs = new (C) Stmt*[nexprs]; + for (unsigned i = 0; i != nexprs; ++i) + Exprs[i] = exprs[i]; } -ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const { - return new (C) ImplicitValueInitExpr(getType()); +void ParenListExpr::DoDestroy(ASTContext& C) { + DestroyChildren(C); + if (Exprs) C.Deallocate(Exprs); + this->~ParenListExpr(); + C.Deallocate(this); } //===----------------------------------------------------------------------===// @@ -1861,14 +2122,22 @@ Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; } Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } -// ObjCKVCRefExpr -Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; } -Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; } +// ObjCImplicitSetterGetterRefExpr +Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() { + return &Base; +} +Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() { + return &Base+1; +} // ObjCSuperExpr Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); } +// ObjCIsaExpr +Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; } + // PredefinedExpr Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); } Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); } @@ -1902,7 +2171,7 @@ Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } // SizeOfAlignOfExpr -Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { +Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? @@ -2024,16 +2293,24 @@ Stmt::child_iterator DesignatedInitExpr::child_end() { } // ImplicitValueInitExpr -Stmt::child_iterator ImplicitValueInitExpr::child_begin() { - return child_iterator(); +Stmt::child_iterator ImplicitValueInitExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator ImplicitValueInitExpr::child_end() { + return child_iterator(); } -Stmt::child_iterator ImplicitValueInitExpr::child_end() { - return child_iterator(); +// ParenListExpr +Stmt::child_iterator ParenListExpr::child_begin() { + return &Exprs[0]; +} +Stmt::child_iterator ParenListExpr::child_end() { + return &Exprs[0]+NumExprs; } // ObjCStringLiteral -Stmt::child_iterator ObjCStringLiteral::child_begin() { +Stmt::child_iterator ObjCStringLiteral::child_begin() { return &String; } Stmt::child_iterator ObjCStringLiteral::child_end() { @@ -2045,7 +2322,7 @@ Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } // ObjCSelectorExpr -Stmt::child_iterator ObjCSelectorExpr::child_begin() { +Stmt::child_iterator ObjCSelectorExpr::child_begin() { return child_iterator(); } Stmt::child_iterator ObjCSelectorExpr::child_end() { @@ -2061,7 +2338,7 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() { } // ObjCMessageExpr -Stmt::child_iterator ObjCMessageExpr::child_begin() { +Stmt::child_iterator ObjCMessageExpr::child_begin() { return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; } Stmt::child_iterator ObjCMessageExpr::child_end() { diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 399c30255a8f..cba0e220952e 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -17,14 +17,6 @@ #include "clang/AST/ExprCXX.h" using namespace clang; -void CXXConditionDeclExpr::Destroy(ASTContext& C) { - // FIXME: Cannot destroy the decl here, because it is linked into the - // DeclContext's chain. - //getVarDecl()->Destroy(C); - this->~CXXConditionDeclExpr(); - C.Deallocate(this); -} - //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// @@ -38,7 +30,7 @@ Stmt::child_iterator CXXTypeidExpr::child_end() { } // CXXBoolLiteralExpr -Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { +Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXBoolLiteralExpr::child_end() { @@ -46,7 +38,7 @@ Stmt::child_iterator CXXBoolLiteralExpr::child_end() { } // CXXNullPtrLiteralExpr -Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { +Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() { @@ -73,7 +65,7 @@ Stmt::child_iterator CXXDefaultArgExpr::child_end() { } // CXXZeroInitValueExpr -Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { +Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { return child_iterator(); } Stmt::child_iterator CXXZeroInitValueExpr::child_end() { @@ -101,8 +93,7 @@ CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), OperatorDelete(operatorDelete), Constructor(constructor), - StartLoc(startLoc), EndLoc(endLoc) -{ + StartLoc(startLoc), EndLoc(endLoc) { unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; SubExprs = new Stmt*[TotalSize]; unsigned i = 0; @@ -124,19 +115,19 @@ Stmt::child_iterator CXXNewExpr::child_end() { Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } +// CXXPseudoDestructorExpr +Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; } +Stmt::child_iterator CXXPseudoDestructorExpr::child_end() { + return &Base + 1; +} + // UnresolvedFunctionNameExpr -Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { - return child_iterator(); +Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { + return child_iterator(); } Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { return child_iterator(); } - -UnresolvedFunctionNameExpr* -UnresolvedFunctionNameExpr::Clone(ASTContext &C) const { - return new (C) UnresolvedFunctionNameExpr(Name, getType(), Loc); -} - // UnaryTypeTraitExpr Stmt::child_iterator UnaryTypeTraitExpr::child_begin() { return child_iterator(); @@ -155,16 +146,16 @@ StmtIterator UnresolvedDeclRefExpr::child_end() { } TemplateIdRefExpr::TemplateIdRefExpr(QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - TemplateName Template, + TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) : Expr(TemplateIdRefExprClass, T, - (Template.isDependent() || + (Template.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, NumTemplateArgs)), (Template.isDependent() || @@ -172,10 +163,8 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateArgs, NumTemplateArgs))), Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template), TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc), - RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) - -{ - TemplateArgument *StoredTemplateArgs + RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) { + TemplateArgument *StoredTemplateArgs = reinterpret_cast<TemplateArgument *> (this+1); for (unsigned I = 0; I != NumTemplateArgs; ++I) new (StoredTemplateArgs + I) TemplateArgument(TemplateArgs[I]); @@ -183,10 +172,10 @@ TemplateIdRefExpr::TemplateIdRefExpr(QualType T, TemplateIdRefExpr * TemplateIdRefExpr::Create(ASTContext &Context, QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier *Qualifier, SourceRange QualifierRange, TemplateName Template, SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, + SourceLocation LAngleLoc, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) + @@ -196,11 +185,13 @@ TemplateIdRefExpr::Create(ASTContext &Context, QualType T, NumTemplateArgs, RAngleLoc); } -void TemplateIdRefExpr::Destroy(ASTContext &Context) { +void TemplateIdRefExpr::DoDestroy(ASTContext &Context) { const TemplateArgument *TemplateArgs = getTemplateArgs(); for (unsigned I = 0; I != NumTemplateArgs; ++I) if (Expr *E = TemplateArgs[I].getAsExpr()) E->Destroy(Context); + this->~TemplateIdRefExpr(); + Context.Deallocate(this); } Stmt::child_iterator TemplateIdRefExpr::child_begin() { @@ -213,34 +204,87 @@ Stmt::child_iterator TemplateIdRefExpr::child_end() { return Stmt::child_iterator(); } -bool UnaryTypeTraitExpr::EvaluateTrait() const { +bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); case UTT_IsPOD: return QueriedType->isPODType(); case UTT_IsClass: // Fallthrough case UTT_IsUnion: - if (const RecordType *Record = QueriedType->getAsRecordType()) { + if (const RecordType *Record = QueriedType->getAs<RecordType>()) { bool Union = Record->getDecl()->isUnion(); return UTT == UTT_IsUnion ? Union : !Union; } return false; case UTT_IsEnum: return QueriedType->isEnumeralType(); case UTT_IsPolymorphic: - if (const RecordType *Record = QueriedType->getAsRecordType()) { + if (const RecordType *Record = QueriedType->getAs<RecordType>()) { // Type traits are only parsed in C++, so we've got CXXRecords. return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); } return false; case UTT_IsAbstract: - if (const RecordType *RT = QueriedType->getAsRecordType()) + if (const RecordType *RT = QueriedType->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); return false; + case UTT_IsEmpty: + if (const RecordType *Record = QueriedType->getAs<RecordType>()) { + return !Record->getDecl()->isUnion() + && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); + } + return false; case UTT_HasTrivialConstructor: - if (const RecordType *RT = QueriedType->getAsRecordType()) + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true then the trait is true, else if type is + // a cv class or union type (or array thereof) with a trivial default + // constructor ([class.ctor]) then the trait is true, else it is false. + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); return false; + case UTT_HasTrivialCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type then + // the trait is true, else if type is a cv class or union type + // with a trivial copy constructor ([class.copy]) then the trait + // is true, else it is false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = QueriedType->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor(); + return false; + case UTT_HasTrivialAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __is_pod (type) is true then the + // trait is true, else if type is a cv class or union type with + // a trivial copy assignment ([class.copy]) then the trait is + // true, else it is false. + // Note: the const and reference restrictions are interesting, + // given that const and reference members don't prevent a class + // from having a trivial copy assignment operator (but do cause + // errors if the copy assignment operator is actually used, q.v. + // [class.copy]p12). + + if (C.getBaseElementType(QueriedType).isConstQualified()) + return false; + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = QueriedType->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment(); + return false; case UTT_HasTrivialDestructor: - if (const RecordType *RT = QueriedType->getAsRecordType()) + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type + // then the trait is true, else if type is a cv class or union + // type (or array thereof) with a trivial destructor + // ([class.dtor]) then the trait is true, else it is + // false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); return false; } @@ -251,7 +295,7 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { if (getNumArgs() == 1) // Prefix operator - return SourceRange(getOperatorLoc(), + return SourceRange(getOperatorLoc(), getArg(0)->getSourceRange().getEnd()); else // Postfix operator @@ -296,26 +340,26 @@ const char *CXXNamedCastExpr::getCastName() const { } } -CXXTemporary *CXXTemporary::Create(ASTContext &C, +CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } -void CXXTemporary::Destroy(ASTContext &C) { +void CXXTemporary::Destroy(ASTContext &Ctx) { this->~CXXTemporary(); - C.Deallocate(this); + Ctx.Deallocate(this); } -CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, +CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { - assert(SubExpr->getType()->isRecordType() && + assert(SubExpr->getType()->isRecordType() && "Expression bound to a temporary must have record type!"); return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } -void CXXBindTemporaryExpr::Destroy(ASTContext &C) { +void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) { Temp->Destroy(C); this->~CXXBindTemporaryExpr(); C.Deallocate(this); @@ -324,38 +368,49 @@ void CXXBindTemporaryExpr::Destroy(ASTContext &C) { CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, - SourceLocation tyBeginLoc, + SourceLocation tyBeginLoc, Expr **Args, - unsigned NumArgs, + unsigned NumArgs, SourceLocation rParenLoc) - : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, - false, Args, NumArgs), + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, + false, Args, NumArgs), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } -CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, +CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs) { - return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, + return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, Args, NumArgs); } -CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, +CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, CXXConstructorDecl *D, bool elidable, - Expr **args, unsigned numargs) + Expr **args, unsigned numargs) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) { - if (NumArgs > 0) { + if (NumArgs) { Args = new (C) Stmt*[NumArgs]; - for (unsigned i = 0; i < NumArgs; ++i) + + for (unsigned i = 0; i != NumArgs; ++i) { + assert(args[i] && "NULL argument in CXXConstructExpr"); Args[i] = args[i]; + } } } -void CXXConstructExpr::Destroy(ASTContext &C) { +CXXConstructExpr::CXXConstructExpr(EmptyShell Empty, ASTContext &C, + unsigned numargs) + : Expr(CXXConstructExprClass, Empty), Args(0), NumArgs(numargs) +{ + if (NumArgs) + Args = new (C) Stmt*[NumArgs]; +} + +void CXXConstructExpr::DoDestroy(ASTContext &C) { DestroyChildren(C); if (Args) C.Deallocate(Args); @@ -363,13 +418,13 @@ void CXXConstructExpr::Destroy(ASTContext &C) { C.Deallocate(this); } -CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, - CXXTemporary **temps, +CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, + CXXTemporary **temps, unsigned numtemps, bool shoulddestroytemps) : Expr(CXXExprWithTemporariesClass, subexpr->getType(), - subexpr->isTypeDependent(), subexpr->isValueDependent()), - SubExpr(subexpr), Temps(0), NumTemps(numtemps), + subexpr->isTypeDependent(), subexpr->isValueDependent()), + SubExpr(subexpr), Temps(0), NumTemps(numtemps), ShouldDestroyTemps(shoulddestroytemps) { if (NumTemps > 0) { Temps = new CXXTemporary*[NumTemps]; @@ -378,16 +433,16 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, } } -CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, +CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, Expr *SubExpr, - CXXTemporary **Temps, + CXXTemporary **Temps, unsigned NumTemps, bool ShouldDestroyTemps){ - return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, + return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps, ShouldDestroyTemps); } -void CXXExprWithTemporaries::Destroy(ASTContext &C) { +void CXXExprWithTemporaries::DoDestroy(ASTContext &C) { DestroyChildren(C); this->~CXXExprWithTemporaries(); C.Deallocate(this); @@ -402,7 +457,7 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { return &SubExpr; } -Stmt::child_iterator CXXBindTemporaryExpr::child_end() { +Stmt::child_iterator CXXBindTemporaryExpr::child_end() { return &SubExpr + 1; } @@ -419,7 +474,7 @@ Stmt::child_iterator CXXExprWithTemporaries::child_begin() { return &SubExpr; } -Stmt::child_iterator CXXExprWithTemporaries::child_end() { +Stmt::child_iterator CXXExprWithTemporaries::child_end() { return &SubExpr + 1; } @@ -442,7 +497,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( } CXXUnresolvedConstructExpr * -CXXUnresolvedConstructExpr::Create(ASTContext &C, +CXXUnresolvedConstructExpr::Create(ASTContext &C, SourceLocation TyBegin, QualType T, SourceLocation LParenLoc, @@ -463,26 +518,79 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs); } -Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { - return child_iterator(&Base); -} +CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) + : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true), + Base(Base), IsArrow(IsArrow), + HasExplicitTemplateArgumentList(HasExplicitTemplateArgs), + OperatorLoc(OperatorLoc), + Qualifier(Qualifier), QualifierRange(QualifierRange), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + Member(Member), MemberLoc(MemberLoc) { + if (HasExplicitTemplateArgumentList) { + ExplicitTemplateArgumentList *ETemplateArgs + = getExplicitTemplateArgumentList(); + ETemplateArgs->LAngleLoc = LAngleLoc; + ETemplateArgs->RAngleLoc = RAngleLoc; + ETemplateArgs->NumTemplateArgs = NumTemplateArgs; -Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { - return child_iterator(&Base + 1); + TemplateArgument *SavedTemplateArgs = ETemplateArgs->getTemplateArgs(); + for (unsigned I = 0; I < NumTemplateArgs; ++I) + new (SavedTemplateArgs + I) TemplateArgument(TemplateArgs[I]); + } } -//===----------------------------------------------------------------------===// -// Cloners -//===----------------------------------------------------------------------===// +CXXUnresolvedMemberExpr * +CXXUnresolvedMemberExpr::Create(ASTContext &C, + Expr *Base, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + NamedDecl *FirstQualifierFoundInScope, + DeclarationName Member, + SourceLocation MemberLoc, + bool HasExplicitTemplateArgs, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { + if (!HasExplicitTemplateArgs) + return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, MemberLoc); -CXXBoolLiteralExpr* CXXBoolLiteralExpr::Clone(ASTContext &C) const { - return new (C) CXXBoolLiteralExpr(Value, getType(), Loc); + void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) + + sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgument) * NumTemplateArgs, + llvm::alignof<CXXUnresolvedMemberExpr>()); + return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc, + Qualifier, QualifierRange, + FirstQualifierFoundInScope, + Member, + MemberLoc, + HasExplicitTemplateArgs, + LAngleLoc, + TemplateArgs, + NumTemplateArgs, + RAngleLoc); } -CXXNullPtrLiteralExpr* CXXNullPtrLiteralExpr::Clone(ASTContext &C) const { - return new (C) CXXNullPtrLiteralExpr(getType(), Loc); +Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { + return child_iterator(&Base); } -CXXZeroInitValueExpr* CXXZeroInitValueExpr::Clone(ASTContext &C) const { - return new (C) CXXZeroInitValueExpr(getType(), TyBeginLoc, RParenLoc); +Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { + return child_iterator(&Base + 1); } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eb6b5b725ff5..94d22998ebbe 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -42,12 +42,16 @@ using llvm::APFloat; /// certain things in certain situations. struct EvalInfo { ASTContext &Ctx; - + /// EvalResult - Contains information about the evaluation. Expr::EvalResult &EvalResult; - EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx), - EvalResult(evalresult) {} + /// AnyLValue - Stack based LValue results are not discarded. + bool AnyLValue; + + EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult, + bool anylvalue = false) + : Ctx(ctx), EvalResult(evalresult), AnyLValue(anylvalue) {} }; @@ -104,12 +108,12 @@ static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { return false; } -static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, +static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, APFloat &Value, ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); // Determine whether we are converting to unsigned or signed. bool DestSigned = DestType->isSignedIntegerType(); - + // FIXME: Warning for overflow. uint64_t Space[4]; bool ignored; @@ -118,16 +122,16 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned); } -static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, +static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, APFloat &Value, ASTContext &Ctx) { bool ignored; APFloat Result = Value; - Result.convert(Ctx.getFloatTypeSemantics(DestType), + Result.convert(Ctx.getFloatTypeSemantics(DestType), APFloat::rmNearestTiesToEven, &ignored); return Result; } -static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, +static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, APSInt &Value, ASTContext &Ctx) { unsigned DestWidth = Ctx.getIntWidth(DestType); APSInt Result = Value; @@ -138,7 +142,7 @@ static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, return Result; } -static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, +static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, APSInt &Value, ASTContext &Ctx) { APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1); @@ -155,7 +159,7 @@ class VISIBILITY_HIDDEN LValueExprEvaluator : public StmtVisitor<LValueExprEvaluator, APValue> { EvalInfo &Info; public: - + LValueExprEvaluator(EvalInfo &info) : Info(info) {} APValue VisitStmt(Stmt *S) { @@ -176,6 +180,16 @@ public: { return Visit(E->getSubExpr()); } APValue VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } + + APValue VisitCastExpr(CastExpr *E) { + switch (E->getCastKind()) { + default: + return APValue(); + + case CastExpr::CK_NoOp: + return Visit(E->getSubExpr()); + } + } // FIXME: Missing: __real__, __imag__ }; } // end anonymous namespace @@ -185,16 +199,15 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) { return Result.isLValue(); } -APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) -{ - if (!E->hasGlobalStorage()) - return APValue(); - +APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) { if (isa<FunctionDecl>(E->getDecl())) { return APValue(E, 0); } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { + if (!Info.AnyLValue && !VD->hasGlobalStorage()) + return APValue(); if (!VD->getType()->isReferenceType()) return APValue(E, 0); + // FIXME: Check whether VD might be overridden! if (VD->getInit()) return Visit(VD->getInit()); } @@ -202,18 +215,17 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) return APValue(); } -APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) -{ +APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) { if (E->hasBlockDeclRefExprs()) return APValue(); - + return APValue(E, 0); } APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - if (E->isFileScope()) - return APValue(E, 0); - return APValue(); + if (!Info.AnyLValue && !E->isFileScope()) + return APValue(); + return APValue(E, 0); } APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { @@ -222,7 +234,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), result, Info)) return APValue(); - Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType(); + Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType(); } else { result = Visit(E->getBase()); if (result.isUninit()) @@ -230,7 +242,7 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { Ty = E->getBase()->getType(); } - RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); @@ -255,13 +267,12 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { return result; } -APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) -{ +APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { APValue Result; - + if (!EvaluatePointer(E->getBase(), Result, Info)) return APValue(); - + APSInt Index; if (!EvaluateInteger(E->getIdx(), Index, Info)) return APValue(); @@ -269,13 +280,12 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8; uint64_t Offset = Index.getSExtValue() * ElementSize; - Result.setLValue(Result.getLValueBase(), + Result.setLValue(Result.getLValueBase(), Result.getLValueOffset() + Offset); return Result; } -APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) -{ +APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) { APValue Result; if (!EvaluatePointer(E->getSubExpr(), Result, Info)) return APValue(); @@ -291,7 +301,7 @@ class VISIBILITY_HIDDEN PointerExprEvaluator : public StmtVisitor<PointerExprEvaluator, APValue> { EvalInfo &Info; public: - + PointerExprEvaluator(EvalInfo &info) : Info(info) {} APValue VisitStmt(Stmt *S) { @@ -337,23 +347,23 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() != BinaryOperator::Add && E->getOpcode() != BinaryOperator::Sub) return APValue(); - + const Expr *PExp = E->getLHS(); const Expr *IExp = E->getRHS(); if (IExp->getType()->isPointerType()) std::swap(PExp, IExp); - + APValue ResultLValue; if (!EvaluatePointer(PExp, ResultLValue, Info)) return APValue(); - + llvm::APSInt AdditionalOffset(32); if (!EvaluateInteger(IExp, AdditionalOffset, Info)) return APValue(); - QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType(); + QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType(); uint64_t SizeOfPointee; - + // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) SizeOfPointee = 1; @@ -376,19 +386,21 @@ APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { return result; return APValue(); } - + APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { const Expr* SubExpr = E->getSubExpr(); // Check for pointer->pointer cast - if (SubExpr->getType()->isPointerType()) { + if (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isObjCObjectPointerType() || + SubExpr->getType()->isNullPtrType()) { APValue Result; if (EvaluatePointer(SubExpr, Result, Info)) return Result; return APValue(); } - + if (SubExpr->getType()->isIntegralType()) { APValue Result; if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) @@ -398,7 +410,7 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); return APValue(0, Result.getInt().getZExtValue()); } - + // Cast is of an lvalue, no need to change value. return Result; } @@ -413,10 +425,10 @@ APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { } return APValue(); -} +} APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { - if (E->isBuiltinCall(Info.Ctx) == + if (E->isBuiltinCall(Info.Ctx) == Builtin::BI__builtin___CFStringMakeConstantString) return APValue(E, 0); return APValue(); @@ -445,13 +457,13 @@ namespace { EvalInfo &Info; APValue GetZeroVector(QualType VecType); public: - + VectorExprEvaluator(EvalInfo &info) : Info(info) {} - + APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitUnaryExtension(const UnaryOperator *E) @@ -485,11 +497,11 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { } APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { - const VectorType *VTy = E->getType()->getAsVectorType(); + const VectorType *VTy = E->getType()->getAs<VectorType>(); QualType EltTy = VTy->getElementType(); unsigned NElts = VTy->getNumElements(); unsigned EltWidth = Info.Ctx.getTypeSize(EltTy); - + const Expr* SE = E->getSubExpr(); QualType SETy = SE->getType(); APValue Result = APValue(); @@ -539,12 +551,12 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { // element. APSInt Init; Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt(); - + llvm::SmallVector<APValue, 4> Elts; for (unsigned i = 0; i != NElts; ++i) { APSInt Tmp = Init; Tmp.extOrTrunc(EltWidth); - + if (EltTy->isIntegerType()) Elts.push_back(APValue(Tmp)); else if (EltTy->isRealFloatingType()) @@ -557,17 +569,17 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { return APValue(&Elts[0], Elts.size()); } -APValue +APValue VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { return this->Visit(const_cast<Expr*>(E->getInitializer())); } -APValue +APValue VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { - const VectorType *VT = E->getType()->getAsVectorType(); + const VectorType *VT = E->getType()->getAs<VectorType>(); unsigned NumInits = E->getNumInits(); unsigned NumElements = VT->getNumElements(); - + QualType EltTy = VT->getElementType(); llvm::SmallVector<APValue, 4> Elements; @@ -595,9 +607,9 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return APValue(&Elements[0], Elements.size()); } -APValue +APValue VectorExprEvaluator::GetZeroVector(QualType T) { - const VectorType *VT = T->getAsVectorType(); + const VectorType *VT = T->getAs<VectorType>(); QualType EltTy = VT->getElementType(); APValue ZeroElement; if (EltTy->isIntegerType()) @@ -676,20 +688,20 @@ public: } return false; } - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// - + bool VisitStmt(Stmt *) { assert(0 && "This should be called on integers, stmts are not integers"); return false; } - + bool VisitExpr(Expr *E) { return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); } - + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } bool VisitIntegerLiteral(const IntegerLiteral *E) { @@ -704,7 +716,7 @@ public: // be able to strip CRV qualifiers from the type. QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1()); QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2()); - return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), + return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), T1.getUnqualifiedType()), E); } @@ -720,11 +732,11 @@ public: bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return Success(E->getValue(), E); } - + bool VisitGNUNullExpr(const GNUNullExpr *E) { return Success(0, E); } - + bool VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) { return Success(0, E); } @@ -734,7 +746,7 @@ public: } bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { - return Success(E->EvaluateTrait(), E); + return Success(E->EvaluateTrait(Info.Ctx), E); } bool VisitChooseExpr(const ChooseExpr *E) { @@ -754,7 +766,7 @@ private: static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { if (!E->getType()->isIntegralType()) return false; - + return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); } @@ -781,7 +793,7 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { // In C++, const, non-volatile integers initialized with ICEs are ICEs. // In C, they can also be folded, although they are not ICEs. - if (E->getType().getCVRQualifiers() == QualType::Const) { + if (E->getType().getCVRQualifiers() == Qualifiers::Const) { if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) { if (APValue *V = D->getEvaluatedValue()) return Success(V->getInt(), E); @@ -817,12 +829,12 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { array_type_class, string_type_class, lang_type_class }; - - // If no argument was supplied, default to "no_type_class". This isn't + + // If no argument was supplied, default to "no_type_class". This isn't // ideal, however it is what gcc does. if (E->getNumArgs() == 0) return no_type_class; - + QualType ArgTy = E->getArg(0)->getType(); if (ArgTy->isVoidType()) return void_type_class; @@ -863,11 +875,17 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); - + case Builtin::BI__builtin_constant_p: // __builtin_constant_p always has one operand: it returns true if that // operand can be folded, false otherwise. return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E); + + case Builtin::BI__builtin_eh_return_data_regno: { + int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue(); + Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); + return Success(Operand, E); + } } } @@ -888,7 +906,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // These need to be handled specially because the operands aren't // necessarily integral bool lhsResult, rhsResult; - + if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { // We were able to evaluate the LHS, see if we can get away with not // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 @@ -905,7 +923,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { // We can't evaluate the LHS; however, sometimes the result // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. - if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || + if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || !rhsResult == (E->getOpcode() == BinaryOperator::LAnd)) { // Since we weren't able to evaluate the left hand side, it // must have had side effects. @@ -933,9 +951,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return false; if (LHS.isComplexFloat()) { - APFloat::cmpResult CR_r = + APFloat::cmpResult CR_r = LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal()); - APFloat::cmpResult CR_i = + APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); if (E->getOpcode() == BinaryOperator::EQ) @@ -944,9 +962,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { else { assert(E->getOpcode() == BinaryOperator::NE && "Invalid complex comparison."); - return Success(((CR_r == APFloat::cmpGreaterThan || + return Success(((CR_r == APFloat::cmpGreaterThan || CR_r == APFloat::cmpLessThan) && - (CR_i == APFloat::cmpGreaterThan || + (CR_i == APFloat::cmpGreaterThan || CR_i == APFloat::cmpLessThan)), E); } } else { @@ -961,17 +979,17 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } } } - + if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) { APFloat RHS(0.0), LHS(0.0); - + if (!EvaluateFloat(E->getRHS(), RHS, Info)) return false; - + if (!EvaluateFloat(E->getLHS(), LHS, Info)) return false; - + APFloat::cmpResult CR = LHS.compare(RHS); switch (E->getOpcode()) { @@ -984,16 +1002,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BinaryOperator::LE: return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); case BinaryOperator::GE: - return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, E); case BinaryOperator::EQ: return Success(CR == APFloat::cmpEqual, E); case BinaryOperator::NE: - return Success(CR == APFloat::cmpGreaterThan + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpLessThan, E); } } - + if (LHSTy->isPointerType() && RHSTy->isPointerType()) { if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) { APValue LHSValue; @@ -1028,7 +1046,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() == BinaryOperator::Sub) { const QualType Type = E->getLHS()->getType(); - const QualType ElementType = Type->getAsPointerType()->getPointeeType(); + const QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) @@ -1105,16 +1123,16 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(Result.getInt() % RHS, E); case BinaryOperator::Shl: { // FIXME: Warn about out of range shift amounts! - unsigned SA = + unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() << SA, E); } case BinaryOperator::Shr: { - unsigned SA = + unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() >> SA, E); } - + case BinaryOperator::LT: return Success(Result.getInt() < RHS, E); case BinaryOperator::GT: return Success(Result.getInt() > RHS, E); case BinaryOperator::LE: return Success(Result.getInt() <= RHS, E); @@ -1144,7 +1162,7 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { E = E->IgnoreParens(); // alignof decl is always accepted, even if it doesn't make sense: we default - // to 1 in those cases. + // to 1 in those cases. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); @@ -1224,7 +1242,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // If so, we could clear the diagnostic ID. return true; case UnaryOperator::Plus: - // The result is always just the subexpr. + // The result is always just the subexpr. return true; case UnaryOperator::Minus: if (!Result.isInt()) return false; @@ -1234,7 +1252,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return Success(~Result.getInt(), E); } } - + /// HandleCast - This is used to evaluate implicit or explicit casts where the /// result type is integer. bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { @@ -1262,7 +1280,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { return Success(HandleIntToIntCast(DestType, SrcType, Result.getInt(), Info.Ctx), E); } - + // FIXME: Clean this up! if (SrcType->isPointerType()) { APValue LV; @@ -1316,7 +1334,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { APFloat F(0.0); if (!EvaluateFloat(SubExpr, F, Info)) return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); - + return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); } @@ -1399,13 +1417,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result = llvm::APFloat::getInf(Sem); return true; } - + case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: // If this is __builtin_nan() turn this into a nan, otherwise we // can't constant fold it. - if (const StringLiteral *S = + if (const StringLiteral *S = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) { if (!S->isWide()) { const llvm::fltSemantics &Sem = @@ -1430,13 +1448,13 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_fabsl: if (!EvaluateFloat(E->getArg(0), Result, Info)) return false; - + if (Result.isNegative()) Result.changeSign(); return true; - case Builtin::BI__builtin_copysign: - case Builtin::BI__builtin_copysignf: + case Builtin::BI__builtin_copysign: + case Builtin::BI__builtin_copysignf: case Builtin::BI__builtin_copysignl: { APFloat RHS(0.); if (!EvaluateFloat(E->getArg(0), Result, Info) || @@ -1457,7 +1475,7 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { switch (E->getOpcode()) { default: return false; - case UnaryOperator::Plus: + case UnaryOperator::Plus: return true; case UnaryOperator::Minus: Result.changeSign(); @@ -1498,12 +1516,12 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); - + if (SubExpr->getType()->isIntegralType()) { APSInt IntResult; if (!EvaluateInteger(SubExpr, IntResult, Info)) return false; - Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), + Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), IntResult, Info.Ctx); return true; } @@ -1532,10 +1550,10 @@ namespace { class VISIBILITY_HIDDEN ComplexExprEvaluator : public StmtVisitor<ComplexExprEvaluator, APValue> { EvalInfo &Info; - + public: ComplexExprEvaluator(EvalInfo &info) : Info(info) {} - + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -1543,7 +1561,7 @@ public: APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitImaginaryLiteral(ImaginaryLiteral *E) { @@ -1554,17 +1572,17 @@ public: if (!EvaluateFloat(SubExpr, Result, Info)) return APValue(); - - return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), + + return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), Result); } else { - assert(SubExpr->getType()->isIntegerType() && + assert(SubExpr->getType()->isIntegerType() && "Unexpected imaginary literal."); llvm::APSInt Result; if (!EvaluateInteger(SubExpr, Result, Info)) return APValue(); - + llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); Zero = 0; return APValue(Zero, Result); @@ -1573,7 +1591,7 @@ public: APValue VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); - QualType EltType = E->getType()->getAsComplexType()->getElementType(); + QualType EltType = E->getType()->getAs<ComplexType>()->getElementType(); QualType SubType = SubExpr->getType(); if (SubType->isRealFloatingType()) { @@ -1584,7 +1602,7 @@ public: if (EltType->isRealFloatingType()) { Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(Result, + return APValue(Result, APFloat(Result.getSemantics(), APFloat::fcZero, false)); } else { llvm::APSInt IResult; @@ -1602,7 +1620,7 @@ public: if (EltType->isRealFloatingType()) { APFloat FResult = HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx); - return APValue(FResult, + return APValue(FResult, APFloat(FResult.getSemantics(), APFloat::fcZero, false)); } else { Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx); @@ -1610,7 +1628,7 @@ public: Zero = 0; return APValue(Result, Zero); } - } else if (const ComplexType *CT = SubType->getAsComplexType()) { + } else if (const ComplexType *CT = SubType->getAs<ComplexType>()) { APValue Src; if (!EvaluateComplex(SubExpr, Src, Info)) @@ -1620,36 +1638,36 @@ public: if (Src.isComplexFloat()) { if (EltType->isRealFloatingType()) { - return APValue(HandleFloatToFloatCast(EltType, SrcType, + return APValue(HandleFloatToFloatCast(EltType, SrcType, Src.getComplexFloatReal(), Info.Ctx), - HandleFloatToFloatCast(EltType, SrcType, + HandleFloatToFloatCast(EltType, SrcType, Src.getComplexFloatImag(), Info.Ctx)); } else { return APValue(HandleFloatToIntCast(EltType, SrcType, Src.getComplexFloatReal(), Info.Ctx), - HandleFloatToIntCast(EltType, SrcType, + HandleFloatToIntCast(EltType, SrcType, Src.getComplexFloatImag(), - Info.Ctx)); + Info.Ctx)); } } else { assert(Src.isComplexInt() && "Invalid evaluate result."); if (EltType->isRealFloatingType()) { - return APValue(HandleIntToFloatCast(EltType, SrcType, + return APValue(HandleIntToFloatCast(EltType, SrcType, Src.getComplexIntReal(), Info.Ctx), - HandleIntToFloatCast(EltType, SrcType, + HandleIntToFloatCast(EltType, SrcType, Src.getComplexIntImag(), Info.Ctx)); } else { return APValue(HandleIntToIntCast(EltType, SrcType, Src.getComplexIntReal(), Info.Ctx), - HandleIntToIntCast(EltType, SrcType, + HandleIntToIntCast(EltType, SrcType, Src.getComplexIntImag(), - Info.Ctx)); + Info.Ctx)); } } } @@ -1657,7 +1675,7 @@ public: // FIXME: Handle more casts. return APValue(); } - + APValue VisitBinaryOperator(const BinaryOperator *E); APValue VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1668,23 +1686,21 @@ public: }; } // end anonymous namespace -static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) -{ +static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) { Result = ComplexExprEvaluator(Info).Visit(const_cast<Expr*>(E)); assert((!Result.isComplexFloat() || - (&Result.getComplexFloatReal().getSemantics() == - &Result.getComplexFloatImag().getSemantics())) && + (&Result.getComplexFloatReal().getSemantics() == + &Result.getComplexFloatImag().getSemantics())) && "Invalid complex evaluation."); return Result.isComplexFloat() || Result.isComplexInt(); } -APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) -{ +APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APValue Result, RHS; - + if (!EvaluateComplex(E->getLHS(), Result, Info)) return APValue(); - + if (!EvaluateComplex(E->getRHS(), RHS, Info)) return APValue(); @@ -1721,7 +1737,7 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) APFloat &LHS_i = LHS.getComplexFloatImag(); APFloat &RHS_r = RHS.getComplexFloatReal(); APFloat &RHS_i = RHS.getComplexFloatImag(); - + APFloat Tmp = LHS_r; Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); Result.getComplexFloatReal() = Tmp; @@ -1737,10 +1753,10 @@ APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); } else { APValue LHS = Result; - Result.getComplexIntReal() = + Result.getComplexIntReal() = (LHS.getComplexIntReal() * RHS.getComplexIntReal() - LHS.getComplexIntImag() * RHS.getComplexIntImag()); - Result.getComplexIntImag() = + Result.getComplexIntImag() = (LHS.getComplexIntReal() * RHS.getComplexIntImag() + LHS.getComplexIntImag() * RHS.getComplexIntReal()); } @@ -1774,7 +1790,7 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { llvm::APFloat f(0.0); if (!EvaluateFloat(this, f, Info)) return false; - + Result.Val = APValue(f); } else if (getType()->isAnyComplexType()) { if (!EvaluateComplex(this, Result.Val, Info)) @@ -1791,6 +1807,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; } +bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result, true); + + return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; +} + /// isEvaluatable - Call Evaluate to see if this expression can be constant /// folded, but discard the result. bool Expr::isEvaluatable(ASTContext &Ctx) const { diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index dd2fc14ab2a4..c47a9dadbadd 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { Out << " \"];\n"; // Display the base classes. - const CXXRecordDecl *Decl - = static_cast<const CXXRecordDecl *>(Type->getAsRecordType()->getDecl()); + const CXXRecordDecl *Decl + = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl()); for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin(); Base != Decl->bases_end(); ++Base) { QualType CanonBaseType = Context.getCanonicalType(Base->getType()); @@ -120,8 +120,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { /// WriteNodeReference - Write out a reference to the given node, /// using a unique identifier for each direct base and for the /// (only) virtual base. -llvm::raw_ostream& -InheritanceHierarchyWriter::WriteNodeReference(QualType Type, +llvm::raw_ostream& +InheritanceHierarchyWriter::WriteNodeReference(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); @@ -149,7 +149,7 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const { llvm::errs() << "Writing '" << Filename.c_str() << "'... "; - llvm::raw_fd_ostream O(Filename.c_str(), false, ErrMsg); + llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); if (ErrMsg.empty()) { InheritanceHierarchyWriter Writer(Context, O); diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 90ec4d33fdfe..d969776aa0ee 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -22,13 +22,13 @@ using namespace clang; NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(ASTContext &Context, +NestedNameSpecifier::FindOrInsert(ASTContext &Context, const NestedNameSpecifier &Mockup) { llvm::FoldingSetNodeID ID; Mockup.Profile(ID); void *InsertPos = 0; - NestedNameSpecifier *NNS + NestedNameSpecifier *NNS = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); if (!NNS) { NNS = new (Context, 4) NestedNameSpecifier(Mockup); @@ -39,10 +39,10 @@ NestedNameSpecifier::FindOrInsert(ASTContext &Context, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); - assert(Prefix && Prefix->isDependent() && "Prefix must be dependent"); + assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); @@ -52,10 +52,10 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, } NestedNameSpecifier * -NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, NamespaceDecl *NS) { assert(NS && "Namespace cannot be NULL"); - assert((!Prefix || + assert((!Prefix || (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && "Broken nested name specifier"); NestedNameSpecifier Mockup; @@ -75,7 +75,17 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, Mockup.Specifier = T; return FindOrInsert(Context, Mockup); } - + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) { + assert(II && "Identifier cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(0); + Mockup.Prefix.setInt(Identifier); + Mockup.Specifier = II; + return FindOrInsert(Context, Mockup); +} + NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) { if (!Context.GlobalNestedNameSpecifier) Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); @@ -105,8 +115,8 @@ bool NestedNameSpecifier::isDependent() const { /// \brief Print this nested name specifier to the given output /// stream. -void -NestedNameSpecifier::print(llvm::raw_ostream &OS, +void +NestedNameSpecifier::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { if (getPrefix()) getPrefix()->print(OS, Policy); @@ -131,15 +141,34 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, std::string TypeStr; Type *T = getAsType(); - // If this is a qualified name type, suppress the qualification: - // it's part of our nested-name-specifier sequence anyway. FIXME: - // We should be able to assert that this doesn't happen. - if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T)) - T = QualT->getNamedType().getTypePtr(); - PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressTagKind = true; - T->getAsStringInternal(TypeStr, InnerPolicy); + InnerPolicy.SuppressScope = true; + + // Nested-name-specifiers are intended to contain minimally-qualified + // types. An actual QualifiedNameType will not occur, since we'll store + // just the type that is referred to in the nested-name-specifier (e.g., + // a TypedefType, TagType, etc.). However, when we are dealing with + // dependent template-id types (e.g., Outer<T>::template Inner<U>), + // the type requires its own nested-name-specifier for uniqueness, so we + // suppress that nested-name-specifier during printing. + assert(!isa<QualifiedNameType>(T) && + "Qualified name type in nested-name-specifier"); + if (const TemplateSpecializationType *SpecType + = dyn_cast<TemplateSpecializationType>(T)) { + // Print the template name without its corresponding + // nested-name-specifier. + SpecType->getTemplateName().print(OS, InnerPolicy, true); + + // Print the template argument list. + TypeStr = TemplateSpecializationType::PrintTemplateArgumentList( + SpecType->getArgs(), + SpecType->getNumArgs(), + InnerPolicy); + } else { + // Print the type normally + T->getAsStringInternal(TypeStr, InnerPolicy); + } OS << TypeStr; break; } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 9d87daa0bfd8..48251d52fd2a 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -32,7 +32,7 @@ ParentMap::ParentMap(Stmt* S) : Impl(0) { if (S) { MapTy *M = new MapTy(); BuildParentMap(*M, S); - Impl = M; + Impl = M; } } @@ -54,16 +54,16 @@ Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const { bool ParentMap::isConsumedExpr(Expr* E) const { Stmt *P = getParent(E); Stmt *DirectChild = E; - + // Ignore parents that are parentheses or casts. while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) { DirectChild = P; P = getParent(P); } - + if (!P) return false; - + switch (P->getStmtClass()) { default: return isa<Expr>(P); @@ -78,7 +78,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const { case Stmt::ForStmtClass: return DirectChild == cast<ForStmt>(P)->getCond(); case Stmt::WhileStmtClass: - return DirectChild == cast<WhileStmt>(P)->getCond(); + return DirectChild == cast<WhileStmt>(P)->getCond(); case Stmt::DoStmtClass: return DirectChild == cast<DoStmt>(P)->getCond(); case Stmt::IfStmtClass: diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp new file mode 100644 index 000000000000..c79cc3c1dbb1 --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -0,0 +1,674 @@ +//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RecordLayoutBuilder.h" + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include <llvm/ADT/SmallSet.h> +#include <llvm/Support/MathExtras.h> + +using namespace clang; + +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) + : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0), + DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), + PrimaryBase(0), PrimaryBaseWasVirtual(false) {} + +/// LayoutVtable - Lay out the vtable and set PrimaryBase. +void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { + if (!RD->isDynamicClass()) { + // There is no primary base in this case. + return; + } + + SelectPrimaryBase(RD); + if (PrimaryBase == 0) { + int AS = 0; + UpdateAlignment(Ctx.Target.getPointerAlign(AS)); + Size += Ctx.Target.getPointerWidth(AS); + DataSize = Size; + } +} + +void +ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + // Skip the PrimaryBase here, as it is laid down first. + if (Base != PrimaryBase || PrimaryBaseWasVirtual) + LayoutBaseNonVirtually(Base, false); + } + } +} + +// Helper routines related to the abi definition from: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but +/// no other data. +bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0)) + return true; + return false; +} + +void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + + // If the record has a primary base class that is virtual, add it to the set + // of primary bases. + if (Layout.getPrimaryBaseWasVirtual()) + IndirectPrimaryBases.insert(Layout.getPrimaryBase()); + + // Now traverse all bases and find primary bases for them. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (Base->getNumVBases()) + IdentifyPrimaryBases(Base); + } +} + +void +ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, + const CXXRecordDecl *&FirstPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (!i->isVirtual()) { + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase) + return; + continue; + } + if (IsNearlyEmpty(Base)) { + if (FirstPrimary==0) + FirstPrimary = Base; + if (!IndirectPrimaryBases.count(Base)) { + setPrimaryBase(Base, true); + return; + } + } + } +} + +/// SelectPrimaryBase - Selects the primary base for the given class and +/// record that with setPrimaryBase. We also calculate the IndirectPrimaries. +void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { + // Compute all the primary virtual bases for all of our direct and + // indirect bases, and record all their primary virtual base classes. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + IdentifyPrimaryBases(Base); + } + + // If the record has a dynamic base class, attempt to choose a primary base + // class. It is the first (in direct base class order) non-virtual dynamic + // base class, if one exists. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (!i->isVirtual()) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (Base->isDynamicClass()) { + // We found it. + setPrimaryBase(Base, false); + return; + } + } + } + + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary virtual base class, if one exists. + + // If we have no virtual bases at this point, bail out as the searching below + // is expensive. + if (RD->getNumVBases() == 0) + return; + + // Then we can search for the first nearly empty virtual base itself. + const CXXRecordDecl *FirstPrimary = 0; + SelectPrimaryVBase(RD, FirstPrimary); + + // Otherwise if is the first nearly empty virtual base, if one exists, + // otherwise there is no primary base class. + if (!PrimaryBase) + setPrimaryBase(FirstPrimary, true); +} + +void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { + LayoutBaseNonVirtually(RD, true); +} + +void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *PB, + int64_t Offset, + llvm::SmallSet<const CXXRecordDecl*, 32> &mark, + llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); +#if 0 + const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PB = L.getPrimaryBase(); + if (PB && L.getPrimaryBaseWasVirtual() + && IndirectPrimary.count(PB)) { + int64_t BaseOffset; + // FIXME: calculate this. + BaseOffset = (1<<63) | (1<<31); + VBases.push_back(PB); + VBaseOffsets.push_back(BaseOffset); + } +#endif + int64_t BaseOffset = Offset;; + // FIXME: Calculate BaseOffset. + if (i->isVirtual()) { + if (Base == PB) { + // Only lay things out once. + if (mark.count(Base)) + continue; + // Mark it so we don't lay it out twice. + mark.insert(Base); + assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong"); + VBases.push_back(std::make_pair(Base, Offset)); + } else if (IndirectPrimary.count(Base)) { + // Someone else will eventually lay this out. + ; + } else { + // Only lay things out once. + if (mark.count(Base)) + continue; + // Mark it so we don't lay it out twice. + mark.insert(Base); + LayoutVirtualBase(Base); + BaseOffset = VBases.back().second; + } + } + if (Base->getNumVBases()) { + const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); + const CXXRecordDecl *PB = L.getPrimaryBase(); + LayoutVirtualBases(Base, PB, BaseOffset, mark, IndirectPrimary); + } + } +} + +bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, + uint64_t Offset) const { + // Look for an empty class with the same type at the same offset. + for (EmptyClassOffsetsTy::const_iterator I = + EmptyClassOffsets.lower_bound(Offset), + E = EmptyClassOffsets.upper_bound(Offset); I != E; ++I) { + + if (I->second == RD) + return false; + } + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Check bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + + if (!canPlaceRecordAtOffset(Base, Offset + BaseClassOffset)) + return false; + } + + // Check fields. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + + if (!canPlaceFieldAtOffset(FD, Offset + FieldOffset)) + return false; + } + + // FIXME: virtual bases. + return true; +} + +bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, + uint64_t Offset) const { + QualType T = FD->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) + return canPlaceRecordAtOffset(RD, Offset); + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs<RecordType>(); + if (!RT) + return true; + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return true; + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + unsigned ElementOffset = Offset; + for (uint64_t I = 0; I != NumElements; ++I) { + if (!canPlaceRecordAtOffset(RD, ElementOffset)) + return false; + + ElementOffset += Info.getSize(); + } + } + + return true; +} + +void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD, + uint64_t Offset) { + if (RD->isEmpty()) + EmptyClassOffsets.insert(std::make_pair(Offset, RD)); + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + // Update bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + uint64_t BaseClassOffset = Info.getBaseClassOffset(Base); + UpdateEmptyClassOffsets(Base, Offset + BaseClassOffset); + } + + // Update fields. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + + uint64_t FieldOffset = Info.getFieldOffset(FieldNo); + UpdateEmptyClassOffsets(FD, Offset + FieldOffset); + } + + // FIXME: Update virtual bases. +} + +void +ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, + uint64_t Offset) { + QualType T = FD->getType(); + + if (const RecordType *RT = T->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + UpdateEmptyClassOffsets(RD, Offset); + return; + } + } + + if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { + QualType ElemTy = Ctx.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs<RecordType>(); + if (!RT) + return; + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD) + return; + + const ASTRecordLayout &Info = Ctx.getASTRecordLayout(RD); + + uint64_t NumElements = Ctx.getConstantArrayElementCount(AT); + unsigned ElementOffset = Offset; + + for (uint64_t I = 0; I != NumElements; ++I) { + UpdateEmptyClassOffsets(RD, ElementOffset); + ElementOffset += Info.getSize(); + } + } +} + +uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { + const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + + // If we have an empty base class, try to place it at offset 0. + if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { + // We were able to place the class at offset 0. + UpdateEmptyClassOffsets(RD, 0); + + Size = std::max(Size, BaseInfo.getSize()); + + return 0; + } + + unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); + + // Round up the current record size to the base's alignment boundary. + uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign); + + // Try to place the base. + while (true) { + if (canPlaceRecordAtOffset(RD, Offset)) + break; + + Offset += BaseAlign; + } + + if (!RD->isEmpty()) { + // Update the data size. + DataSize = Offset + BaseInfo.getNonVirtualSize(); + + Size = std::max(Size, DataSize); + } else + Size = std::max(Size, Offset + BaseInfo.getSize()); + + // Remember max struct/class alignment. + UpdateAlignment(BaseAlign); + + UpdateEmptyClassOffsets(RD, Offset); + return Offset; +} + +void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, + bool IsVirtualBase) { + // Layout the base. + unsigned Offset = LayoutBase(RD); + + // Add base class offsets. + if (IsVirtualBase) + VBases.push_back(std::make_pair(RD, Offset)); + else + Bases.push_back(std::make_pair(RD, Offset)); + +#if 0 + // And now add offsets for all our primary virtual bases as well, so + // they all have offsets. + const ASTRecordLayout *L = &BaseInfo; + const CXXRecordDecl *PB = L->getPrimaryBase(); + while (PB) { + if (L->getPrimaryBaseWasVirtual()) { + VBases.push_back(PB); + VBaseOffsets.push_back(Size); + } + PB = L->getPrimaryBase(); + if (PB) + L = &Ctx.getASTRecordLayout(PB); + } +#endif +} + +void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { + IsUnion = D->isUnion(); + + Packed = D->hasAttr<PackedAttr>(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + UpdateAlignment(AA->getAlignment()); + + // If this is a C++ class, lay out the vtable and the non-virtual bases. + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); + if (RD) { + LayoutVtable(RD); + // PrimaryBase goes first. + if (PrimaryBase) { + if (PrimaryBaseWasVirtual) + IndirectPrimaryBases.insert(PrimaryBase); + LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual); + } + LayoutNonVirtualBases(RD); + } + + LayoutFields(D); + + NonVirtualSize = Size; + NonVirtualAlignment = Alignment; + + if (RD) { + llvm::SmallSet<const CXXRecordDecl*, 32> mark; + LayoutVirtualBases(RD, PrimaryBase, 0, mark, IndirectPrimaryBases); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + if (ObjCInterfaceDecl *SD = D->getSuperClass()) { + const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); + + UpdateAlignment(SL.getAlignment()); + + // We start laying out ivars not at the end of the superclass + // structure, but at the next byte following the last field. + Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8); + DataSize = Size; + } + + Packed = D->hasAttr<PackedAttr>(); + + // The #pragma pack attribute specifies the maximum field alignment. + if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>()) + MaxFieldAlignment = PPA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + UpdateAlignment(AA->getAlignment()); + + // Layout each ivar sequentially. + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + Ctx.ShallowCollectObjCIvars(D, Ivars, Impl); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) + LayoutField(Ivars[i]); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + LayoutField(*Field); +} + +void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { + bool FieldPacked = Packed; + uint64_t FieldOffset = IsUnion ? 0 : DataSize; + uint64_t FieldSize; + unsigned FieldAlign; + + FieldPacked |= D->hasAttr<PackedAttr>(); + + if (const Expr *BitWidthExpr = D->getBitWidth()) { + // TODO: Need to check this algorithm on other targets! + // (tested on Linux-X86) + FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); + + std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + + FieldAlign = FieldInfo.second; + + if (FieldPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + + // Check if we need to add padding to give the field the correct + // alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // Padding members don't affect overall alignment + if (!D->getIdentifier()) + FieldAlign = 1; + } else { + if (D->getType()->isIncompleteArrayType()) { + // This is a flexible array member; we can't directly + // query getTypeInfo about these, so we figure it out here. + // Flexible array members don't have any size, but they + // have to be aligned appropriately for their element type. + FieldSize = 0; + const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); + FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); + } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { + std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + if (FieldPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + // The maximum field alignment overrides the aligned attribute. + if (MaxFieldAlignment) + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + + // Round up the current record size to the field's alignment boundary. + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + + if (!IsUnion) { + while (true) { + // Check if we can place the field at this offset. + if (canPlaceFieldAtOffset(D, FieldOffset)) + break; + + // We couldn't place the field at the offset. Try again at a new offset. + FieldOffset += FieldAlign; + } + + UpdateEmptyClassOffsets(D, FieldOffset); + } + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Reserve space for this field. + if (IsUnion) + Size = std::max(Size, FieldSize); + else + Size = FieldOffset + FieldSize; + + // Update the data size. + DataSize = Size; + + // Remember max struct/class alignment. + UpdateAlignment(FieldAlign); +} + +void ASTRecordLayoutBuilder::FinishLayout() { + // In C++, records cannot be of size 0. + if (Ctx.getLangOptions().CPlusPlus && Size == 0) + Size = 8; + // Finally, round the size of the record up to the alignment of the + // record itself. + Size = (Size + (Alignment-1)) & ~(Alignment-1); +} + +void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { + if (NewAlignment <= Alignment) + return; + + assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2")); + + Alignment = NewAlignment; +} + +const ASTRecordLayout * +ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, + const RecordDecl *D) { + ASTRecordLayoutBuilder Builder(Ctx); + + Builder.Layout(D); + + if (!isa<CXXRecordDecl>(D)) + return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + + // FIXME: This is not always correct. See the part about bitfields at + // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. + // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. + bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); + + // FIXME: This should be done in FinalizeLayout. + uint64_t DataSize = + IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; + uint64_t NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size(), + NonVirtualSize, + Builder.NonVirtualAlignment, + Builder.PrimaryBase, + Builder.PrimaryBaseWasVirtual, + Builder.Bases.data(), + Builder.Bases.size(), + Builder.VBases.data(), + Builder.VBases.size()); +} + +const ASTRecordLayout * +ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, + const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + ASTRecordLayoutBuilder Builder(Ctx); + + Builder.Layout(D, Impl); + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, + Builder.DataSize, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h new file mode 100644 index 000000000000..6e4cdd2fe2ee --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.h @@ -0,0 +1,146 @@ +//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H +#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/DataTypes.h" +#include <map> + +namespace clang { + class ASTContext; + class ASTRecordLayout; + class CXXRecordDecl; + class FieldDecl; + class ObjCImplementationDecl; + class ObjCInterfaceDecl; + class RecordDecl; + +class ASTRecordLayoutBuilder { + ASTContext &Ctx; + + uint64_t Size; + unsigned Alignment; + llvm::SmallVector<uint64_t, 16> FieldOffsets; + + /// Packed - Whether the record is packed or not. + bool Packed; + + /// MaxFieldAlignment - The maximum allowed field alignment. This is set by + /// #pragma pack. + unsigned MaxFieldAlignment; + + /// DataSize - The data size of the record being laid out. + uint64_t DataSize; + + bool IsUnion; + + uint64_t NonVirtualSize; + unsigned NonVirtualAlignment; + const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseWasVirtual; + + typedef llvm::SmallVector<std::pair<const CXXRecordDecl *, + uint64_t>, 4> BaseOffsetsTy; + + /// Bases - base classes and their offsets from the record. + BaseOffsetsTy Bases; + + // VBases - virtual base classes and their offsets from the record. + BaseOffsetsTy VBases; + + /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are + /// primary base classes for some other direct or indirect base class. + llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases; + + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy; + EmptyClassOffsetsTy EmptyClassOffsets; + + ASTRecordLayoutBuilder(ASTContext &Ctx); + + void Layout(const RecordDecl *D); + void Layout(const CXXRecordDecl *D); + void Layout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl); + + void LayoutFields(const RecordDecl *D); + void LayoutField(const FieldDecl *D); + + void SelectPrimaryBase(const CXXRecordDecl *RD); + void SelectPrimaryVBase(const CXXRecordDecl *RD, + const CXXRecordDecl *&FirstPrimary); + + /// IdentifyPrimaryBases - Identify all virtual base classes, direct or + /// indirect, that are primary base classes for some other direct or indirect + /// base class. + void IdentifyPrimaryBases(const CXXRecordDecl *RD); + + void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) { + PrimaryBase = PB; + PrimaryBaseWasVirtual = Virtual; + } + + bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + + /// LayoutBase - Will lay out a base and return the offset where it was + /// placed, in bits. + uint64_t LayoutBase(const CXXRecordDecl *RD); + + void LayoutVtable(const CXXRecordDecl *RD); + void LayoutNonVirtualBases(const CXXRecordDecl *RD); + void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); + void LayoutVirtualBase(const CXXRecordDecl *RD); + void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB, + int64_t Offset, + llvm::SmallSet<const CXXRecordDecl*, 32> &mark, + llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary); + + /// canPlaceRecordAtOffset - Return whether a record (either a base class + /// or a field) can be placed at the given offset. + /// Returns false if placing the record will result in two components + /// (direct or indirect) of the same type having the same offset. + bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const; + + /// canPlaceFieldAtOffset - Return whether a field can be placed at the given + /// offset. + bool canPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) const; + + /// UpdateEmptyClassOffsets - Called after a record (either a base class + /// or a field) has been placed at the given offset. Will update the + /// EmptyClassOffsets map if the class is empty or has any empty bases or + /// fields. + void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset); + + /// UpdateEmptyClassOffsets - Called after a field has been placed at the + /// given offset. + void UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset); + + /// FinishLayout - Finalize record layout. Adjust record size based on the + /// alignment. + void FinishLayout(); + + void UpdateAlignment(unsigned NewAlignment); + + ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT + void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT +public: + static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, + const RecordDecl *RD); + static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, + const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl); +}; + +} // end namespace clang + +#endif + diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 17577910d2a3..3a838fadafa4 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Type.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include <cstdio> using namespace clang; static struct StmtClassNameTable { @@ -43,7 +44,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { } const char *Stmt::getStmtClassName() const { - return getStmtInfoTableEntry(sClass).Name; + return getStmtInfoTableEntry((StmtClass)sClass).Name; } void Stmt::DestroyChildren(ASTContext &C) { @@ -51,19 +52,12 @@ void Stmt::DestroyChildren(ASTContext &C) { if (Stmt* Child = *I++) Child->Destroy(C); } -void Stmt::Destroy(ASTContext &C) { +void Stmt::DoDestroy(ASTContext &C) { DestroyChildren(C); - // FIXME: Eventually all Stmts should be allocated with the allocator - // in ASTContext, just like with Decls. this->~Stmt(); C.Deallocate((void *)this); } -void DeclStmt::Destroy(ASTContext &C) { - this->~DeclStmt(); - C.Deallocate((void *)this); -} - void Stmt::PrintStats() { // Ensure the table is primed. getStmtInfoTableEntry(Stmt::NullStmtClass); @@ -99,16 +93,18 @@ bool Stmt::CollectingStats(bool enable) { return StatSwitch; } -NullStmt* NullStmt::Clone(ASTContext &C) const { - return new (C) NullStmt(SemiLoc); -} - -ContinueStmt* ContinueStmt::Clone(ASTContext &C) const { - return new (C) ContinueStmt(ContinueLoc); -} +void SwitchStmt::DoDestroy(ASTContext &Ctx) { + // Destroy the SwitchCase statements in this switch. In the normal + // case, this loop will merely decrement the reference counts from + // the Retain() calls in addSwitchCase(); + SwitchCase *SC = FirstCase; + while (SC) { + SwitchCase *Next = SC->getNextSwitchCase(); + SC->Destroy(Ctx); + SC = Next; + } -BreakStmt* BreakStmt::Clone(ASTContext &C) const { - return new (C) BreakStmt(BreakLoc); + Stmt::DoDestroy(Ctx); } void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { @@ -191,7 +187,7 @@ std::string AsmStmt::getInputConstraint(unsigned i) const { void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, - unsigned NumInputs, + unsigned NumInputs, const std::string *Names, StringLiteral **Constraints, Stmt **Exprs) { @@ -200,7 +196,7 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, this->Names.clear(); this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs); this->Constraints.clear(); - this->Constraints.insert(this->Constraints.end(), + this->Constraints.insert(this->Constraints.end(), Constraints, Constraints + NumOutputs + NumInputs); this->Exprs.clear(); this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs); @@ -211,13 +207,13 @@ void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, /// This returns -1 if the operand name is invalid. int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { unsigned NumPlusOperands = 0; - + // Check if this is an output operand. for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) { if (getOutputName(i) == SymbolicName) return i; } - + for (unsigned i = 0, e = getNumInputs(); i != e; ++i) if (getInputName(i) == SymbolicName) return getNumOutputs() + NumPlusOperands + i; @@ -239,7 +235,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, const char *StrStart = getAsmString()->getStrData(); const char *StrEnd = StrStart + getAsmString()->getByteLength(); const char *CurPtr = StrStart; - + // "Simple" inline asms have no constraints or operands, just convert the asm // string to escape $'s. if (isSimple()) { @@ -261,7 +257,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, // CurStringPiece - The current string that we are building up as we scan the // asm string. std::string CurStringPiece; - + while (1) { // Done with the string? if (CurPtr == StrEnd) { @@ -269,7 +265,7 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } - + char CurChar = *CurPtr++; if (CurChar == '$') { CurStringPiece += "$$"; @@ -278,48 +274,48 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, CurStringPiece += CurChar; continue; } - + // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } - + char EscapedChar = *CurPtr++; if (EscapedChar == '%') { // %% -> % // Escaped percentage sign. CurStringPiece += '%'; continue; } - + if (EscapedChar == '=') { // %= -> Generate an unique ID. CurStringPiece += "${:uid}"; continue; } - + // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. if (!CurStringPiece.empty()) { Pieces.push_back(AsmStringPiece(CurStringPiece)); CurStringPiece.clear(); } - + // Handle %x4 and %x[foo] by capturing x as the modifier character. char Modifier = '\0'; if (isalpha(EscapedChar)) { Modifier = EscapedChar; EscapedChar = *CurPtr++; } - + if (isdigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; - + --CurPtr; while (CurPtr != StrEnd && isdigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); - + unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { @@ -330,20 +326,20 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, Pieces.push_back(AsmStringPiece(N, Modifier)); continue; } - + // Handle %[foo], a symbolic operand reference. if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; - + // Find the ']'. const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); if (NameEnd == 0) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; - + std::string SymbolicName(CurPtr, NameEnd); - + int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. @@ -351,11 +347,11 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, return diag::err_asm_unknown_symbolic_operand_name; } Pieces.push_back(AsmStringPiece(N, Modifier)); - + CurPtr = NameEnd+1; continue; } - + DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } @@ -513,7 +509,7 @@ Stmt::child_iterator ReturnStmt::child_end() { } // AsmStmt -Stmt::child_iterator AsmStmt::child_begin() { +Stmt::child_iterator AsmStmt::child_begin() { return Exprs.empty() ? 0 : &Exprs[0]; } Stmt::child_iterator AsmStmt::child_end() { @@ -569,10 +565,10 @@ QualType CXXCatchStmt::getCaughtType() { return QualType(); } -void CXXCatchStmt::Destroy(ASTContext& C) { +void CXXCatchStmt::DoDestroy(ASTContext& C) { if (ExceptionDecl) ExceptionDecl->Destroy(C); - Stmt::Destroy(C); + Stmt::DoDestroy(C); } // CXXTryStmt diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index bc096bf0d9f3..0465999a94cc 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -30,12 +30,12 @@ namespace { SourceManager *SM; FILE *F; unsigned IndentLevel; - + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump /// the first few levels of an AST. This keeps track of how many ast levels /// are left. unsigned MaxDepth; - + /// LastLocFilename/LastLocLine - Keep track of the last location we print /// out so that we can print out deltas from then on out. const char *LastLocFilename; @@ -47,18 +47,18 @@ namespace { LastLocFilename = ""; LastLocLine = ~0U; } - + void DumpSubTree(Stmt *S) { // Prune the recursion if not using dump all. if (MaxDepth == 0) return; - + ++IndentLevel; if (S) { if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) VisitDeclStmt(DS); - else { + else { Visit(S); - + // Print out children. Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); if (CI != CE) { @@ -75,25 +75,22 @@ namespace { } --IndentLevel; } - + void DumpDeclarator(Decl *D); - + void Indent() const { for (int i = 0, e = IndentLevel; i < e; ++i) fprintf(F, " "); } - + void DumpType(QualType T) { fprintf(F, "'%s'", T.getAsString().c_str()); if (!T.isNull()) { - // If the type is directly a typedef, strip off typedefness to give at - // least one level of concreteness. - if (TypedefType *TDT = dyn_cast<TypedefType>(T)) { - QualType Simplified = - TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); + // If the type is sugared, also dump a (shallow) desugared type. + QualType Simplified = T.getDesugaredType(); + if (Simplified != T) fprintf(F, ":'%s'", Simplified.getAsString().c_str()); - } } } void DumpStmt(const Stmt *Node) { @@ -108,15 +105,16 @@ namespace { } void DumpSourceRange(const Stmt *Node); void DumpLocation(SourceLocation Loc); - + // Stmts. void VisitStmt(Stmt *Node); void VisitDeclStmt(DeclStmt *Node); void VisitLabelStmt(LabelStmt *Node); void VisitGotoStmt(GotoStmt *Node); - + // Exprs void VisitExpr(Expr *Node); + void VisitCastExpr(CastExpr *Node); void VisitDeclRefExpr(DeclRefExpr *Node); void VisitPredefinedExpr(PredefinedExpr *Node); void VisitCharacterLiteral(CharacterLiteral *Node); @@ -137,14 +135,19 @@ namespace { void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); void VisitCXXThisExpr(CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); - + void VisitCXXConstructExpr(CXXConstructExpr *Node); + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); + void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node); + void DumpCXXTemporary(CXXTemporary *Temporary); + // ObjC void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); - void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node); + void VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); void VisitObjCSuperExpr(ObjCSuperExpr *Node); }; @@ -156,7 +159,7 @@ namespace { void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); - + if (SpellingLoc.isInvalid()) { fprintf(stderr, "<invalid sloc>"); return; @@ -182,11 +185,11 @@ void StmtDumper::DumpLocation(SourceLocation Loc) { void StmtDumper::DumpSourceRange(const Stmt *Node) { // Can't translate locations if a SourceManager isn't available. if (SM == 0) return; - + // TODO: If the parent expression is available, we can print a delta vs its // location. SourceRange R = Node->getSourceRange(); - + fprintf(stderr, " <"); DumpLocation(R.getBegin()); if (R.getBegin() != R.getEnd()) { @@ -194,7 +197,7 @@ void StmtDumper::DumpSourceRange(const Stmt *Node) { DumpLocation(R.getEnd()); } fprintf(stderr, ">"); - + // <t2.c:123:421[blah], t2.c:412:321> } @@ -220,15 +223,15 @@ void StmtDumper::DumpDeclarator(Decl *D) { // Emit storage class for vardecls. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getStorageClass() != VarDecl::None) - fprintf(F, "%s ", + fprintf(F, "%s ", VarDecl::getStorageClassSpecifierString(V->getStorageClass())); } - + std::string Name = VD->getNameAsString(); - VD->getType().getAsStringInternal(Name, + VD->getType().getAsStringInternal(Name, PrintingPolicy(VD->getASTContext().getLangOptions())); fprintf(F, "%s", Name.c_str()); - + // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getInit()) { @@ -293,32 +296,37 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } +void StmtDumper::VisitCastExpr(CastExpr *Node) { + DumpExpr(Node); + fprintf(F, " <%s>", Node->getCastKindName()); +} + void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); fprintf(F, " "); switch (Node->getDecl()->getKind()) { - case Decl::Function: fprintf(F,"FunctionDecl"); break; - case Decl::Var: fprintf(F,"Var"); break; - case Decl::ParmVar: fprintf(F,"ParmVar"); break; - case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; - case Decl::Typedef: fprintf(F,"Typedef"); break; - case Decl::Record: fprintf(F,"Record"); break; - case Decl::Enum: fprintf(F,"Enum"); break; - case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; - case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; - case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; - default: fprintf(F,"Decl"); break; + default: fprintf(F,"Decl"); break; + case Decl::Function: fprintf(F,"FunctionDecl"); break; + case Decl::Var: fprintf(F,"Var"); break; + case Decl::ParmVar: fprintf(F,"ParmVar"); break; + case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; + case Decl::Typedef: fprintf(F,"Typedef"); break; + case Decl::Record: fprintf(F,"Record"); break; + case Decl::Enum: fprintf(F,"Enum"); break; + case Decl::CXXRecord: fprintf(F,"CXXRecord"); break; + case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; + case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; } - - fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), + + fprintf(F, "='%s' %p", Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); } void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); - fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), + fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); if (Node->isFreeIvar()) fprintf(F, " isFreeIvar"); @@ -359,7 +367,7 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) { switch (char C = Str->getStrData()[i]) { default: if (isprint(C)) - fputc(C, F); + fputc(C, F); else fprintf(F, "\\%03o", C); break; @@ -390,7 +398,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", - Node->getMemberDecl()->getNameAsString().c_str(), + Node->getMemberDecl()->getNameAsString().c_str(), (void*)Node->getMemberDecl()); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -431,8 +439,9 @@ void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); - fprintf(F, " %s<%s>", Node->getCastName(), - Node->getTypeAsWritten().getAsString().c_str()); + fprintf(F, " %s<%s> <%s>", Node->getCastName(), + Node->getTypeAsWritten().getAsString().c_str(), + Node->getCastKindName()); } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { @@ -447,10 +456,37 @@ void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { DumpExpr(Node); - fprintf(F, " functional cast to %s", + fprintf(F, " functional cast to %s", Node->getTypeAsWritten().getAsString().c_str()); } +void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { + DumpExpr(Node); + if (Node->isElidable()) + fprintf(F, " elidable"); +} + +void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { + DumpExpr(Node); + fprintf(F, " "); + DumpCXXTemporary(Node->getTemporary()); +} + +void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) { + DumpExpr(Node); + ++IndentLevel; + for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { + fprintf(F, "\n"); + Indent(); + DumpCXXTemporary(Node->getTemporary(i)); + } + --IndentLevel; +} + +void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { + fprintf(F, "(CXXTemporary %p)", (void *)Temporary); +} + //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// @@ -464,21 +500,21 @@ void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); DumpType(Node->getEncodedType()); } void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); fprintf(F, "%s", Node->getSelector().getAsString().c_str()); } void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - + fprintf(F, " "); fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str()); } @@ -486,16 +522,17 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - fprintf(F, " Kind=PropertyRef Property=\"%s\"", + fprintf(F, " Kind=PropertyRef Property=\"%s\"", Node->getProperty()->getNameAsString().c_str()); } -void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { +void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node) { DumpExpr(Node); - + ObjCMethodDecl *Getter = Node->getGetterMethod(); ObjCMethodDecl *Setter = Node->getSetterMethod(); - fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", + fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", Getter->getSelector().getAsString().c_str(), Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); } diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 5c22e28894f9..4f62b66e257d 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -23,10 +23,10 @@ static inline VariableArrayType* FindVA(Type* t) { if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt)) if (vat->getSizeExpr()) return vat; - + t = vt->getElementType().getTypePtr(); } - + return NULL; } @@ -39,20 +39,20 @@ void StmtIteratorBase::NextVA() { if (p) return; - + if (inDecl()) { - if (VarDecl* VD = dyn_cast<VarDecl>(decl)) + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) if (VD->Init) return; - + NextDecl(); } else if (inDeclGroup()) { - if (VarDecl* VD = dyn_cast<VarDecl>(*DGI)) + if (VarDecl* VD = dyn_cast<VarDecl>(*DGI)) if (VD->Init) return; - - NextDecl(); + + NextDecl(); } else { assert (inSizeOfTypeVA()); @@ -63,10 +63,10 @@ void StmtIteratorBase::NextVA() { void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { assert (getVAPtr() == NULL); - + if (inDecl()) { assert (decl); - + // FIXME: SIMPLIFY AWAY. if (ImmediateAdvance) decl = 0; @@ -75,10 +75,10 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { } else { assert (inDeclGroup()); - + if (ImmediateAdvance) ++DGI; - + for ( ; DGI != DGE; ++DGI) if (HandleDecl(*DGI)) return; @@ -88,18 +88,18 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { } bool StmtIteratorBase::HandleDecl(Decl* D) { - - if (VarDecl* VD = dyn_cast<VarDecl>(D)) { + + if (VarDecl* VD = dyn_cast<VarDecl>(D)) { if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { setVAPtr(VAPtr); return true; } - + if (VD->getInit()) return true; } else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) { - if (VariableArrayType* VAPtr = + if (VariableArrayType* VAPtr = FindVA(TD->getUnderlyingType().getTypePtr())) { setVAPtr(VAPtr); return true; @@ -110,7 +110,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { return true; } - return false; + return false; } StmtIteratorBase::StmtIteratorBase(Decl* d) @@ -130,19 +130,19 @@ StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) } Stmt*& StmtIteratorBase::GetDeclExpr() const { - + if (VariableArrayType* VAPtr = getVAPtr()) { assert (VAPtr->SizeExpr); return VAPtr->SizeExpr; } assert (inDecl() || inDeclGroup()); - + if (inDeclGroup()) { VarDecl* VD = cast<VarDecl>(*DGI); return *VD->getInitAddress(); } - + assert (inDecl()); if (VarDecl* VD = dyn_cast<VarDecl>(decl)) { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index fec17fb22352..05d0c2683545 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -17,7 +17,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/Streams.h" #include "llvm/Support/Format.h" using namespace clang; @@ -34,12 +33,12 @@ namespace { PrintingPolicy Policy; public: - StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, + StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, const PrintingPolicy &Policy, unsigned Indentation = 0) : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), Policy(Policy) {} - + void PrintStmt(Stmt *S) { PrintStmt(S, Policy.Indentation); } @@ -64,29 +63,29 @@ namespace { void PrintRawDeclStmt(DeclStmt *S); void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); - + void PrintExpr(Expr *E) { if (E) Visit(E); else OS << "<null expr>"; } - + llvm::raw_ostream &Indent(int Delta = 0) { for (int i = 0, e = IndentLevel+Delta; i < e; ++i) OS << " "; return OS; } - + bool PrintOffsetOfDesignator(Expr *E); void VisitUnaryOffsetOf(UnaryOperator *Node); - - void Visit(Stmt* S) { + + void Visit(Stmt* S) { if (Helper && Helper->handledStmt(S,OS)) return; else StmtVisitor<StmtPrinter>::Visit(S); } - + void VisitStmt(Stmt *Node); #define STMT(CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); @@ -109,7 +108,7 @@ void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); I != E; ++I) PrintStmt(*I); - + Indent() << "}"; } @@ -120,7 +119,7 @@ void StmtPrinter::PrintRawDecl(Decl *D) { void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); llvm::SmallVector<Decl*, 2> Decls; - for ( ; Begin != End; ++Begin) + for ( ; Begin != End; ++Begin) Decls.push_back(*Begin); Decl::printGroup(Decls.data(), Decls.size(), OS, Policy, IndentLevel); @@ -150,7 +149,7 @@ void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { PrintExpr(Node->getRHS()); } OS << ":\n"; - + PrintStmt(Node->getSubStmt(), 0); } @@ -168,7 +167,7 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; PrintExpr(If->getCond()); OS << ')'; - + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { OS << ' '; PrintRawCompoundStmt(CS); @@ -178,10 +177,10 @@ void StmtPrinter::PrintRawIfStmt(IfStmt *If) { PrintStmt(If->getThen()); if (If->getElse()) Indent(); } - + if (Stmt *Else = If->getElse()) { OS << "else"; - + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) { OS << ' '; PrintRawCompoundStmt(CS); @@ -205,7 +204,7 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { Indent() << "switch ("; PrintExpr(Node->getCond()); OS << ")"; - + // Pretty print compoundstmt bodies (very common). if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { OS << " "; @@ -238,7 +237,7 @@ void StmtPrinter::VisitDoStmt(DoStmt *Node) { PrintStmt(Node->getBody()); Indent(); } - + OS << "while ("; PrintExpr(Node->getCond()); OS << ");\n"; @@ -263,7 +262,7 @@ void StmtPrinter::VisitForStmt(ForStmt *Node) { PrintExpr(Node->getInc()); } OS << ") "; - + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; @@ -282,7 +281,7 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { OS << " in "; PrintExpr(Node->getCollection()); OS << ") "; - + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { PrintRawCompoundStmt(CS); OS << "\n"; @@ -323,63 +322,63 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { Indent() << "asm "; - + if (Node->isVolatile()) OS << "volatile "; - + OS << "("; VisitStringLiteral(Node->getAsmString()); - + // Outputs if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { if (i != 0) OS << ", "; - + if (!Node->getOutputName(i).empty()) { OS << '['; OS << Node->getOutputName(i); OS << "] "; } - + VisitStringLiteral(Node->getOutputConstraintLiteral(i)); OS << " "; Visit(Node->getOutputExpr(i)); } - + // Inputs if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { if (i != 0) OS << ", "; - + if (!Node->getInputName(i).empty()) { OS << '['; OS << Node->getInputName(i); OS << "] "; } - + VisitStringLiteral(Node->getInputConstraintLiteral(i)); OS << " "; Visit(Node->getInputExpr(i)); } - + // Clobbers if (Node->getNumClobbers() != 0) OS << " : "; - + for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { if (i != 0) OS << ", "; - + VisitStringLiteral(Node->getClobber(i)); } - + OS << ");\n"; } @@ -389,11 +388,11 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawCompoundStmt(TS); OS << "\n"; } - - for (ObjCAtCatchStmt *catchStmt = + + for (ObjCAtCatchStmt *catchStmt = static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts()); - catchStmt; - catchStmt = + catchStmt; + catchStmt = static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) { Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { @@ -401,19 +400,18 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { PrintRawDecl(DS); } OS << ")"; - if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) - { - PrintRawCompoundStmt(CS); - OS << "\n"; - } + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } } - - if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>( - Node->getFinallyStmt())) { + + if (ObjCAtFinallyStmt *FS = static_cast<ObjCAtFinallyStmt *>( + Node->getFinallyStmt())) { Indent() << "@finally"; PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody())); OS << "\n"; - } + } } void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { @@ -459,7 +457,7 @@ void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { Indent() << "try "; PrintRawCompoundStmt(Node->getTryBlock()); - for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { + for (unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { OS << " "; PrintRawCXXCatchStmt(Node->getHandler(i)); } @@ -478,14 +476,14 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { OS << Node->getDecl()->getNameAsString(); } -void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { +void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { NamedDecl *D = Node->getDecl(); Node->getQualifier()->print(OS, Policy); OS << D->getNameAsString(); } -void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { +void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { Node->getQualifier()->print(OS, Policy); OS << Node->getDeclName().getAsString(); } @@ -494,12 +492,10 @@ void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) { if (Node->getQualifier()) Node->getQualifier()->print(OS, Policy); Node->getTemplateName().print(OS, Policy, true); - OS << '<'; OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy); - OS << '>'; } void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { @@ -518,12 +514,15 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { OS << Node->getProperty()->getNameAsCString(); } -void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { +void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *Node) { if (Node->getBase()) { PrintExpr(Node->getBase()); OS << "."; } - // FIXME: Setter/Getter names + if (Node->getGetterMethod()) + OS << Node->getGetterMethod()->getNameAsString(); + } void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { @@ -594,9 +593,9 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { bool isSigned = Node->getType()->isSignedIntegerType(); OS << Node->getValue().toString(10, isSigned); - + // Emit suffixes. Integer literals are always a builtin integer type. - switch (Node->getType()->getAsBuiltinType()->getKind()) { + switch (Node->getType()->getAs<BuiltinType>()->getKind()) { default: assert(0 && "Unexpected type for integer literal!"); case BuiltinType::Int: break; // no suffix. case BuiltinType::UInt: OS << 'U'; break; @@ -623,7 +622,7 @@ void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { // FIXME: this doesn't print wstrings right. for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { unsigned char Char = Str->getStrData()[i]; - + switch (Char) { default: if (isprint(Char)) @@ -653,7 +652,7 @@ void StmtPrinter::VisitParenExpr(ParenExpr *Node) { void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { if (!Node->isPostfix()) { OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); - + // Print a space if this is an "identifier operator" like __real, or if // it might be concatenated incorrectly like '+'. switch (Node->getOpcode()) { @@ -671,7 +670,7 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { } } PrintExpr(Node->getSubExpr()); - + if (Node->isPostfix()) OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); } @@ -737,8 +736,22 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { OS << (Node->isArrow() ? "->" : "."); // FIXME: Suppress printing references to unnamed objects // representing anonymous unions/structs + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + OS << Node->getMemberDecl()->getNameAsString(); + + if (Node->hasExplicitTemplateArgumentList()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); } +void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->isa" : ".isa"); +} + void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { PrintExpr(Node->getBase()); OS << "."; @@ -774,7 +787,7 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { } void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { PrintExpr(Node->getCond()); - + if (Node->getLHS()) { OS << " ? "; PrintExpr(Node->getLHS()); @@ -783,7 +796,7 @@ void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { else { // Handle GCC extension where LHS can be NULL. OS << " ?: "; } - + PrintExpr(Node->getRHS()); } @@ -845,6 +858,15 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { OS << " }"; } +void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) { + OS << "( "; + for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << " )"; +} + void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(), DEnd = Node->designators_end(); @@ -861,7 +883,7 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { } else { PrintExpr(Node->getArrayRangeStart(*D)); OS << " ... "; - PrintExpr(Node->getArrayRangeEnd(*D)); + PrintExpr(Node->getArrayRangeEnd(*D)); } OS << "]"; } @@ -1013,7 +1035,7 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << Node->getType().getAsString(); OS << "("; for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), - ArgEnd = Node->arg_end(); + ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { if (Arg != Node->arg_begin()) OS << ", "; @@ -1082,6 +1104,20 @@ void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { PrintExpr(E->getArgument()); } +void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + PrintExpr(E->getBase()); + if (E->isArrow()) + OS << "->"; + else + OS << '.'; + if (E->getQualifier()) + E->getQualifier()->print(OS, Policy); + + std::string TypeS; + E->getDestroyedType().getAsStringInternal(TypeS, Policy); + OS << TypeS; +} + void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { OS << E->getName().getAsString(); } @@ -1095,13 +1131,13 @@ void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { PrintExpr(E->getSubExpr()); } -void +void StmtPrinter::VisitCXXUnresolvedConstructExpr( CXXUnresolvedConstructExpr *Node) { OS << Node->getTypeAsWritten().getAsString(); OS << "("; for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(), - ArgEnd = Node->arg_end(); + ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { if (Arg != Node->arg_begin()) OS << ", "; @@ -1113,7 +1149,20 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr( void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + else if (Node->hasExplicitTemplateArgumentList()) + // FIXME: Track use of "template" keyword explicitly? + OS << "template "; + OS << Node->getMember().getAsString(); + + if (Node->hasExplicitTemplateArgumentList()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } } static const char *getTypeTraitName(UnaryTypeTrait UTT) { @@ -1142,7 +1191,7 @@ void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { << E->getQueriedType().getAsString() << ")"; } -// Obj-C +// Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { OS << "@"; @@ -1180,7 +1229,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << ":"; } else OS << ", "; // Handle variadic methods. - + PrintExpr(Mess->getArg(i)); } } @@ -1194,9 +1243,9 @@ void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) { void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { BlockDecl *BD = Node->getBlockDecl(); OS << "^"; - + const FunctionType *AFT = Node->getFunctionType(); - + if (isa<FunctionNoProtoType>(AFT)) { OS << "()"; } else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) { @@ -1209,7 +1258,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { (*AI)->getType().getAsStringInternal(ParamStr, Policy); OS << ParamStr; } - + const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); if (FT->isVariadic()) { if (!BD->param_empty()) OS << ", "; @@ -1241,10 +1290,10 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, } if (Policy.Dump) { - dump(); + dump(Context.getSourceManager()); return; } - + StmtPrinter P(OS, Context, Helper, Policy, Indentation); P.Visit(const_cast<Stmt*>(this)); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp new file mode 100644 index 000000000000..c4d42f6be228 --- /dev/null +++ b/lib/AST/StmtProfile.cpp @@ -0,0 +1,720 @@ +//===---- StmtProfile.cpp - Profile implementation for Stmt ASTs ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::Profile method, which builds a unique bit +// representation that identifies a statement/expression. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Compiler.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor<StmtProfiler> { + llvm::FoldingSetNodeID &ID; + ASTContext &Context; + bool Canonical; + + public: + StmtProfiler(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical) + : ID(ID), Context(Context), Canonical(Canonical) { } + + void VisitStmt(Stmt *S); + +#define STMT(Node, Base) void Visit##Node(Node *S); +#include "clang/AST/StmtNodes.def" + + /// \brief Visit a declaration that is referenced within an expression + /// or statement. + void VisitDecl(Decl *D); + + /// \brief Visit a type that is referenced within an expression or + /// statement. + void VisitType(QualType T); + + /// \brief Visit a name that occurs within an expression or statement. + void VisitName(DeclarationName Name); + + /// \brief Visit a nested-name-specifier that occurs within an expression + /// or statement. + void VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Visit a template name that occurs within an expression or + /// statement. + void VisitTemplateName(TemplateName Name); + + /// \brief Visit template arguments that occur within an expression or + /// statement. + void VisitTemplateArguments(const TemplateArgument *Args, unsigned NumArgs); + }; +} + +void StmtProfiler::VisitStmt(Stmt *S) { + ID.AddInteger(S->getStmtClass()); + for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end(); + C != CEnd; ++C) + Visit(*C); +} + +void StmtProfiler::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) + VisitDecl(*D); +} + +void StmtProfiler::VisitNullStmt(NullStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCaseStmt(CaseStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + VisitName(S->getID()); +} + +void StmtProfiler::VisitIfStmt(IfStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDoStmt(DoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitForStmt(ForStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + VisitName(S->getLabel()->getID()); +} + +void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->isVolatile()); + ID.AddBoolean(S->isSimple()); + VisitStringLiteral(S->getAsmString()); + ID.AddInteger(S->getNumOutputs()); + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + ID.AddString(S->getOutputName(I)); + VisitStringLiteral(S->getOutputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumInputs()); + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + ID.AddString(S->getInputName(I)); + VisitStringLiteral(S->getInputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumClobbers()); + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) + VisitStringLiteral(S->getClobber(I)); +} + +void StmtProfiler::VisitCXXCatchStmt(CXXCatchStmt *S) { + VisitStmt(S); + VisitType(S->getCaughtType()); +} + +void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->hasEllipsis()); + if (S->getCatchParamDecl()) + VisitType(S->getCatchParamDecl()->getType()); +} + +void StmtProfiler::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitExpr(Expr *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); +} + +void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getIdentType()); +} + +void StmtProfiler::VisitIntegerLiteral(IntegerLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); +} + +void StmtProfiler::VisitCharacterLiteral(CharacterLiteral *S) { + VisitExpr(S); + ID.AddBoolean(S->isWide()); + ID.AddInteger(S->getValue()); +} + +void StmtProfiler::VisitFloatingLiteral(FloatingLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); + ID.AddBoolean(S->isExact()); +} + +void StmtProfiler::VisitImaginaryLiteral(ImaginaryLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitStringLiteral(StringLiteral *S) { + VisitExpr(S); + ID.AddString(S->getString()); + ID.AddBoolean(S->isWide()); +} + +void StmtProfiler::VisitParenExpr(ParenExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitParenListExpr(ParenListExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isSizeOf()); + if (S->isArgumentType()) + VisitType(S->getArgumentType()); +} + +void StmtProfiler::VisitArraySubscriptExpr(ArraySubscriptExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCallExpr(CallExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitMemberExpr(MemberExpr *S) { + VisitExpr(S); + VisitDecl(S->getMemberDecl()); + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitCompoundLiteralExpr(CompoundLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isFileScope()); +} + +void StmtProfiler::VisitCastExpr(CastExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) { + VisitCastExpr(S); + ID.AddBoolean(S->isLvalueCast()); +} + +void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) { + VisitCastExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void StmtProfiler::VisitCStyleCastExpr(CStyleCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitBinaryOperator(BinaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitCompoundAssignOperator(CompoundAssignOperator *S) { + VisitBinaryOperator(S); +} + +void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { + VisitExpr(S); + VisitName(S->getLabel()->getID()); +} + +void StmtProfiler::VisitStmtExpr(StmtExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitTypesCompatibleExpr(TypesCompatibleExpr *S) { + VisitExpr(S); + VisitType(S->getArgType1()); + VisitType(S->getArgType2()); +} + +void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitChooseExpr(ChooseExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitGNUNullExpr(GNUNullExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitVAArgExpr(VAArgExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitInitListExpr(InitListExpr *S) { + if (S->getSyntacticForm()) { + VisitInitListExpr(S->getSyntacticForm()); + return; + } + + VisitExpr(S); +} + +void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->usesGNUSyntax()); + for (DesignatedInitExpr::designators_iterator D = S->designators_begin(), + DEnd = S->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + ID.AddInteger(0); + VisitName(D->getFieldName()); + continue; + } + + if (D->isArrayDesignator()) { + ID.AddInteger(1); + } else { + assert(D->isArrayRangeDesignator()); + ID.AddInteger(2); + } + ID.AddInteger(D->getFirstExprIndex()); + } +} + +void StmtProfiler::VisitImplicitValueInitExpr(ImplicitValueInitExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitExtVectorElementExpr(ExtVectorElementExpr *S) { + VisitExpr(S); + VisitName(&S->getAccessor()); +} + +void StmtProfiler::VisitBlockExpr(BlockExpr *S) { + VisitExpr(S); + VisitDecl(S->getBlockDecl()); +} + +void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isByRef()); + ID.AddBoolean(S->isConstQualAdded()); +} + +void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) { + VisitCallExpr(S); + ID.AddInteger(S->getOperator()); +} + +void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) { + VisitCallExpr(S); +} + +void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXStaticCastExpr(CXXStaticCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXConstCastExpr(CXXConstCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->getValue()); +} + +void StmtProfiler::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + +void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXThrowExpr(CXXThrowExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *S) { + VisitExpr(S); + VisitDecl(S->getParam()); +} + +void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { + VisitExpr(S); + VisitDecl( + const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor())); +} + +void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { + VisitExpr(S); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isElidable()); +} + +void StmtProfiler::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *S) { + VisitCXXConstructExpr(S); +} + +void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) { + VisitDeclRefExpr(S); +} + +void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isGlobalDelete()); + ID.AddBoolean(S->isArrayForm()); + VisitDecl(S->getOperatorDelete()); +} + + +void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) { + VisitExpr(S); + VisitType(S->getAllocatedType()); + VisitDecl(S->getOperatorNew()); + VisitDecl(S->getOperatorDelete()); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isArray()); + ID.AddInteger(S->getNumPlacementArgs()); + ID.AddBoolean(S->isGlobalNew()); + ID.AddBoolean(S->isParenTypeId()); + ID.AddBoolean(S->hasInitializer()); + ID.AddInteger(S->getNumConstructorArgs()); +} + +void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitType(S->getDestroyedType()); +} + +void +StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) { + VisitExpr(S); + VisitName(S->getName()); +} + +void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getQueriedType()); +} + +void StmtProfiler::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *S) { + VisitDeclRefExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); +} + +void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) { + VisitExpr(S); + VisitName(S->getDeclName()); + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->isAddressOfOperand()); +} + +void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) { + VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); + VisitTemplateName(S->getTemplateName()); + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) { + VisitExpr(S); + ID.AddBoolean(S->shouldDestroyTemporaries()); + for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I) + VisitDecl( + const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor())); +} + +void +StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { + VisitExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMember()); +} + +void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitObjCEncodeExpr(ObjCEncodeExpr *S) { + VisitExpr(S); + VisitType(S->getEncodedType()); +} + +void StmtProfiler::VisitObjCSelectorExpr(ObjCSelectorExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); +} + +void StmtProfiler::VisitObjCProtocolExpr(ObjCProtocolExpr *S) { + VisitExpr(S); + VisitDecl(S->getProtocol()); +} + +void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isFreeIvar()); +} + +void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getProperty()); +} + +void StmtProfiler::VisitObjCImplicitSetterGetterRefExpr( + ObjCImplicitSetterGetterRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getGetterMethod()); + VisitDecl(S->getSetterMethod()); + VisitDecl(S->getInterfaceDecl()); +} + +void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); + VisitDecl(S->getMethodDecl()); +} + +void StmtProfiler::VisitObjCSuperExpr(ObjCSuperExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitDecl(Decl *D) { + ID.AddInteger(D? D->getKind() : 0); + + if (Canonical && D) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + ID.AddInteger(NTTP->getDepth()); + ID.AddInteger(NTTP->getIndex()); + VisitType(NTTP->getType()); + return; + } + + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + // The Itanium C++ ABI uses the type of a parameter when mangling + // expressions that involve function parameters, so we will use the + // parameter's type for establishing function parameter identity. That + // way, our definition of "equivalent" (per C++ [temp.over.link]) + // matches the definition of "equivalent" used for name mangling. + VisitType(Parm->getType()); + return; + } + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + return; + } + + if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) { + // The Itanium C++ ABI mangles references to a set of overloaded + // functions using just the function name, so we do the same here. + VisitName(Ovl->getDeclName()); + return; + } + } + + ID.AddPointer(D? D->getCanonicalDecl() : 0); +} + +void StmtProfiler::VisitType(QualType T) { + if (Canonical) + T = Context.getCanonicalType(T); + + ID.AddPointer(T.getAsOpaquePtr()); +} + +void StmtProfiler::VisitName(DeclarationName Name) { + ID.AddPointer(Name.getAsOpaquePtr()); +} + +void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) { + if (Canonical) + NNS = Context.getCanonicalNestedNameSpecifier(NNS); + ID.AddPointer(NNS); +} + +void StmtProfiler::VisitTemplateName(TemplateName Name) { + if (Canonical) + Name = Context.getCanonicalTemplateName(Name); + + Name.Profile(ID); +} + +void StmtProfiler::VisitTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + const TemplateArgument &Arg = Args[I]; + + // Mostly repetitive with TemplateArgument::Profile! + ID.AddInteger(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Declaration: + VisitDecl(Arg.getAsDecl()); + break; + + case TemplateArgument::Integral: + Arg.getAsIntegral()->Profile(ID); + VisitType(Arg.getIntegralType()); + break; + + case TemplateArgument::Expression: + Visit(Arg.getAsExpr()); + break; + + case TemplateArgument::Pack: + VisitTemplateArguments(Arg.pack_begin(), Arg.pack_size()); + break; + } + } +} + +void Stmt::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical) { + StmtProfiler Profiler(ID, Context, Canonical); + Profiler.Visit(this); +} diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp index 96b5218ba2f0..61fd750ccc83 100644 --- a/lib/AST/StmtViz.cpp +++ b/lib/AST/StmtViz.cpp @@ -15,7 +15,6 @@ #include "clang/AST/StmtGraphTraits.h" #include "clang/AST/Decl.h" #include "llvm/Support/GraphWriter.h" -#include <sstream> using namespace clang; @@ -23,8 +22,8 @@ void Stmt::viewAST() const { #ifndef NDEBUG llvm::ViewGraph(this,"AST"); #else - llvm::cerr << "Stmt::viewAST is only available in debug builds on " - << "systems with Graphviz or gv!\n"; + llvm::errs() << "Stmt::viewAST is only available in debug builds on " + << "systems with Graphviz or gv!\n"; #endif } @@ -33,26 +32,26 @@ template<> struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits { static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph, bool ShortNames) { - + #ifndef NDEBUG std::string OutSStr; llvm::raw_string_ostream Out(OutSStr); - + if (Node) Out << Node->getStmtClassName(); else Out << "<NULL>"; - - std::string OutStr = Out.str(); + + std::string OutStr = Out.str(); if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); - + // Process string output to make it nicer... for (unsigned i = 0; i != OutStr.length(); ++i) if (OutStr[i] == '\n') { // Left justify OutStr[i] = '\\'; OutStr.insert(OutStr.begin()+i+1, 'l'); } - + return OutStr; #else return ""; diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 5b671c111fbf..24588bc5f11f 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -22,39 +22,55 @@ using namespace clang; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) return Template; - + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) return QTN->getTemplateDecl(); return 0; } +OverloadedFunctionDecl *TemplateName::getAsOverloadedFunctionDecl() const { + if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast<OverloadedFunctionDecl *>()) + return Ovl; + + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) + return QTN->getOverloadedFunctionDecl(); + + return 0; +} + bool TemplateName::isDependent() const { if (TemplateDecl *Template = getAsTemplateDecl()) { - // FIXME: We don't yet have a notion of dependent - // declarations. When we do, check that. This hack won't last - // long!. - return isa<TemplateTemplateParmDecl>(Template); + return isa<TemplateTemplateParmDecl>(Template) || + Template->getDeclContext()->isDependentContext(); } + if (OverloadedFunctionDecl *Ovl = getAsOverloadedFunctionDecl()) + return Ovl->getDeclContext()->isDependentContext(); + return true; } -void +void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) OS << Template->getIdentifier()->getName(); + else if (OverloadedFunctionDecl *Ovl + = Storage.dyn_cast<OverloadedFunctionDecl *>()) + OS << Ovl->getNameAsString(); else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getTemplateDecl()->getIdentifier()->getName(); + OS << QTN->getDecl()->getNameAsString(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { - if (!SuppressNNS) + if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); OS << "template "; + // FIXME: Shouldn't we have a more general kind of name? OS << DTN->getName()->getName(); } } @@ -65,3 +81,13 @@ void TemplateName::dump() const { LO.Bool = true; print(llvm::errs(), PrintingPolicy(LO)); } + +TemplateDecl *QualifiedTemplateName::getTemplateDecl() const { + return dyn_cast<TemplateDecl>(Template); +} + +OverloadedFunctionDecl * +QualifiedTemplateName::getOverloadedFunctionDecl() const { + return dyn_cast<OverloadedFunctionDecl>(Template); +} + diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4e061a9fbe62..0293862baedb 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -22,12 +22,12 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; -bool QualType::isConstant(ASTContext &Ctx) const { - if (isConstQualified()) +bool QualType::isConstant(QualType T, ASTContext &Ctx) { + if (T.isConstQualified()) return true; - if (getTypePtr()->isArrayType()) - return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx); + if (const ArrayType *AT = Ctx.getAsArrayType(T)) + return AT->getElementType().isConstant(Ctx); return false; } @@ -37,6 +37,18 @@ void Type::Destroy(ASTContext& C) { C.Deallocate(this); } +void ConstantArrayWithExprType::Destroy(ASTContext& C) { + // FIXME: destruction of SizeExpr commented out due to resource contention. + // SizeExpr->Destroy(C); + // See FIXME in SemaDecl.cpp:1536: if we were able to either steal + // or clone the SizeExpr there, then here we could freely delete it. + // Since we do not know how to steal or clone, we keep a pointer to + // a shared resource, but we cannot free it. + // (There probably is a trivial solution ... for people knowing clang!). + this->~ConstantArrayWithExprType(); + C.Deallocate(this); +} + void VariableArrayType::Destroy(ASTContext& C) { if (SizeExpr) SizeExpr->Destroy(C); @@ -45,14 +57,37 @@ void VariableArrayType::Destroy(ASTContext& C) { } void DependentSizedArrayType::Destroy(ASTContext& C) { - SizeExpr->Destroy(C); + // FIXME: Resource contention like in ConstantArrayWithExprType ? + // May crash, depending on platform or a particular build. + // SizeExpr->Destroy(C); this->~DependentSizedArrayType(); C.Deallocate(this); } +void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + QualType ET, + ArraySizeModifier SizeMod, + unsigned TypeQuals, + Expr *E) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + E->Profile(ID, Context, true); +} + +void +DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + QualType ElementType, Expr *SizeExpr) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + SizeExpr->Profile(ID, Context, true); +} + void DependentSizedExtVectorType::Destroy(ASTContext& C) { - if (SizeExpr) - SizeExpr->Destroy(C); + // FIXME: Deallocate size expression, once we're cloning properly. +// if (SizeExpr) +// SizeExpr->Destroy(C); this->~DependentSizedExtVectorType(); C.Deallocate(this); } @@ -64,18 +99,15 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { // If this is directly an array type, return it. if (const ArrayType *ATy = dyn_cast<ArrayType>(this)) return ATy->getElementType().getTypePtr(); - + // If the canonical form of this type isn't the right kind, reject it. - if (!isa<ArrayType>(CanonicalType)) { - // Look through type qualifiers - if (ArrayType *AT = dyn_cast<ArrayType>(CanonicalType.getUnqualifiedType())) - return AT->getElementType().getTypePtr(); + if (!isa<ArrayType>(CanonicalType)) return 0; - } - + // If this is a typedef for an array type, strip the typedef off without // losing all typedef information. - return cast<ArrayType>(getDesugaredType())->getElementType().getTypePtr(); + return cast<ArrayType>(getUnqualifiedDesugaredType()) + ->getElementType().getTypePtr(); } /// getDesugaredType - Return the specified type with any "sugar" removed from @@ -84,66 +116,52 @@ const Type *Type::getArrayElementTypeNoTypeQual() const { /// to getting the canonical type, but it doesn't remove *all* typedefs. For /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is /// concrete. -/// -/// \param ForDisplay When true, the desugaring is provided for -/// display purposes only. In this case, we apply more heuristics to -/// decide whether it is worth providing a desugared form of the type -/// or not. -QualType QualType::getDesugaredType(bool ForDisplay) const { - return getTypePtr()->getDesugaredType(ForDisplay) - .getWithAdditionalQualifiers(getCVRQualifiers()); +QualType QualType::getDesugaredType(QualType T) { + QualifierCollector Qs; + + QualType Cur = T; + while (true) { + const Type *CurTy = Qs.strip(Cur); + switch (CurTy->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *Ty = cast<Class##Type>(CurTy); \ + if (!Ty->isSugared()) \ + return Qs.apply(Cur); \ + Cur = Ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } } -/// getDesugaredType - Return the specified type with any "sugar" removed from -/// type type. This takes off typedefs, typeof's etc. If the outer level of -/// the type is already concrete, it returns it unmodified. This is similar -/// to getting the canonical type, but it doesn't remove *all* typedefs. For -/// example, it return "T*" as "T*", (not as "int*"), because the pointer is -/// concrete. -/// -/// \param ForDisplay When true, the desugaring is provided for -/// display purposes only. In this case, we apply more heuristics to -/// decide whether it is worth providing a desugared form of the type -/// or not. -QualType Type::getDesugaredType(bool ForDisplay) const { - if (const TypedefType *TDT = dyn_cast<TypedefType>(this)) - return TDT->LookThroughTypedefs().getDesugaredType(); - if (const TypeOfExprType *TOE = dyn_cast<TypeOfExprType>(this)) - return TOE->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this)) - return TOT->getUnderlyingType().getDesugaredType(); - if (const DecltypeType *DTT = dyn_cast<DecltypeType>(this)) - return DTT->getUnderlyingExpr()->getType().getDesugaredType(); - if (const TemplateSpecializationType *Spec - = dyn_cast<TemplateSpecializationType>(this)) { - if (ForDisplay) - return QualType(this, 0); +/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic +/// sugar off the given type. This should produce an object of the +/// same dynamic type as the canonical type. +const Type *Type::getUnqualifiedDesugaredType() const { + const Type *Cur = this; - QualType Canon = Spec->getCanonicalTypeInternal(); - if (Canon->getAsTemplateSpecializationType()) - return QualType(this, 0); - return Canon->getDesugaredType(); - } - if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) { - if (ForDisplay) { - // If desugaring the type that the qualified name is referring to - // produces something interesting, that's our desugared type. - QualType NamedType = QualName->getNamedType().getDesugaredType(); - if (NamedType != QualName->getNamedType()) - return NamedType; - } else - return QualName->getNamedType().getDesugaredType(); + while (true) { + switch (Cur->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Class: { \ + const Class##Type *Ty = cast<Class##Type>(Cur); \ + if (!Ty->isSugared()) return Cur; \ + Cur = Ty->desugar().getTypePtr(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } } - - return QualType(this, 0); } /// isVoidType - Helper method to determine if this is the 'void' type. bool Type::isVoidType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Void; - if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) - return AS->getBaseType()->isVoidType(); return false; } @@ -151,18 +169,16 @@ bool Type::isObjectType() const { if (isa<FunctionType>(CanonicalType) || isa<ReferenceType>(CanonicalType) || isa<IncompleteArrayType>(CanonicalType) || isVoidType()) return false; - if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) - return AS->getBaseType()->isObjectType(); return true; } bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { - case ExtQual: - return cast<ExtQualType>(CanonicalType)->getBaseType()->isDerivedType(); case Pointer: case VariableArray: case ConstantArray: + case ConstantArrayWithExpr: + case ConstantArrayWithoutExpr: case IncompleteArray: case FunctionProto: case FunctionNoProto: @@ -176,23 +192,23 @@ bool Type::isDerivedType() const { } bool Type::isClassType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isClass(); return false; } bool Type::isStructureType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isStruct(); return false; } bool Type::isVoidPointerType() const { - if (const PointerType *PT = getAsPointerType()) + if (const PointerType *PT = getAs<PointerType>()) return PT->getPointeeType()->isVoidType(); return false; } bool Type::isUnionType() const { - if (const RecordType *RT = getAsRecordType()) + if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isUnion(); return false; } @@ -200,192 +216,29 @@ bool Type::isUnionType() const { bool Type::isComplexType() const { if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) return CT->getElementType()->isFloatingType(); - if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) - return AS->getBaseType()->isComplexType(); return false; } bool Type::isComplexIntegerType() const { // Check for GCC complex integer extension. - if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) - return CT->getElementType()->isIntegerType(); - if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) - return AS->getBaseType()->isComplexIntegerType(); - return false; + return getAsComplexIntegerType(); } const ComplexType *Type::getAsComplexIntegerType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) { - if (CTy->getElementType()->isIntegerType()) - return CTy; - return 0; - } - - // If the canonical form of this type isn't what we want, reject it. - if (!isa<ComplexType>(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa<ComplexType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return cast<ComplexType>(getDesugaredType()); -} - -const BuiltinType *Type::getAsBuiltinType() const { - // If this is directly a builtin type, return it. - if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this)) - return BTy; - - // If the canonical form of this type isn't a builtin type, reject it. - if (!isa<BuiltinType>(CanonicalType)) { - // Look through type qualifiers (e.g. ExtQualType's). - if (isa<BuiltinType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); - return 0; - } - - // If this is a typedef for a builtin type, strip the typedef off without - // losing all typedef information. - return cast<BuiltinType>(getDesugaredType()); -} - -const FunctionType *Type::getAsFunctionType() const { - // If this is directly a function type, return it. - if (const FunctionType *FTy = dyn_cast<FunctionType>(this)) - return FTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<FunctionType>(CanonicalType)) { - // Look through type qualifiers - if (isa<FunctionType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsFunctionType(); - return 0; - } - - // If this is a typedef for a function type, strip the typedef off without - // losing all typedef information. - return cast<FunctionType>(getDesugaredType()); -} - -const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const { - return dyn_cast_or_null<FunctionNoProtoType>(getAsFunctionType()); -} - -const FunctionProtoType *Type::getAsFunctionProtoType() const { - return dyn_cast_or_null<FunctionProtoType>(getAsFunctionType()); -} - - -const PointerType *Type::getAsPointerType() const { - // If this is directly a pointer type, return it. - if (const PointerType *PTy = dyn_cast<PointerType>(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<PointerType>(CanonicalType)) { - // Look through type qualifiers - if (isa<PointerType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsPointerType(); - return 0; - } - - // If this is a typedef for a pointer type, strip the typedef off without - // losing all typedef information. - return cast<PointerType>(getDesugaredType()); -} - -const BlockPointerType *Type::getAsBlockPointerType() const { - // If this is directly a block pointer type, return it. - if (const BlockPointerType *PTy = dyn_cast<BlockPointerType>(this)) - return PTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<BlockPointerType>(CanonicalType)) { - // Look through type qualifiers - if (isa<BlockPointerType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsBlockPointerType(); - return 0; - } - - // If this is a typedef for a block pointer type, strip the typedef off - // without losing all typedef information. - return cast<BlockPointerType>(getDesugaredType()); -} - -const ReferenceType *Type::getAsReferenceType() const { - // If this is directly a reference type, return it. - if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<ReferenceType>(CanonicalType)) { - // Look through type qualifiers - if (isa<ReferenceType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsReferenceType(); - return 0; - } - - // If this is a typedef for a reference type, strip the typedef off without - // losing all typedef information. - return cast<ReferenceType>(getDesugaredType()); -} - -const LValueReferenceType *Type::getAsLValueReferenceType() const { - // If this is directly an lvalue reference type, return it. - if (const LValueReferenceType *RTy = dyn_cast<LValueReferenceType>(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<LValueReferenceType>(CanonicalType)) { - // Look through type qualifiers - if (isa<LValueReferenceType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType(); - return 0; - } - - // If this is a typedef for an lvalue reference type, strip the typedef off - // without losing all typedef information. - return cast<LValueReferenceType>(getDesugaredType()); -} - -const RValueReferenceType *Type::getAsRValueReferenceType() const { - // If this is directly an rvalue reference type, return it. - if (const RValueReferenceType *RTy = dyn_cast<RValueReferenceType>(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<RValueReferenceType>(CanonicalType)) { - // Look through type qualifiers - if (isa<RValueReferenceType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType(); - return 0; - } - - // If this is a typedef for an rvalue reference type, strip the typedef off - // without losing all typedef information. - return cast<RValueReferenceType>(getDesugaredType()); + if (const ComplexType *Complex = getAs<ComplexType>()) + if (Complex->getElementType()->isIntegerType()) + return Complex; + return 0; } -const MemberPointerType *Type::getAsMemberPointerType() const { - // If this is directly a member pointer type, return it. - if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this)) - return MTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<MemberPointerType>(CanonicalType)) { - // Look through type qualifiers - if (isa<MemberPointerType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsMemberPointerType(); - return 0; - } - - // If this is a typedef for a member pointer type, strip the typedef off - // without losing all typedef information. - return cast<MemberPointerType>(getDesugaredType()); +QualType Type::getPointeeType() const { + if (const PointerType *PT = getAs<PointerType>()) + return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->getPointeeType(); + if (const BlockPointerType *BPT = getAs<BlockPointerType>()) + return BPT->getPointeeType(); + return QualType(); } /// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length @@ -404,59 +257,23 @@ bool Type::isVariablyModifiedType() const { // Also, C++ references and member pointers can point to a variably modified // type, where VLAs appear as an extension to C++, and should be treated // correctly. - if (const PointerType *PT = getAsPointerType()) + if (const PointerType *PT = getAs<PointerType>()) return PT->getPointeeType()->isVariablyModifiedType(); - if (const ReferenceType *RT = getAsReferenceType()) + if (const ReferenceType *RT = getAs<ReferenceType>()) return RT->getPointeeType()->isVariablyModifiedType(); - if (const MemberPointerType *PT = getAsMemberPointerType()) + if (const MemberPointerType *PT = getAs<MemberPointerType>()) return PT->getPointeeType()->isVariablyModifiedType(); // A function can return a variably modified type // This one isn't completely obvious, but it follows from the // definition in C99 6.7.5p3. Because of this rule, it's // illegal to declare a function returning a variably modified type. - if (const FunctionType *FT = getAsFunctionType()) + if (const FunctionType *FT = getAs<FunctionType>()) return FT->getResultType()->isVariablyModifiedType(); return false; } -const RecordType *Type::getAsRecordType() const { - // If this is directly a record type, return it. - if (const RecordType *RTy = dyn_cast<RecordType>(this)) - return RTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<RecordType>(CanonicalType)) { - // Look through type qualifiers - if (isa<RecordType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsRecordType(); - return 0; - } - - // If this is a typedef for a record type, strip the typedef off without - // losing all typedef information. - return cast<RecordType>(getDesugaredType()); -} - -const TagType *Type::getAsTagType() const { - // If this is directly a tag type, return it. - if (const TagType *TagTy = dyn_cast<TagType>(this)) - return TagTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<TagType>(CanonicalType)) { - // Look through type qualifiers - if (isa<TagType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsTagType(); - return 0; - } - - // If this is a typedef for a tag type, strip the typedef off without - // losing all typedef information. - return cast<TagType>(getDesugaredType()); -} - const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast<RecordType>(this)) { @@ -468,24 +285,21 @@ const RecordType *Type::getAsStructureType() const { if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { if (!RT->getDecl()->isStruct()) return 0; - + // If this is a typedef for a structure type, strip the typedef off without // losing all typedef information. - return cast<RecordType>(getDesugaredType()); + return cast<RecordType>(getUnqualifiedDesugaredType()); } - // Look through type qualifiers - if (isa<RecordType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsStructureType(); return 0; } -const RecordType *Type::getAsUnionType() const { +const RecordType *Type::getAsUnionType() const { // If this is directly a union type, return it. if (const RecordType *RT = dyn_cast<RecordType>(this)) { if (RT->getDecl()->isUnion()) return RT; } - + // If the canonical form of this type isn't the right kind, reject it. if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { if (!RT->getDecl()->isUnion()) @@ -493,118 +307,49 @@ const RecordType *Type::getAsUnionType() const { // If this is a typedef for a union type, strip the typedef off without // losing all typedef information. - return cast<RecordType>(getDesugaredType()); - } - - // Look through type qualifiers - if (isa<RecordType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsUnionType(); - return 0; -} - -const EnumType *Type::getAsEnumType() const { - // Check the canonicalized unqualified type directly; the more complex - // version is unnecessary because there isn't any typedef information - // to preserve. - return dyn_cast<EnumType>(CanonicalType.getUnqualifiedType()); -} - -const ComplexType *Type::getAsComplexType() const { - // Are we directly a complex type? - if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) - return CTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<ComplexType>(CanonicalType)) { - // Look through type qualifiers - if (isa<ComplexType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsComplexType(); - return 0; - } - - // If this is a typedef for a complex type, strip the typedef off without - // losing all typedef information. - return cast<ComplexType>(getDesugaredType()); -} - -const VectorType *Type::getAsVectorType() const { - // Are we directly a vector type? - if (const VectorType *VTy = dyn_cast<VectorType>(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<VectorType>(CanonicalType)) { - // Look through type qualifiers - if (isa<VectorType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsVectorType(); - return 0; + return cast<RecordType>(getUnqualifiedDesugaredType()); } - // If this is a typedef for a vector type, strip the typedef off without - // losing all typedef information. - return cast<VectorType>(getDesugaredType()); -} - -const ExtVectorType *Type::getAsExtVectorType() const { - // Are we directly an OpenCU vector type? - if (const ExtVectorType *VTy = dyn_cast<ExtVectorType>(this)) - return VTy; - - // If the canonical form of this type isn't the right kind, reject it. - if (!isa<ExtVectorType>(CanonicalType)) { - // Look through type qualifiers - if (isa<ExtVectorType>(CanonicalType.getUnqualifiedType())) - return CanonicalType.getUnqualifiedType()->getAsExtVectorType(); - return 0; - } - - // If this is a typedef for an extended vector type, strip the typedef off - // without losing all typedef information. - return cast<ExtVectorType>(getDesugaredType()); + return 0; } -const ObjCInterfaceType *Type::getAsObjCInterfaceType() const { +const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCInterfaceType's, just return the canonical // type pointer if it is the right class. There is no typedef information to // return and these cannot be Address-space qualified. - return dyn_cast<ObjCInterfaceType>(CanonicalType.getUnqualifiedType()); -} - -const ObjCObjectPointerType *Type::getAsObjCObjectPointerType() const { - // There is no sugar for ObjCObjectPointerType's, just return the - // canonical type pointer if it is the right class. - return dyn_cast<ObjCObjectPointerType>(CanonicalType.getUnqualifiedType()); + if (const ObjCInterfaceType *OIT = getAs<ObjCInterfaceType>()) + if (OIT->getNumProtocols()) + return OIT; + return 0; } -const ObjCQualifiedInterfaceType * -Type::getAsObjCQualifiedInterfaceType() const { - // There is no sugar for ObjCQualifiedInterfaceType's, just return the - // canonical type pointer if it is the right class. - return dyn_cast<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType()); +bool Type::isObjCQualifiedInterfaceType() const { + return getAsObjCQualifiedInterfaceType() != 0; } const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. - if (const ObjCObjectPointerType *OPT = getAsObjCObjectPointerType()) { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->isObjCQualifiedIdType()) return OPT; } return 0; } -const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { - // There is no sugar for template type parameters, so just return - // the canonical type pointer if it is the right class. - // FIXME: can these be address-space qualified? - return dyn_cast<TemplateTypeParmType>(CanonicalType); +const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (OPT->getInterfaceType()) + return OPT; + } + return 0; } -const TemplateSpecializationType * -Type::getAsTemplateSpecializationType() const { - // There is no sugar for class template specialization types, so - // just return the canonical type pointer if it is the right class. - return dyn_cast<TemplateSpecializationType>(CanonicalType); +const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { + if (const PointerType *PT = getAs<PointerType>()) + if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + return 0; } bool Type::isIntegerType() const { @@ -620,8 +365,6 @@ bool Type::isIntegerType() const { return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isIntegerType(); return false; } @@ -635,24 +378,18 @@ bool Type::isIntegralType() const { // FIXME: In C++, enum types are never integral. if (isa<FixedWidthIntType>(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isIntegralType(); return false; } bool Type::isEnumeralType() const { if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) return TT->getDecl()->isEnum(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isEnumeralType(); return false; } bool Type::isBooleanType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::Bool; - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isBooleanType(); return false; } @@ -662,16 +399,12 @@ bool Type::isCharType() const { BT->getKind() == BuiltinType::UChar || BT->getKind() == BuiltinType::Char_S || BT->getKind() == BuiltinType::SChar; - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isCharType(); return false; } bool Type::isWideCharType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() == BuiltinType::WChar; - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isWideCharType(); return false; } @@ -684,18 +417,16 @@ bool Type::isSignedIntegerType() const { return BT->getKind() >= BuiltinType::Char_S && BT->getKind() <= BuiltinType::LongLong; } - + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); - + if (const FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(CanonicalType)) return FWIT->isSigned(); - + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isSignedIntegerType(); return false; } @@ -718,8 +449,6 @@ bool Type::isUnsignedIntegerType() const { if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isUnsignedIntegerType(); return false; } @@ -731,8 +460,6 @@ bool Type::isFloatingType() const { return CT->getElementType()->isFloatingType(); if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isFloatingType(); return false; } @@ -742,8 +469,6 @@ bool Type::isRealFloatingType() const { BT->getKind() <= BuiltinType::LongDouble; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isRealFloatingType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isRealFloatingType(); return false; } @@ -757,8 +482,6 @@ bool Type::isRealType() const { return true; if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) return VT->getElementType()->isRealType(); - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isRealType(); return false; } @@ -772,8 +495,6 @@ bool Type::isArithmeticType() const { return ET->getDecl()->isDefinition(); if (isa<FixedWidthIntType>(CanonicalType)) return true; - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isArithmeticType(); return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType); } @@ -787,8 +508,6 @@ bool Type::isScalarType() const { return true; return false; } - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isScalarType(); if (isa<FixedWidthIntType>(CanonicalType)) return true; return isa<PointerType>(CanonicalType) || @@ -815,8 +534,6 @@ bool Type::isAggregateType() const { return true; } - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isAggregateType(); return isa<ArrayType>(CanonicalType); } @@ -824,8 +541,6 @@ bool Type::isAggregateType() const { /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types or dependent types. bool Type::isConstantSizeType() const { - if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) - return EXTQT->getBaseType()->isConstantSizeType(); assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); assert(!isDependentType() && "This doesn't make sense for dependent types"); // The VAT must have a size, as it is known to be complete. @@ -835,11 +550,9 @@ bool Type::isConstantSizeType() const { /// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) /// - a type that can describe objects, but which lacks information needed to /// determine its size. -bool Type::isIncompleteType() const { - switch (CanonicalType->getTypeClass()) { +bool Type::isIncompleteType() const { + switch (CanonicalType->getTypeClass()) { default: return false; - case ExtQual: - return cast<ExtQualType>(CanonicalType)->getBaseType()->isIncompleteType(); case Builtin: // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never // be completed. @@ -853,7 +566,6 @@ bool Type::isIncompleteType() const { // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; case ObjCInterface: - case ObjCQualifiedInterface: // ObjC interfaces are incomplete if they are @class, not @interface. return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl(); } @@ -869,8 +581,6 @@ bool Type::isPODType() const { switch (CanonicalType->getTypeClass()) { // Everything not explicitly mentioned is not POD. default: return false; - case ExtQual: - return cast<ExtQualType>(CanonicalType)->getBaseType()->isPODType(); case VariableArray: case ConstantArray: // IncompleteArray is caught by isIncompleteType() above. @@ -889,7 +599,7 @@ bool Type::isPODType() const { return true; case Record: - if (CXXRecordDecl *ClassDecl + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) return ClassDecl->isPOD(); @@ -899,7 +609,7 @@ bool Type::isPODType() const { } bool Type::isPromotableIntegerType() const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs<BuiltinType>()) switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::Char_S: @@ -909,14 +619,14 @@ bool Type::isPromotableIntegerType() const { case BuiltinType::Short: case BuiltinType::UShort: return true; - default: + default: return false; } return false; } bool Type::isNullPtrType() const { - if (const BuiltinType *BT = getAsBuiltinType()) + if (const BuiltinType *BT = getAs<BuiltinType>()) return BT->getKind() == BuiltinType::NullPtr; return false; } @@ -936,7 +646,6 @@ bool Type::isSpecifierType() const { case QualifiedName: case Typename: case ObjCInterface: - case ObjCQualifiedInterface: case ObjCObjectPointer: return true; default: @@ -944,6 +653,15 @@ bool Type::isSpecifierType() const { } } +const char *Type::getTypeClassName() const { + switch (TC) { + default: assert(0 && "Type class not in TypeNodes.def!"); +#define ABSTRACT_TYPE(Derived, Base) +#define TYPE(Derived, Base) case Derived: return #Derived; +#include "clang/AST/TypeNodes.def" + } +} + const char *BuiltinType::getName(const LangOptions &LO) const { switch (getKind()) { default: assert(0 && "Unknown builtin type!"); @@ -967,10 +685,14 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case Double: return "double"; case LongDouble: return "long double"; case WChar: return "wchar_t"; + case Char16: return "char16_t"; + case Char32: return "char32_t"; case NullPtr: return "nullptr_t"; case Overload: return "<overloaded function type>"; case Dependent: return "<dependent type>"; - case UndeducedAuto: return "<undeduced auto type>"; + case UndeducedAuto: return "auto"; + case ObjCId: return "id"; + case ObjCClass: return "Class"; } } @@ -979,7 +701,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool anyExceptionSpec, unsigned NumExceptions, - exception_iterator Exs) { + exception_iterator Exs, bool NoReturn) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); @@ -988,41 +710,43 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, ID.AddInteger(hasExceptionSpec); if (hasExceptionSpec) { ID.AddInteger(anyExceptionSpec); - for(unsigned i = 0; i != NumExceptions; ++i) + for (unsigned i = 0; i != NumExceptions; ++i) ID.AddPointer(Exs[i].getAsOpaquePtr()); } + ID.AddInteger(NoReturn); } void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), - getNumExceptions(), exception_begin()); + getNumExceptions(), exception_begin(), getNoReturnAttr()); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, + QualType OIT, ObjCProtocolDecl **protocols, unsigned NumProtocols) { - ID.AddPointer(Decl); + ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) ID.AddPointer(protocols[i]); } void ObjCObjectPointerType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); + if (getNumProtocols()) + Profile(ID, getPointeeType(), &Protocols[0], getNumProtocols()); + else + Profile(ID, getPointeeType(), 0, 0); } -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, - const ObjCInterfaceDecl *Decl, - ObjCProtocolDecl **protocols, - unsigned NumProtocols) { - ID.AddPointer(Decl); +void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID, + QualType OIT, ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(OIT.getAsOpaquePtr()); for (unsigned i = 0; i != NumProtocols; i++) ID.AddPointer(protocols[i]); } -void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); +void ObjCProtocolListType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), &Protocols[0], getNumProtocols()); } /// LookThroughTypedefs - Return the ultimate type this typedef corresponds to @@ -1037,38 +761,51 @@ QualType TypedefType::LookThroughTypedefs() const { QualType FirstType = getDecl()->getUnderlyingType(); if (!isa<TypedefType>(FirstType)) return FirstType; - + // Otherwise, do the fully general loop. - unsigned TypeQuals = 0; + QualifierCollector Qs; + + QualType CurType; const TypedefType *TDT = this; - while (1) { - QualType CurType = TDT->getDecl()->getUnderlyingType(); - - - /// FIXME: - /// FIXME: This is incorrect for ExtQuals! - /// FIXME: - TypeQuals |= CurType.getCVRQualifiers(); + do { + CurType = TDT->getDecl()->getUnderlyingType(); + TDT = dyn_cast<TypedefType>(Qs.strip(CurType)); + } while (TDT); - TDT = dyn_cast<TypedefType>(CurType); - if (TDT == 0) - return QualType(CurType.getTypePtr(), TypeQuals); - } + return Qs.apply(CurType); +} + +QualType TypedefType::desugar() const { + return getDecl()->getUnderlyingType(); } TypeOfExprType::TypeOfExprType(Expr *E, QualType can) : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) { - assert(!isa<TypedefType>(can) && "Invalid canonical type"); } -DecltypeType::DecltypeType(Expr *E, QualType can) - : Type(Decltype, can, E->isTypeDependent()), E(E) { - assert(can->isDependentType() == E->isTypeDependent() && - "type dependency mismatch!"); - assert(!isa<TypedefType>(can) && "Invalid canonical type"); +QualType TypeOfExprType::desugar() const { + return getUnderlyingExpr()->getType(); +} + +void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); +} + +DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) + : Type(Decltype, can, E->isTypeDependent()), E(E), + UnderlyingType(underlyingType) { +} + +DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E) + : DecltypeType(E, Context.DependentTy), Context(Context) { } + +void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); } -TagType::TagType(TypeClass TC, TagDecl *D, QualType can) +TagType::TagType(TypeClass TC, TagDecl *D, QualType can) : Type(TC, can, D->isDependentType()), decl(D, 0) {} bool RecordType::classof(const TagType *TT) { @@ -1079,7 +816,7 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } -bool +bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { @@ -1087,12 +824,12 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { case TemplateArgument::Null: assert(false && "Should not have a NULL template argument"); break; - + case TemplateArgument::Type: if (Args[Idx].getAsType()->isDependentType()) return true; break; - + case TemplateArgument::Declaration: case TemplateArgument::Integral: // Never dependent @@ -1103,7 +840,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { Args[Idx].getAsExpr()->isValueDependent()) return true; break; - + case TemplateArgument::Pack: assert(0 && "FIXME: Implement!"); break; @@ -1114,18 +851,19 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { } TemplateSpecializationType:: -TemplateSpecializationType(TemplateName T, const TemplateArgument *Args, +TemplateSpecializationType(ASTContext &Context, TemplateName T, + const TemplateArgument *Args, unsigned NumArgs, QualType Canon) - : Type(TemplateSpecialization, + : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Template(T), NumArgs(NumArgs) -{ - assert((!Canon.isNull() || + Context(Context), + Template(T), NumArgs(NumArgs) { + assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && "No canonical type for non-dependent class template specialization"); - TemplateArgument *TemplateArgs + TemplateArgument *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); @@ -1151,16 +889,34 @@ TemplateSpecializationType::getArg(unsigned Idx) const { return getArgs()[Idx]; } -void -TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, - TemplateName T, - const TemplateArgument *Args, - unsigned NumArgs) { +void +TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + ASTContext &Context) { T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) - Args[Idx].Profile(ID); + Args[Idx].Profile(ID, Context); +} + +QualType QualifierCollector::apply(QualType QT) const { + if (!hasNonFastQualifiers()) + return QT.withFastQualifiers(getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(QT, *this); +} + +QualType QualifierCollector::apply(const Type *T) const { + if (!hasNonFastQualifiers()) + return QualType(T, getFastQualifiers()); + + assert(Context && "extended qualifiers but no context!"); + return Context->getQualifiedType(T, *this); } + //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// @@ -1188,14 +944,46 @@ void Type::dump() const { static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { - // Note: funkiness to ensure we get a space only between quals. - bool NonePrinted = true; - if (TypeQuals & QualType::Const) - S += "const", NonePrinted = false; - if (TypeQuals & QualType::Volatile) - S += (NonePrinted+" volatile"), NonePrinted = false; - if (TypeQuals & QualType::Restrict) - S += (NonePrinted+" restrict"), NonePrinted = false; + if (TypeQuals & Qualifiers::Const) { + if (!S.empty()) S += ' '; + S += "const"; + } + if (TypeQuals & Qualifiers::Volatile) { + if (!S.empty()) S += ' '; + S += "volatile"; + } + if (TypeQuals & Qualifiers::Restrict) { + if (!S.empty()) S += ' '; + S += "restrict"; + } +} + +std::string Qualifiers::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::getAsStringInternal(std::string &S, + const PrintingPolicy&) const { + AppendTypeQualList(S, getCVRQualifiers()); + if (unsigned AddressSpace = getAddressSpace()) { + if (!S.empty()) S += ' '; + S += "__attribute__((address_space("; + S += llvm::utostr_32(AddressSpace); + S += ")))"; + } + if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { + if (!S.empty()) S += ' '; + S += "__attribute__((objc_gc("; + if (GCAttrType == Qualifiers::Weak) + S += "weak"; + else + S += "strong"; + S += ")))"; + } } std::string QualType::getAsString() const { @@ -1205,8 +993,8 @@ std::string QualType::getAsString() const { return S; } -void -QualType::getAsStringInternal(std::string &S, +void +QualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { if (isNull()) { S += "NULL TYPE"; @@ -1217,19 +1005,22 @@ QualType::getAsStringInternal(std::string &S, return; // Print qualifiers as appropriate. - if (unsigned Tq = getCVRQualifiers()) { + Qualifiers Quals = getQualifiers(); + if (!Quals.empty()) { std::string TQS; - AppendTypeQualList(TQS, Tq); - if (!S.empty()) - S = TQS + ' ' + S; - else - S = TQS; + Quals.getAsStringInternal(TQS, Policy); + + if (!S.empty()) { + TQS += ' '; + TQS += S; + } + std::swap(S, TQS); } getTypePtr()->getAsStringInternal(S, Policy); } -void BuiltinType::getAsStringInternal(std::string &S, +void BuiltinType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { if (S.empty()) { S = getName(Policy.LangOpts); @@ -1260,33 +1051,14 @@ void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Poli S = "_Complex " + S; } -void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { - bool NeedsSpace = false; - if (AddressSpace) { - S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; - NeedsSpace = true; - } - if (GCAttrType != QualType::GCNone) { - if (NeedsSpace) - S += ' '; - S += "__attribute__((objc_gc("; - if (GCAttrType == QualType::Weak) - S += "weak"; - else - S += "strong"; - S += ")))"; - } - BaseType->getAsStringInternal(S, Policy); -} - void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S = '*' + S; - + // Handle things like 'int (*A)[4];' correctly. // FIXME: this should include vectors, but vectors use attributes I guess. if (isa<ArrayType>(getPointeeType())) S = '(' + S + ')'; - + getPointeeType().getAsStringInternal(S, Policy); } @@ -1335,10 +1107,33 @@ void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy S += '['; S += llvm::utostr(getSize().getZExtValue()); S += ']'; - + getElementType().getAsStringInternal(S, Policy); } +void ConstantArrayWithExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + if (Policy.ConstantArraySizeAsWritten) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + getSizeExpr()->printPretty(s, 0, Policy); + S += '['; + S += s.str(); + S += ']'; + getElementType().getAsStringInternal(S, Policy); + } + else + ConstantArrayType::getAsStringInternal(S, Policy); +} + +void ConstantArrayWithoutExprType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + if (Policy.ConstantArraySizeAsWritten) { + S += "[]"; + getElementType().getAsStringInternal(S, Policy); + } + else + ConstantArrayType::getAsStringInternal(S, Policy); +} + void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += "[]"; @@ -1347,17 +1142,17 @@ void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPoli void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } - + if (getSizeModifier() == Static) S += "static"; else if (getSizeModifier() == Star) S += '*'; - + if (getSizeExpr()) { std::string SStr; llvm::raw_string_ostream s(SStr); @@ -1365,23 +1160,23 @@ void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy S += s.str(); } S += ']'; - + getElementType().getAsStringInternal(S, Policy); } void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { S += '['; - - if (getIndexTypeQualifier()) { - AppendTypeQualList(S, getIndexTypeQualifier()); + + if (getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, getIndexTypeCVRQualifiers()); S += ' '; } - + if (getSizeModifier() == Static) S += "static"; else if (getSizeModifier() == Star) S += '*'; - + if (getSizeExpr()) { std::string SStr; llvm::raw_string_ostream s(SStr); @@ -1389,7 +1184,7 @@ void DependentSizedArrayType::getAsStringInternal(std::string &S, const Printing S += s.str(); } S += ']'; - + getElementType().getAsStringInternal(S, Policy); } @@ -1439,7 +1234,7 @@ void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPol InnerString = "typeof(" + Tmp + ")" + InnerString; } -void DecltypeType::getAsStringInternal(std::string &InnerString, +void DecltypeType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. InnerString = ' ' + InnerString; @@ -1453,8 +1248,10 @@ void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPoli // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) S = "(" + S + ")"; - + S += "()"; + if (getNoReturnAttr()) + S += " __attribute__((noreturn))"; getResultType().getAsStringInternal(S, Policy); } @@ -1462,7 +1259,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy // If needed for precedence reasons, wrap the inner part in grouping parens. if (!S.empty()) S = "(" + S + ")"; - + S += "("; std::string Tmp; PrintingPolicy ParamPolicy(Policy); @@ -1473,7 +1270,7 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy S += Tmp; Tmp.clear(); } - + if (isVariadic()) { if (getNumArgs()) S += ", "; @@ -1482,8 +1279,10 @@ void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy // Do not emit int() if we have a proto, emit 'int(void)'. S += "void"; } - + S += ")"; + if (getNoReturnAttr()) + S += " __attribute__((noreturn))"; getResultType().getAsStringInternal(S, Policy); } @@ -1499,13 +1298,13 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P InnerString = ' ' + InnerString; if (!Name) - InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + + InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + llvm::utostr_32(Index) + InnerString; else InnerString = Name->getName() + InnerString; } -std::string +std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, unsigned NumArgs, @@ -1515,7 +1314,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { if (Arg) SpecString += ", "; - + // Print the argument into a string. std::string ArgString; switch (Args[Arg].getKind()) { @@ -1565,7 +1364,7 @@ TemplateSpecializationType::PrintTemplateArgumentList( return SpecString; } -void +void TemplateSpecializationType:: getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { std::string SpecString; @@ -1589,10 +1388,11 @@ void QualifiedNameType::getAsStringInternal(std::string &InnerString, const Prin llvm::raw_string_ostream OS(MyString); NNS->print(OS, Policy); } - + std::string TypeStr; PrintingPolicy InnerPolicy(Policy); InnerPolicy.SuppressTagKind = true; + InnerPolicy.SuppressScope = true; NamedType.getAsStringInternal(TypeStr, InnerPolicy); MyString += TypeStr; @@ -1615,35 +1415,65 @@ void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingP else if (const TemplateSpecializationType *Spec = getTemplateId()) { Spec->getTemplateName().print(OS, Policy, true); OS << TemplateSpecializationType::PrintTemplateArgumentList( - Spec->getArgs(), + Spec->getArgs(), Spec->getNumArgs(), Policy); } } - + if (InnerString.empty()) InnerString.swap(MyString); else InnerString = MyString + ' ' + InnerString; } -void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { - if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. - InnerString = ' ' + InnerString; - InnerString = getDecl()->getIdentifier()->getName() + InnerString; +void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(Decl); + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); } -void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, - const PrintingPolicy &Policy) const { +void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + if (getNumProtocols()) + Profile(ID, getDecl(), &Protocols[0], getNumProtocols()); + else + Profile(ID, getDecl(), 0, 0); +} + +void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; + std::string ObjCQIString = getDecl()->getNameAsString(); + if (getNumProtocols()) { + ObjCQIString += '<'; + bool isFirst = true; + for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { + if (isFirst) + isFirst = false; + else + ObjCQIString += ','; + ObjCQIString += (*I)->getNameAsString(); + } + ObjCQIString += '>'; + } + InnerString = ObjCQIString + InnerString; +} + +void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { std::string ObjCQIString; - - if (getDecl()) - ObjCQIString = getDecl()->getNameAsString(); - else + + if (isObjCIdType() || isObjCQualifiedIdType()) ObjCQIString = "id"; + else if (isObjCClassType() || isObjCQualifiedClassType()) + ObjCQIString = "Class"; + else + ObjCQIString = getInterfaceDecl()->getNameAsString(); if (!qual_empty()) { ObjCQIString += '<'; @@ -1654,15 +1484,23 @@ void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString, } ObjCQIString += '>'; } + + PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy); + + if (!isObjCIdType() && !isObjCQualifiedIdType()) + ObjCQIString += " *"; // Don't forget the implicit pointer. + else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = ObjCQIString + InnerString; } -void -ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString, +void ObjCProtocolListType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - std::string ObjCQIString = getDecl()->getNameAsString(); + + std::string ObjCQIString = getBaseType().getAsString(Policy); ObjCQIString += '<'; bool isFirst = true; for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { @@ -1676,13 +1514,23 @@ ObjCQualifiedInterfaceType::getAsStringInternal(std::string &InnerString, InnerString = ObjCQIString + InnerString; } +void ElaboratedType::getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const { + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + UnderlyingType.getAsStringInternal(InnerString, InnerPolicy); + + InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString; +} + void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { if (Policy.SuppressTag) return; if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - + const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); const char *ID; if (const IdentifierInfo *II = getDecl()->getIdentifier()) @@ -1696,10 +1544,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy // If this is a class template specialization, print the template // arguments. - if (ClassTemplateSpecializationDecl *Spec + if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - std::string TemplateArgsStr + std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), @@ -1707,17 +1555,17 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy InnerString = TemplateArgsStr + InnerString; } - if (Kind) { + if (!Policy.SuppressScope) { // Compute the full nested-name-specifier for this type. In C, // this will always be empty. std::string ContextStr; - for (DeclContext *DC = getDecl()->getDeclContext(); + for (DeclContext *DC = getDecl()->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { std::string MyPart; if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { if (NS->getIdentifier()) MyPart = NS->getNameAsString(); - } else if (ClassTemplateSpecializationDecl *Spec + } else if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr @@ -1737,7 +1585,10 @@ void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy ContextStr = MyPart + "::" + ContextStr; } - InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString; + if (Kind) + InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString; + else + InnerString = ContextStr + ID + InnerString; } else InnerString = ID + InnerString; } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp new file mode 100644 index 000000000000..c24477ae81c5 --- /dev/null +++ b/lib/AST/TypeLoc.cpp @@ -0,0 +1,370 @@ +//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLoc subclasses implementations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TypeLocVisitor.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// TypeLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +/// \brief Return the source range for the visited TypeSpecLoc. +class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { +public: +#define ABSTRACT_TYPELOC(CLASS) +#define TYPELOC(CLASS, PARENT, TYPE) \ + SourceRange Visit##CLASS(CLASS TyLoc) { return TyLoc.getSourceRange(); } +#include "clang/AST/TypeLocNodes.def" + + SourceRange VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A typeloc wrapper was not handled!"); + return SourceRange(); + } +}; + +} + +SourceRange TypeLoc::getSourceRange() const { + if (isNull()) + return SourceRange(); + return TypeLocRanger().Visit(*this); +} + +/// \brief Returns the size of type source info data block for the given type. +unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { + return TypeLoc(Ty, 0).getFullDataSize(); +} + +/// \brief Find the TypeSpecLoc that is part of this TypeLoc. +TypeSpecLoc TypeLoc::getTypeSpecLoc() const { + if (isNull()) + return TypeSpecLoc(); + + if (const DeclaratorLoc *DL = dyn_cast<DeclaratorLoc>(this)) + return DL->getTypeSpecLoc(); + return cast<TypeSpecLoc>(*this); +} + +/// \brief Find the TypeSpecLoc that is part of this TypeLoc and return its +/// SourceRange. +SourceRange TypeLoc::getTypeSpecRange() const { + return getTypeSpecLoc().getSourceRange(); +} + +namespace { + +/// \brief Report the full source info data size for the visited TypeLoc. +class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { +public: +#define ABSTRACT_TYPELOC(CLASS) +#define TYPELOC(CLASS, PARENT, TYPE) \ + unsigned Visit##CLASS(CLASS TyLoc) { return TyLoc.getFullDataSize(); } +#include "clang/AST/TypeLocNodes.def" + + unsigned VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A type loc wrapper was not handled!"); + return 0; + } +}; + +} + +/// \brief Returns the size of the type source info data block. +unsigned TypeLoc::getFullDataSize() const { + if (isNull()) return 0; + return TypeSizer().Visit(*this); +} + +namespace { + +/// \brief Return the "next" TypeLoc for the visited TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { +public: +#define TYPELOC(CLASS, PARENT, TYPE) +#define DECLARATOR_TYPELOC(CLASS, TYPE) \ + TypeLoc Visit##CLASS(CLASS TyLoc); +#include "clang/AST/TypeLocNodes.def" + + TypeLoc VisitTypeSpecLoc(TypeLoc TyLoc) { return TypeLoc(); } + TypeLoc VisitObjCProtocolListLoc(ObjCProtocolListLoc TL); + + TypeLoc VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A declarator loc wrapper was not handled!"); + return TypeLoc(); + } +}; + +} + +TypeLoc NextLoc::VisitObjCProtocolListLoc(ObjCProtocolListLoc TL) { + return TL.getBaseTypeLoc(); +} + +TypeLoc NextLoc::VisitPointerLoc(PointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitMemberPointerLoc(MemberPointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitBlockPointerLoc(BlockPointerLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitReferenceLoc(ReferenceLoc TL) { + return TL.getPointeeLoc(); +} +TypeLoc NextLoc::VisitFunctionLoc(FunctionLoc TL) { + return TL.getResultLoc(); +} +TypeLoc NextLoc::VisitArrayLoc(ArrayLoc TL) { + return TL.getElementLoc(); +} + +/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +TypeLoc TypeLoc::getNextTypeLoc() const { + return NextLoc().Visit(*this); +} + +//===----------------------------------------------------------------------===// +// TypeSpecLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { +class TypeSpecChecker : public TypeLocVisitor<TypeSpecChecker, bool> { +public: + bool VisitTypeSpecLoc(TypeSpecLoc TyLoc) { return true; } +}; + +} + +bool TypeSpecLoc::classof(const TypeLoc *TL) { + return TypeSpecChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// DeclaratorLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +/// \brief Return the TypeSpecLoc for the visited DeclaratorLoc. +class TypeSpecGetter : public TypeLocVisitor<TypeSpecGetter, TypeSpecLoc> { +public: +#define TYPELOC(CLASS, PARENT, TYPE) +#define DECLARATOR_TYPELOC(CLASS, TYPE) \ + TypeSpecLoc Visit##CLASS(CLASS TyLoc) { return TyLoc.getTypeSpecLoc(); } +#include "clang/AST/TypeLocNodes.def" + + TypeSpecLoc VisitTypeLoc(TypeLoc TyLoc) { + assert(0 && "A declarator loc wrapper was not handled!"); + return TypeSpecLoc(); + } +}; + +} + +/// \brief Find the TypeSpecLoc that is part of this DeclaratorLoc. +TypeSpecLoc DeclaratorLoc::getTypeSpecLoc() const { + return TypeSpecGetter().Visit(*this); +} + +namespace { + +class DeclaratorLocChecker : public TypeLocVisitor<DeclaratorLocChecker, bool> { +public: + bool VisitDeclaratorLoc(DeclaratorLoc TyLoc) { return true; } +}; + +} + +bool DeclaratorLoc::classof(const TypeLoc *TL) { + return DeclaratorLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// DefaultTypeSpecLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class DefaultTypeSpecLocChecker : + public TypeLocVisitor<DefaultTypeSpecLocChecker, bool> { +public: + bool VisitDefaultTypeSpecLoc(DefaultTypeSpecLoc TyLoc) { return true; } +}; + +} + +bool DefaultTypeSpecLoc::classof(const TypeLoc *TL) { + return DefaultTypeSpecLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// TypedefLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class TypedefLocChecker : public TypeLocVisitor<TypedefLocChecker, bool> { +public: + bool VisitTypedefLoc(TypedefLoc TyLoc) { return true; } +}; + +} + +bool TypedefLoc::classof(const TypeLoc *TL) { + return TypedefLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCInterfaceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCInterfaceLocChecker : + public TypeLocVisitor<ObjCInterfaceLocChecker, bool> { +public: + bool VisitObjCInterfaceLoc(ObjCInterfaceLoc TyLoc) { return true; } +}; + +} + +bool ObjCInterfaceLoc::classof(const TypeLoc *TL) { + return ObjCInterfaceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ObjCProtocolListLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ObjCProtocolListLocChecker : + public TypeLocVisitor<ObjCProtocolListLocChecker, bool> { +public: + bool VisitObjCProtocolListLoc(ObjCProtocolListLoc TyLoc) { return true; } +}; + +} + +bool ObjCProtocolListLoc::classof(const TypeLoc *TL) { + return ObjCProtocolListLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// PointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class PointerLocChecker : public TypeLocVisitor<PointerLocChecker, bool> { +public: + bool VisitPointerLoc(PointerLoc TyLoc) { return true; } +}; + +} + +bool PointerLoc::classof(const TypeLoc *TL) { + return PointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// BlockPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class BlockPointerLocChecker : + public TypeLocVisitor<BlockPointerLocChecker, bool> { +public: + bool VisitBlockPointerLoc(BlockPointerLoc TyLoc) { return true; } +}; + +} + +bool BlockPointerLoc::classof(const TypeLoc *TL) { + return BlockPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// MemberPointerLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class MemberPointerLocChecker : + public TypeLocVisitor<MemberPointerLocChecker, bool> { +public: + bool VisitMemberPointerLoc(MemberPointerLoc TyLoc) { return true; } +}; + +} + +bool MemberPointerLoc::classof(const TypeLoc *TL) { + return MemberPointerLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ReferenceLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ReferenceLocChecker : public TypeLocVisitor<ReferenceLocChecker, bool> { +public: + bool VisitReferenceLoc(ReferenceLoc TyLoc) { return true; } +}; + +} + +bool ReferenceLoc::classof(const TypeLoc *TL) { + return ReferenceLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// FunctionLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class FunctionLocChecker : public TypeLocVisitor<FunctionLocChecker, bool> { +public: + bool VisitFunctionLoc(FunctionLoc TyLoc) { return true; } +}; + +} + +bool FunctionLoc::classof(const TypeLoc *TL) { + return FunctionLocChecker().Visit(*TL); +} + +//===----------------------------------------------------------------------===// +// ArrayLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class ArrayLocChecker : public TypeLocVisitor<ArrayLocChecker, bool> { +public: + bool VisitArrayLoc(ArrayLoc TyLoc) { return true; } +}; + +} + +bool ArrayLoc::classof(const TypeLoc *TL) { + return ArrayLocChecker().Visit(*TL); +} |
