diff options
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/APValue.cpp | 3 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 211 | ||||
-rw-r--r-- | lib/AST/ASTDiagnostic.cpp | 6 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 28 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 193 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 38 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 48 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 18 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 69 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 22 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 59 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 444 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 53 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 112 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 568 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.h | 8 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 89 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 78 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 73 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 28 | ||||
-rw-r--r-- | lib/AST/TemplateName.cpp | 18 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 20 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 4 |
23 files changed, 1523 insertions, 667 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 50a6e0a..731d5e0 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -48,7 +48,8 @@ const APValue &APValue::operator=(const APValue &RHS) { else if (isFloat()) setFloat(RHS.getFloat()); else if (isVector()) - setVector(((Vec*)(char*)RHS.Data)->Elts, RHS.getVectorLength()); + setVector(((const Vec *)(const char *)RHS.Data)->Elts, + RHS.getVectorLength()); else if (isComplexInt()) setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); else if (isComplexFloat()) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c77acce..eea727d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -41,6 +41,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, Builtin::Context &builtins, bool FreeMem, unsigned size_reserve) : GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + NSConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), @@ -325,55 +326,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } -CXXMethodVector::iterator CXXMethodVector::begin() const { - if ((Storage & 0x01) == 0) - return reinterpret_cast<iterator>(&Storage); - - vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01); - return &Vec->front(); -} - -CXXMethodVector::iterator CXXMethodVector::end() const { - if ((Storage & 0x01) == 0) { - if (Storage == 0) - return reinterpret_cast<iterator>(&Storage); - - return reinterpret_cast<iterator>(&Storage) + 1; - } - - vector_type *Vec = reinterpret_cast<vector_type *>(Storage & ~0x01); - return &Vec->front() + Vec->size(); -} - -void CXXMethodVector::push_back(const CXXMethodDecl *Method) { - if (Storage == 0) { - // 0 -> 1 element. - Storage = reinterpret_cast<uintptr_t>(Method); - return; - } - - vector_type *Vec; - if ((Storage & 0x01) == 0) { - // 1 -> 2 elements. Allocate a new vector and push the element into that - // vector. - Vec = new vector_type; - Vec->push_back(reinterpret_cast<const CXXMethodDecl *>(Storage)); - Storage = reinterpret_cast<uintptr_t>(Vec) | 0x01; - } else - Vec = reinterpret_cast<vector_type *>(Storage & ~0x01); - - // Add the new method to the vector. - Vec->push_back(Method); -} - -void CXXMethodVector::Destroy() { - if (Storage & 0x01) - delete reinterpret_cast<vector_type *>(Storage & ~0x01); - - Storage = 0; -} - - ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos @@ -515,7 +467,7 @@ ASTContext::getTypeInfo(const Type *T) { Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. - if (VT->getNumElements() & (VT->getNumElements()-1)) { + if (Align & (Align-1)) { Align = llvm::NextPowerOf2(Align); Width = llvm::RoundUpToAlignment(Width, Align); } @@ -701,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr()); - case Type::InjectedClassName: - return getTypeInfo(cast<InjectedClassNameType>(T) - ->getUnderlyingType().getTypePtr()); - case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); @@ -833,9 +781,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, CollectInheritedProtocols(SD, Protocols); SD = SD->getSuperClass(); } - return; - } - if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { + } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -844,9 +790,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; - } - if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { + } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); @@ -855,26 +799,20 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, PE = Proto->protocol_end(); P != PE; ++P) CollectInheritedProtocols(*P, Protocols); } - return; } } unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) { unsigned count = 0; // Count ivars declared in class extension. - if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { - for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); I != E; ++I) { - ++count; - } - } - + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) + count += CDecl->ivar_size(); + // Count ivar defined in this class's implementation. This // includes synthesized ivars. if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) - for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); I != E; ++I) - ++count; + count += ImplDecl->ivar_size(); + return count; } @@ -998,6 +936,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { ASTRecordLayoutBuilder::ComputeLayout(*this, D); ASTRecordLayouts[D] = NewEntry; + if (getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::errs()); + } + return *NewEntry; } @@ -1735,8 +1678,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); } else { - Decl->TypeForDecl = new (*this, TypeAlignment) - InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal()); + Decl->TypeForDecl = + new (*this, TypeAlignment) InjectedClassNameType(Decl, TST); Types.push_back(Decl->TypeForDecl); } return QualType(Decl->TypeForDecl, 0); @@ -1867,7 +1810,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { unsigned NumArgs = Args.size(); llvm::SmallVector<TemplateArgument, 4> ArgVec; @@ -1875,17 +1819,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); - return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon); + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, + Canon, IsCurrentInstantiation); } QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { if (!Canon.isNull()) Canon = getCanonicalType(Canon); else { + assert(!IsCurrentInstantiation && + "current-instantiation specializations should always " + "have a canonical type"); + // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); llvm::SmallVector<TemplateArgument, 4> CanonArgs; @@ -1896,7 +1846,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; - TemplateSpecializationType::Profile(ID, CanonTemplate, + TemplateSpecializationType::Profile(ID, CanonTemplate, false, CanonArgs.data(), NumArgs, *this); void *InsertPos = 0; @@ -1908,7 +1858,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), TypeAlignment); - Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, + Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false, CanonArgs.data(), NumArgs, Canon); Types.push_back(Spec); @@ -1928,7 +1878,9 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, sizeof(TemplateArgument) * NumArgs), TypeAlignment); TemplateSpecializationType *Spec - = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs, + = new (Mem) TemplateSpecializationType(*this, Template, + IsCurrentInstantiation, + Args, NumArgs, Canon); Types.push_back(Spec); @@ -2108,10 +2060,10 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, if (!InterfaceT.isCanonical() || !areSortedAndUniqued(Protocols, NumProtocols)) { if (!areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); SortAndUniqueProtocols(&Sorted[0], UniqueCount); Canonical = getObjCObjectPointerType(getCanonicalType(InterfaceT), @@ -2154,8 +2106,8 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, // Sort the protocol list alphabetically to canonicalize it. QualType Canonical; if (NumProtocols && !areSortedAndUniqued(Protocols, NumProtocols)) { - llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(NumProtocols); - std::copy(Protocols, Protocols + NumProtocols, Sorted.begin()); + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, + Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; SortAndUniqueProtocols(&Sorted[0], UniqueCount); @@ -2634,14 +2586,9 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { 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); - } - } + while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0))) + QT = AT->getElementType(); + return Qs.apply(QT); } QualType ASTContext::getBaseElementType(const ArrayType *AT) { @@ -2886,6 +2833,7 @@ QualType ASTContext::getCFConstantStringType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } @@ -2901,6 +2849,46 @@ void ASTContext::setCFConstantStringType(QualType T) { CFConstantStringTypeDecl = Rec->getDecl(); } +// getNSConstantStringType - Return the type used for constant NSStrings. +QualType ASTContext::getNSConstantStringType() { + if (!NSConstantStringTypeDecl) { + NSConstantStringTypeDecl = + CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__builtin_NSString")); + NSConstantStringTypeDecl->startDefinition(); + + QualType FieldTypes[3]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.withConst()); + // const char *str; + FieldTypes[1] = getPointerType(CharTy.withConst()); + // unsigned int length; + FieldTypes[2] = UnsignedIntTy; + + // Create fields + for (unsigned i = 0; i < 3; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false); + Field->setAccess(AS_public); + NSConstantStringTypeDecl->addDecl(Field); + } + + NSConstantStringTypeDecl->completeDefinition(); + } + + return getTagDeclType(NSConstantStringTypeDecl); +} + +void ASTContext::setNSConstantStringType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid NSConstantStringType"); + NSConstantStringTypeDecl = Rec->getDecl(); +} + QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = @@ -2923,6 +2911,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); ObjCFastEnumerationStateTypeDecl->addDecl(Field); } @@ -2960,6 +2949,7 @@ QualType ASTContext::getBlockDescriptorType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3008,6 +2998,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() { FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3085,6 +3076,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3129,6 +3121,7 @@ QualType ASTContext::getBlockParmType( &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3149,6 +3142,7 @@ QualType ASTContext::getBlockParmType( FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), Name, FieldType, /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); + Field->setAccess(AS_public); T->addDecl(Field); } @@ -3192,7 +3186,7 @@ std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } -/// getObjCEncodingForBlockDecl - Return the encoded type for this method +/// getObjCEncodingForBlockDecl - Return the encoded type for this block /// declaration. void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) { @@ -3207,7 +3201,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, SourceLocation Loc; CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); CharUnits ParmOffset = PtrSize; - for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E = Decl->param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); @@ -3258,7 +3252,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // their size. CharUnits ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); assert (sz.isPositive() && @@ -3272,7 +3266,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, // Argument types. ParmOffset = 2 * PtrSize; for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), - E = Decl->param_end(); PI != E; ++PI) { + E = Decl->sel_param_end(); PI != E; ++PI) { ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = @@ -3494,13 +3488,18 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, return; } + // encoding for pointer or r3eference types. + QualType PointeeTy; if (const PointerType *PT = T->getAs<PointerType>()) { if (PT->isObjCSelType()) { S += ':'; return; } - QualType PointeeTy = PT->getPointeeType(); - + PointeeTy = PT->getPointeeType(); + } + else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + PointeeTy = RT->getPointeeType(); + if (!PointeeTy.isNull()) { bool isReadOnly = false; // For historical/compatibility reasons, the read-only qualifier of the // pointee gets emitted _before_ the '^'. The read-only qualifier of @@ -3524,12 +3523,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // Another legacy compatibility encoding. Some ObjC qualifier and type // combinations need to be rearranged. // Rewrite "in const" from "nr" to "rn" - const char * s = S.c_str(); - int len = S.length(); - if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') { - std::string replace = "rn"; - S.replace(S.end()-2, S.end(), replace); - } + if (llvm::StringRef(S).endswith("nr")) + S.replace(S.end()-2, S.end(), "rn"); } if (PointeeTy->isCharType()) { @@ -3559,7 +3554,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, NULL); return; } - + if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { @@ -4136,15 +4131,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, const ObjCObjectPointerType *RHSOPT) { - if (RHSOPT->isObjCBuiltinType() || - LHSOPT->isObjCIdType() || LHSOPT->isObjCQualifiedIdType()) + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; if (LHSOPT->isObjCBuiltinType()) { return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); } - if (RHSOPT->isObjCQualifiedIdType()) + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); @@ -4190,7 +4184,8 @@ void getIntersectionOfProtocols(ASTContext &Context, unsigned RHSNumProtocols = RHS->getNumProtocols(); if (RHSNumProtocols > 0) { - ObjCProtocolDecl **RHSProtocols = (ObjCProtocolDecl **)RHS->qual_begin(); + ObjCProtocolDecl **RHSProtocols = + const_cast<ObjCProtocolDecl **>(RHS->qual_begin()); for (unsigned i = 0; i < RHSNumProtocols; ++i) if (InheritedProtocolSet.count(RHSProtocols[i])) IntersectionOfProtocols.push_back(RHSProtocols[i]); diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 866b7f7..e4cd2a9 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, continue; } - // ...or an injected class name... - if (isa<InjectedClassNameType>(Ty)) { - QT = cast<InjectedClassNameType>(Ty)->desugar(); - continue; - } - // ...or a substituted template type parameter. if (isa<SubstTemplateTypeParmType>(Ty)) { QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 5dfb99f..ae09d79 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); if (!IsStructurallyEquivalent(Context, - Inj1->getUnderlyingType(), - Inj2->getUnderlyingType())) + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) return false; break; } @@ -1438,7 +1438,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { for (DeclContext::lookup_result Lookup = DC->lookup(Name); Lookup.first != Lookup.second; ++Lookup.first) { - if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) { @@ -1451,7 +1451,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { } if (!ConflictingDecls.empty()) { - Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(), ConflictingDecls.size()); } @@ -1905,6 +1905,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc, Name, T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); } @@ -2125,7 +2126,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, - D->getStorageClass()); + D->getStorageClass(), + D->getStorageClassAsWritten()); // Import the qualifier, if any. if (D->getQualifier()) { NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); @@ -2197,6 +2199,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), /*FIXME: Default argument*/ 0); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); return Importer.Imported(D, ToParm); @@ -2312,7 +2315,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ToMethod->addDecl(ToParams[I]); } ToMethod->setMethodParams(Importer.getToContext(), - ToParams.data(), ToParams.size()); + ToParams.data(), ToParams.size(), + ToParams.size()); ToMethod->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToMethod); @@ -2881,8 +2885,11 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { if (!SubExpr) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), - SubExpr, + SubExpr, BasePath, E->isLvalueCast()); } @@ -2899,8 +2906,11 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { if (!TInfo && E->getTypeInfoAsWritten()) return 0; + // FIXME: Initialize the base path. + assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); + CXXBaseSpecifierArray BasePath; return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(), - SubExpr, TInfo, + SubExpr, BasePath, TInfo, Importer.Import(E->getLParenLoc()), Importer.Import(E->getRParenLoc())); } @@ -3086,7 +3096,7 @@ FileID ASTImporter::Import(FileID FromID) { FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! - const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags()); + const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM); llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dc9fb59..ffe4967 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -25,7 +25,6 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Parse/DeclSpec.h" #include "llvm/Support/ErrorHandling.h" -#include <vector> using namespace clang; @@ -286,6 +285,28 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { } Linkage NamedDecl::getLinkage() const { + + // Objective-C: treat all Objective-C declarations as having external + // linkage. + switch (getKind()) { + default: + break; + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCClass: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCForwardProtocol: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCIvar: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + return ExternalLinkage; + } + // Handle linkage for namespace-scope names. if (getDeclContext()->getLookupContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) @@ -354,88 +375,79 @@ std::string NamedDecl::getQualifiedNameAsString() const { } std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { - // FIXME: Collect contexts, then accumulate names to avoid unnecessary - // std::string thrashing. - std::vector<std::string> Names; - std::string QualName; const DeclContext *Ctx = getDeclContext(); if (Ctx->isFunctionOrMethod()) return getNameAsString(); - while (Ctx) { + typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy; + ContextsTy Contexts; + + // Collect contexts. + while (Ctx && isa<NamedDecl>(Ctx)) { + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + }; + + std::string QualName; + llvm::raw_string_ostream OS(QualName); + + for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend(); + I != E; ++I) { if (const ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + = dyn_cast<ClassTemplateSpecializationDecl>(*I)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); std::string TemplateArgsStr = TemplateSpecializationType::PrintTemplateArgumentList( TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size(), P); - Names.push_back(Spec->getIdentifier()->getNameStart() + TemplateArgsStr); - } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(Ctx)) { + OS << Spec->getName() << TemplateArgsStr; + } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) { if (ND->isAnonymousNamespace()) - Names.push_back("<anonymous namespace>"); + OS << "<anonymous namespace>"; else - Names.push_back(ND->getNameAsString()); - } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(Ctx)) { - if (!RD->getIdentifier()) { - std::string RecordString = "<anonymous "; - RecordString += RD->getKindName(); - RecordString += ">"; - Names.push_back(RecordString); - } else { - Names.push_back(RD->getNameAsString()); - } - } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Ctx)) { - std::string Proto = FD->getNameAsString(); - + OS << ND; + } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) { + if (!RD->getIdentifier()) + OS << "<anonymous " << RD->getKindName() << '>'; + else + OS << RD; + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); - Proto += "("; + OS << FD << '('; if (FT) { - llvm::raw_string_ostream POut(Proto); unsigned NumParams = FD->getNumParams(); for (unsigned i = 0; i < NumParams; ++i) { if (i) - POut << ", "; + OS << ", "; std::string Param; FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); - POut << Param; + OS << Param; } if (FT->isVariadic()) { if (NumParams > 0) - POut << ", "; - POut << "..."; + OS << ", "; + OS << "..."; } } - Proto += ")"; - - Names.push_back(Proto); - } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) - Names.push_back(ND->getNameAsString()); - else - break; - - Ctx = Ctx->getParent(); + OS << ')'; + } else { + OS << cast<NamedDecl>(*I); + } + OS << "::"; } - std::vector<std::string>::reverse_iterator - I = Names.rbegin(), - End = Names.rend(); - - for (; I!=End; ++I) - QualName += *I + "::"; - if (getDeclName()) - QualName += getNameAsString(); + OS << this; else - QualName += "<anonymous>"; + OS << "<anonymous>"; - return QualName; + return OS.str(); } bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { @@ -494,6 +506,24 @@ NamedDecl *NamedDecl::getUnderlyingDecl() { } } +bool NamedDecl::isCXXInstanceMember() const { + assert(isCXXClassMember() && + "checking whether non-member is instance member"); + + const NamedDecl *D = this; + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + if (isa<FieldDecl>(D)) + return true; + if (isa<CXXMethodDecl>(D)) + return cast<CXXMethodDecl>(D)->isInstance(); + if (isa<FunctionTemplateDecl>(D)) + return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D) + ->getTemplatedDecl())->isInstance(); + return false; +} + //===----------------------------------------------------------------------===// // DeclaratorDecl Implementation //===----------------------------------------------------------------------===// @@ -568,8 +598,8 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S) { - return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S); + StorageClass S, StorageClass SCAsWritten) { + return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } void VarDecl::Destroy(ASTContext& C) { @@ -793,8 +823,10 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, S, DefArg); + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, + S, SCAsWritten, DefArg); } Expr *ParmVarDecl::getDefaultArg() { @@ -874,6 +906,12 @@ void FunctionDecl::getNameForDiagnostic(std::string &S, } +bool FunctionDecl::isVariadic() const { + if (const FunctionProtoType *FT = getType()->getAs<FunctionProtoType>()) + return FT->isVariadic(); + return false; +} + Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { if (I->Body) { @@ -1291,6 +1329,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, } } +void +FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs) { + assert(TemplateOrSpecialization.isNull()); + size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); + Size += Templates.size() * sizeof(FunctionTemplateDecl*); + Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc); + void *Buffer = Context.Allocate(Size); + DependentFunctionTemplateSpecializationInfo *Info = + new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, + TemplateArgs); + TemplateOrSpecialization = Info; +} + +DependentFunctionTemplateSpecializationInfo:: +DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, + const TemplateArgumentListInfo &TArgs) + : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + + d.NumTemplates = Ts.size(); + d.NumArgs = TArgs.size(); + + FunctionTemplateDecl **TsArray = + const_cast<FunctionTemplateDecl**>(getTemplates()); + for (unsigned I = 0, E = Ts.size(); I != E; ++I) + TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl()); + + TemplateArgumentLoc *ArgsArray = + const_cast<TemplateArgumentLoc*>(getTemplateArgs()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) + new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); +} + TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. @@ -1407,6 +1479,10 @@ void TagDecl::startDefinition() { if (TagType *TagT = const_cast<TagType *>(TypeForDecl->getAs<TagType>())) { TagT->decl.setPointer(this); TagT->decl.setInt(1); + } else if (InjectedClassNameType *Injected + = const_cast<InjectedClassNameType *>( + TypeForDecl->getAs<InjectedClassNameType>())) { + Injected->Decl = cast<CXXRecordDecl>(this); } if (isa<CXXRecordDecl>(this)) { @@ -1428,6 +1504,11 @@ void TagDecl::completeDefinition() { assert(TagT->decl.getPointer() == this && "Attempt to redefine a tag definition?"); TagT->decl.setInt(0); + } else if (InjectedClassNameType *Injected + = const_cast<InjectedClassNameType *>( + TypeForDecl->getAs<InjectedClassNameType>())) { + assert(Injected->Decl == this && + "Attempt to redefine a class template definition?"); } } @@ -1606,10 +1687,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass S, bool isInline, - bool hasWrittenPrototype) { - FunctionDecl *New - = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, S, isInline); + StorageClass S, StorageClass SCAsWritten, + bool isInline, bool hasWrittenPrototype) { + FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, + S, SCAsWritten, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index c693e15..b5aec0c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -231,24 +231,28 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case CXXConstructor: case CXXDestructor: case CXXConversion: - case Typedef: case EnumConstant: case Var: case ImplicitParam: case ParmVar: case NonTypeTemplateParm: case ObjCMethod: - case ObjCContainer: - case ObjCInterface: case ObjCProperty: - case ObjCCompatibleAlias: return IDNS_Ordinary; + case ObjCCompatibleAlias: + case ObjCInterface: + return IDNS_Ordinary | IDNS_Type; + + case Typedef: + case UnresolvedUsingTypename: + case TemplateTypeParm: + return IDNS_Ordinary | IDNS_Type; + case UsingShadow: return 0; // we'll actually overwrite this later case UnresolvedUsingValue: - case UnresolvedUsingTypename: return IDNS_Ordinary | IDNS_Using; case Using: @@ -257,13 +261,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCProtocol: return IDNS_ObjCProtocol; - case ObjCImplementation: - return IDNS_ObjCImplementation; - - case ObjCCategory: - case ObjCCategoryImpl: - return IDNS_ObjCCategoryName; - case Field: case ObjCAtDefsField: case ObjCIvar: @@ -272,16 +269,18 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Record: case CXXRecord: case Enum: - case TemplateTypeParm: - return IDNS_Tag; + return IDNS_Tag | IDNS_Type; case Namespace: - case Template: + case NamespaceAlias: + return IDNS_Namespace; + case FunctionTemplate: + return IDNS_Ordinary; + case ClassTemplate: case TemplateTemplateParm: - case NamespaceAlias: - return IDNS_Tag | IDNS_Ordinary; + return IDNS_Ordinary | IDNS_Tag | IDNS_Type; // Never have names. case Friend: @@ -295,10 +294,13 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Block: case TranslationUnit: - // Aren't looked up? case UsingDirective: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: + case ObjCImplementation: + case ObjCCategory: + case ObjCCategoryImpl: + // Never looked up by name. return 0; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 94ed85c..68f4a82 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -587,9 +587,9 @@ CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, - bool isStatic, bool isInline) { + bool isStatic, StorageClass SCAsWritten, bool isInline) { return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, - isStatic, isInline); + isStatic, SCAsWritten, isInline); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -633,6 +633,27 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { return true; } +bool CXXMethodDecl::isCopyAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared copy assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of + // type X, X&, const X&, volatile X& or const volatile X&. + if (/*operator=*/getOverloadedOperator() != OO_Equal || + /*non-static*/ isStatic() || + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() || + /*exactly one parameter*/getNumParams() != 1) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>()) + ParamType = Ref->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { assert(MD->isCanonicalDecl() && "Method is not canonical!"); assert(!MD->getParent()->isDependentContext() && @@ -659,15 +680,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { assert(isInstance() && "No 'this' for static methods!"); QualType ClassTy = C.getTypeDeclType(getParent()); - - // Aesthetically we prefer not to synthesize a type as the - // InjectedClassNameType of a template pattern: injected class names - // are printed without template arguments, which might - // surprise/confuse/distract our poor users if they didn't - // explicitly write one. - if (isa<InjectedClassNameType>(ClassTy)) - ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType(); - ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); @@ -686,9 +698,9 @@ bool CXXMethodDecl::hasInlineBody() const { CXXBaseOrMemberInitializer:: CXXBaseOrMemberInitializer(ASTContext &Context, - TypeSourceInfo *TInfo, + TypeSourceInfo *TInfo, bool IsVirtual, SourceLocation L, Expr *Init, SourceLocation R) - : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), + : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0), IsVirtual(IsVirtual), LParenLoc(L), RParenLoc(R) { } @@ -745,11 +757,12 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, QualType T, TypeSourceInfo *TInfo, bool isExplicit, - bool isInline, bool isImplicitlyDeclared) { + bool isInline, + bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared); + return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, + isInline, isImplicitlyDeclared); } bool CXXConstructorDecl::isDefaultConstructor() const { @@ -848,8 +861,7 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, bool isImplicitlyDeclared) { assert(N.getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, - isImplicitlyDeclared); + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); } void diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 821e38b..dc4aacd 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -330,11 +330,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isInstance, bool isVariadic, bool isSynthesized, - ImplementationControl impControl) { + ImplementationControl impControl, + unsigned numSelectorArgs) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, - isVariadic, isSynthesized, impControl); + isVariadic, isSynthesized, impControl, + numSelectorArgs); } void ObjCMethodDecl::Destroy(ASTContext &C) { @@ -841,6 +843,12 @@ FindPropertyImplDecl(IdentifierInfo *Id) const { return 0; } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCCategoryImplDecl *CID) { + OS << CID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCImplementationDecl //===----------------------------------------------------------------------===// @@ -853,6 +861,12 @@ ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCImplementationDecl *ID) { + OS << ID->getName(); + return OS; +} + //===----------------------------------------------------------------------===// // ObjCCompatibleAliasDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index a625865..53949247 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -301,17 +301,15 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { } void DeclPrinter::VisitEnumDecl(EnumDecl *D) { - Out << "enum " << D->getNameAsString() << " {\n"; + Out << "enum " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } void DeclPrinter::VisitRecordDecl(RecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { Out << " {\n"; @@ -321,7 +319,7 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { } void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { - Out << D->getNameAsString(); + Out << D; if (Expr *Init = D->getInitExpr()) { Out << " = "; Init->printPretty(Out, Context, 0, Policy, Indentation); @@ -406,7 +404,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << ", "; if (BMInitializer->isMemberInitializer()) { FieldDecl *FD = BMInitializer->getMember(); - Out << FD->getNameAsString(); + Out << FD; } else { Out << QualType(BMInitializer->getBaseClass(), 0).getAsString(); } @@ -537,7 +535,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { // C++ declarations //---------------------------------------------------------------------------- void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { - Out << "namespace " << D->getNameAsString() << " {\n"; + Out << "namespace " << D << " {\n"; VisitDeclContext(D); Indent() << "}"; } @@ -546,22 +544,20 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { Out << "using namespace "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getNominatedNamespaceAsWritten()->getNameAsString(); + Out << D->getNominatedNamespaceAsWritten(); } void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - Out << "namespace " << D->getNameAsString() << " = "; + Out << "namespace " << D << " = "; if (D->getQualifier()) D->getQualifier()->print(Out, Policy); - Out << D->getAliasedNamespace()->getNameAsString(); + Out << D->getAliasedNamespace(); } void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << D->getKindName(); - if (D->getIdentifier()) { - Out << " "; - Out << D->getNameAsString(); - } + if (D->getIdentifier()) + Out << ' ' << D; if (D->isDefinition()) { // Print the base classes @@ -669,7 +665,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) { if (I != D->begin()) Out << ", "; - Out << I->getInterface()->getNameAsString(); + Out << I->getInterface(); } } @@ -688,8 +684,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { // FIXME: selector is missing here! pos = name.find_first_of(":", lastPos); Out << " " << name.substr(lastPos, pos - lastPos); - Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" - << (*PI)->getNameAsString(); + Out << ":(" << (*PI)->getType().getAsString(Policy) << ')' << *PI; lastPos = pos + 1; } @@ -711,7 +706,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@implementation " << I << " : " << SID->getNameAsString(); + Out << "@implementation " << I << " : " << SID; else Out << "@implementation " << I; Out << "\n"; @@ -724,7 +719,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { ObjCInterfaceDecl *SID = OID->getSuperClass(); if (SID) - Out << "@interface " << I << " : " << SID->getNameAsString(); + Out << "@interface " << I << " : " << SID; else Out << "@interface " << I; @@ -733,7 +728,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { if (!Protocols.empty()) { for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) - Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); + Out << (I == Protocols.begin() ? '<' : ',') << *I; } if (!Protocols.empty()) @@ -744,8 +739,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { 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"; + Indent() << (*I)->getType().getAsString(Policy) << ' ' << *I << ";\n"; } Indentation -= Policy.Indentation; Out << "}\n"; @@ -762,20 +756,18 @@ void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { E = D->protocol_end(); I != E; ++I) { if (I != D->protocol_begin()) Out << ", "; - Out << (*I)->getNameAsString(); + Out << *I; } } void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { - Out << "@protocol " << PID->getNameAsString() << '\n'; + Out << "@protocol " << PID << '\n'; VisitDeclContext(PID, false); Out << "@end"; } void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { - Out << "@implementation " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -783,9 +775,7 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { } void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { - Out << "@interface " - << PID->getClassInterface()->getNameAsString() - << '(' << PID->getNameAsString() << ")\n"; + Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n"; VisitDeclContext(PID, false); Out << "@end"; @@ -793,8 +783,8 @@ void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { } void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { - Out << "@compatibility_alias " << AID->getNameAsString() - << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; + Out << "@compatibility_alias " << AID + << ' ' << AID->getClassInterface() << ";\n"; } /// PrintObjCPropertyDecl - print a property declaration. @@ -854,8 +844,7 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { } Out << " )"; } - Out << ' ' << PDecl->getType().getAsString(Policy) - << ' ' << PDecl->getNameAsString(); + Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { @@ -863,28 +852,28 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { Out << "@synthesize "; else Out << "@dynamic "; - Out << PID->getPropertyDecl()->getNameAsString(); + Out << PID->getPropertyDecl(); if (PID->getPropertyIvarDecl()) - Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); + Out << '=' << PID->getPropertyIvarDecl(); } void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << "using "; D->getTargetNestedNameDecl()->print(Out, Policy); - Out << D->getNameAsString(); + Out << D; } void DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { Out << "using typename "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getDeclName().getAsString(); + Out << D->getDeclName(); } void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index b449398..c498dea 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -178,6 +178,20 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +void ClassTemplateDecl::getPartialSpecializations( + llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs + = CommonPtr->PartialSpecializations; + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = &*P; + } +} + ClassTemplatePartialSpecializationDecl * ClassTemplateDecl::findPartialSpecialization(QualType T) { ASTContext &Context = getASTContext(); @@ -186,7 +200,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { for (partial_spec_iterator P = getPartialSpecializations().begin(), PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { - if (Context.hasSameType(Context.getTypeDeclType(&*P), T)) + if (Context.hasSameType(P->getInjectedSpecializationType(), T)) return &*P; } @@ -456,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, QualType CanonInjectedType, - ClassTemplatePartialSpecializationDecl *PrevDecl) { + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) { unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; for (unsigned I = 0; I != N; ++I) @@ -468,7 +483,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, SpecializedTemplate, Builder, ClonedArgs, N, - PrevDecl); + PrevDecl, + SequenceNumber); Result->setSpecializationKind(TSK_ExplicitSpecialization); Context.getInjectedClassNameType(Result, CanonInjectedType); diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 19b58bc..4f85fca 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -18,7 +18,7 @@ #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include <cstdio> +#include "llvm/Support/raw_ostream.h" using namespace clang; namespace clang { @@ -202,32 +202,42 @@ bool DeclarationName::isDependentName() const { } std::string DeclarationName::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationName::printName(llvm::raw_ostream &OS) const { switch (getNameKind()) { case Identifier: if (const IdentifierInfo *II = getAsIdentifierInfo()) - return II->getName(); - return ""; + OS << II->getName(); + return; case ObjCZeroArgSelector: case ObjCOneArgSelector: case ObjCMultiArgSelector: - return getObjCSelector().getAsString(); + OS << getObjCSelector().getAsString(); + return; case CXXConstructorName: { QualType ClassType = getCXXNameType(); if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) - return ClassRec->getDecl()->getNameAsString(); - return ClassType.getAsString(); + OS << ClassRec->getDecl(); + else + OS << ClassType.getAsString(); + return; } case CXXDestructorName: { - std::string Result = "~"; + OS << '~'; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXOperatorName: { @@ -240,32 +250,32 @@ std::string DeclarationName::getAsString() const { const char *OpName = OperatorNames[getCXXOverloadedOperator()]; assert(OpName && "not an overloaded operator"); - std::string Result = "operator"; + OS << "operator"; if (OpName[0] >= 'a' && OpName[0] <= 'z') - Result += ' '; - Result += OpName; - return Result; + OS << ' '; + OS << OpName; + return; } - case CXXLiteralOperatorName: { - return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName()); - } + case CXXLiteralOperatorName: + OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); + return; case CXXConversionFunctionName: { - std::string Result = "operator "; + OS << "operator "; QualType Type = getCXXNameType(); if (const RecordType *Rec = Type->getAs<RecordType>()) - Result += Rec->getDecl()->getNameAsString(); + OS << Rec->getDecl(); else - Result += Type.getAsString(); - return Result; + OS << Type.getAsString(); + return; } case CXXUsingDirective: - return "<using-directive>"; + OS << "<using-directive>"; + return; } assert(false && "Unexpected declaration name kind"); - return ""; } QualType DeclarationName::getCXXNameType() const { @@ -369,7 +379,8 @@ DeclarationName DeclarationName::getUsingDirectiveName() { } void DeclarationName::dump() const { - fprintf(stderr, "%s\n", getAsString().c_str()); + printName(llvm::errs()); + llvm::errs() << '\n'; } DeclarationNameTable::DeclarationNameTable() { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index ae4bc8c..00662a5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -27,6 +27,65 @@ #include <algorithm> using namespace clang; +/// isKnownToHaveBooleanValue - Return true if this is an integer expression +/// that is known to return 0 or 1. This happens for _Bool/bool expressions +/// but also int expressions which are produced by things like comparisons in +/// C. +bool Expr::isKnownToHaveBooleanValue() const { + // If this value has _Bool type, it is obvious 0/1. + if (getType()->isBooleanType()) return true; + // If this is a non-scalar-integer type, we don't care enough to try. + if (!getType()->isIntegralType()) return false; + + if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) + return PE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) { + switch (UO->getOpcode()) { + case UnaryOperator::Plus: + case UnaryOperator::Extension: + return UO->getSubExpr()->isKnownToHaveBooleanValue(); + default: + return false; + } + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(this)) + return CE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) { + switch (BO->getOpcode()) { + default: return false; + case BinaryOperator::LT: // Relational operators. + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: // Equality operators. + case BinaryOperator::NE: + case BinaryOperator::LAnd: // AND operator. + case BinaryOperator::LOr: // Logical OR operator. + return true; + + case BinaryOperator::And: // Bitwise AND operator. + case BinaryOperator::Xor: // Bitwise XOR operator. + case BinaryOperator::Or: // Bitwise OR operator. + // Handle things like (x==2)|(y==12). + return BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue(); + + case BinaryOperator::Comma: + case BinaryOperator::Assign: + return BO->getRHS()->isKnownToHaveBooleanValue(); + } + } + + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this)) + return CO->getTrueExpr()->isKnownToHaveBooleanValue() && + CO->getFalseExpr()->isKnownToHaveBooleanValue(); + + return false; +} + //===----------------------------------------------------------------------===// // Primary Expressions. //===----------------------------------------------------------------------===// @@ -231,14 +290,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { // For incorrect code, there might not be an ObjCInterfaceDecl. Do // a null check to avoid a crash. if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) - Out << ID->getNameAsString(); + Out << ID; if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) { - Out << '('; - Out << CID->getNameAsString(); - Out << ')'; - } + dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) + Out << '(' << CID << ')'; + Out << ' '; Out << MD->getSelector().getAsString(); Out << ']'; @@ -492,17 +549,70 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } +OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, + TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, + exprsPtr, numExprs, RParenLoc); +} + +OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, + unsigned numComps, unsigned numExprs) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + return new (Mem) OffsetOfExpr(numComps, numExprs); +} + +OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) + : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false, + /*ValueDependent=*/tsi->getType()->isDependentType() || + hasAnyTypeDependentArguments(exprsPtr, numExprs) || + hasAnyValueDependentArguments(exprsPtr, numExprs)), + OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), + NumComps(numComps), NumExprs(numExprs) +{ + for(unsigned i = 0; i < numComps; ++i) { + setComponent(i, compsPtr[i]); + } + + for(unsigned i = 0; i < numExprs; ++i) { + setIndexExpr(i, exprsPtr[i]); + } +} + +IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { + assert(getKind() == Field || getKind() == Identifier); + if (getKind() == Field) + return getField()->getIdentifier(); + + return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask); +} + MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, ValueDecl *memberdecl, - NamedDecl *founddecl, + DeclAccessPair founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); - bool hasQualOrFound = (qual != 0 || founddecl != memberdecl); + bool hasQualOrFound = (qual != 0 || + founddecl.getDecl() != memberdecl || + founddecl.getAccess() != memberdecl->getAccess()); if (hasQualOrFound) Size += sizeof(MemberNameQualifier); @@ -593,6 +703,12 @@ const char *CastExpr::getCastKindName() const { return 0; } +void CastExpr::DoDestroy(ASTContext &C) +{ + BasePath.Destroy(); + Expr::DoDestroy(C); +} + Expr *CastExpr::getSubExprAsWritten() { Expr *SubExpr = 0; CastExpr *E = this; @@ -720,10 +836,11 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { return OverOps[Opc]; } -InitListExpr::InitListExpr(SourceLocation lbraceloc, +InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, Expr **initExprs, unsigned numInits, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), false, false), + InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), UnionFieldInit(0), HadArrayRangeDesignator(false) { @@ -734,24 +851,24 @@ InitListExpr::InitListExpr(SourceLocation lbraceloc, ValueDependent = true; } - InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); + InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); } -void InitListExpr::reserveInits(unsigned NumInits) { +void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { if (NumInits > InitExprs.size()) - InitExprs.reserve(NumInits); + InitExprs.reserve(C, NumInits); } -void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { +void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); Idx < LastIdx; ++Idx) - InitExprs[Idx]->Destroy(Context); - InitExprs.resize(NumInits, 0); + InitExprs[Idx]->Destroy(C); + InitExprs.resize(C, NumInits, 0); } -Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { +Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { if (Init >= InitExprs.size()) { - InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0); InitExprs.back() = expr; return 0; } @@ -835,19 +952,22 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, } case BinaryOperatorClass: { const BinaryOperator *BO = cast<BinaryOperator>(this); - // Consider comma to have side effects if the LHS or RHS does. - if (BO->getOpcode() == BinaryOperator::Comma) { - // ((foo = <blah>), 0) is an idiom for hiding the result (and - // lvalue-ness) of an assignment written in a macro. - if (IntegerLiteral *IE = - dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens())) - if (IE->getValue() == 0) - return false; - - return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || - BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + switch (BO->getOpcode()) { + default: + break; + // Consider ',', '||', '&&' to have side effects if the LHS or RHS does. + case BinaryOperator::Comma: + // ((foo = <blah>), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + return (BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); } - if (BO->isAssignmentOp()) return false; Loc = BO->getOperatorLoc(); @@ -1219,11 +1339,13 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { return LV_Valid; case ObjCPropertyRefExprClass: // FIXME: check if read-only property. return LV_Valid; - case ObjCImplicitSetterGetterRefExprClass: // FIXME: check if read-only property. + case ObjCImplicitSetterGetterRefExprClass: + // FIXME: check if read-only property. return LV_Valid; case PredefinedExprClass: return LV_Valid; case UnresolvedLookupExprClass: + case UnresolvedMemberExprClass: return LV_Valid; case CXXDefaultArgExprClass: return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx); @@ -1821,7 +1943,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::AddrOf: case UnaryOperator::Deref: return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: case UnaryOperator::LNot: case UnaryOperator::Plus: @@ -1831,6 +1952,12 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case UnaryOperator::Imag: return CheckICE(Exp->getSubExpr(), Ctx); case UnaryOperator::OffsetOf: + break; + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { // Note that per C99, offsetof must be an ICE. And AFAIK, using // Evaluate matches the proposed gcc behavior for cases like // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect @@ -1838,7 +1965,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // array subscripts that aren't ICEs, and if the array subscripts // are ICEs, the value of the offsetof must be an integer constant. return CheckEvalInICE(E, Ctx); - } } case Expr::SizeOfAlignOfExprClass: { const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); @@ -1936,7 +2062,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ImplicitCastExprClass: case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: - case Expr::CXXNamedCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: { @@ -1953,7 +2078,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // 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. - if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) + if (const CallExpr *CallCE + = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { Expr::EvalResult EVResult; if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || @@ -2176,101 +2302,156 @@ void ExtVectorElementExpr::getEncodedElementAccess( } } -// constructor for instance messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, Expr *receiver, - Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), SelName(selInfo), - MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = receiver; - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -// FIXME: clsName should be typed to ObjCInterfaceType -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, IdentifierInfo *clsName, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, ObjCMethodDecl *mproto, - SourceLocation LBrac, SourceLocation RBrac, - Expr **ArgExprs, unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} - -// constructor for class messages. -ObjCMessageExpr::ObjCMessageExpr(ASTContext &C, ObjCInterfaceDecl *cls, - SourceLocation clsNameLoc, Selector selInfo, - QualType retType, - ObjCMethodDecl *mproto, SourceLocation LBrac, - SourceLocation RBrac, Expr **ArgExprs, - unsigned nargs) - : Expr(ObjCMessageExprClass, retType, false, false), ClassNameLoc(clsNameLoc), - SelName(selInfo), MethodProto(mproto) +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false, + /*ValueDependent=*/false), + NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), + HasMethod(Method != 0), SuperLoc(SuperLoc), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) { - NumArgs = nargs; - SubExprs = new (C) Stmt*[NumArgs+1]; - SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); - if (NumArgs) { - for (unsigned i = 0; i != NumArgs; ++i) - SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); - } - LBracloc = LBrac; - RBracloc = RBrac; -} + setReceiverPointer(SuperType.getAsOpaquePtr()); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, T->isDependentType(), + (T->isDependentType() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(), + (Receiver->isTypeDependent() || + hasAnyValueDependentArguments(Args, NumArgs))), + NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper, + SuperType, Sel, Method, Args, NumArgs, + RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args, + NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, + unsigned NumArgs) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); +} + +Selector ObjCMessageExpr::getSelector() const { + if (HasMethod) + return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod) + ->getSelector(); + return Selector(SelectorOrMethod); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + switch (getReceiverKind()) { + case Instance: + if (const ObjCObjectPointerType *Ptr + = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + break; -ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { - uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; - switch (x & Flags) { - default: - assert(false && "Invalid ObjCMessageExpr."); - case IsInstMeth: - return ClassInfo(0, 0, SourceLocation()); - case IsClsMethDeclUnknown: - return ClassInfo(0, (IdentifierInfo*) (x & ~Flags), ClassNameLoc); - case IsClsMethDeclKnown: { - ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); - return ClassInfo(D, D->getIdentifier(), ClassNameLoc); - } - } -} + case Class: + if (const ObjCInterfaceType *Iface + = getClassReceiver()->getAs<ObjCInterfaceType>()) + return Iface->getDecl(); + break; -void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { - if (CI.Decl == 0 && CI.Name == 0) { - SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); - return; - } + case SuperInstance: + if (const ObjCObjectPointerType *Ptr + = getSuperType()->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + break; - if (CI.Decl == 0) - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Name | IsClsMethDeclUnknown); - else - SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.Decl | IsClsMethDeclKnown); - ClassNameLoc = CI.Loc; -} + case SuperClass: + if (const ObjCObjectPointerType *Iface + = getSuperType()->getAs<ObjCObjectPointerType>()) + return Iface->getInterfaceDecl(); + break; + } -void ObjCMessageExpr::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (SubExprs) - C.Deallocate(SubExprs); - this->~ObjCMessageExpr(); - C.Deallocate((void*) this); + return 0; } bool ChooseExpr::isConditionTrue(ASTContext &C) const { @@ -2577,6 +2758,15 @@ Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } +// OffsetOfExpr +Stmt::child_iterator OffsetOfExpr::child_begin() { + return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1) + + NumComps); +} +Stmt::child_iterator OffsetOfExpr::child_end() { + return child_iterator(&*child_begin() + NumExprs); +} + // SizeOfAlignOfExpr Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { // If this is of a type and the type is a VLA type (and not a typedef), the @@ -2746,10 +2936,12 @@ Stmt::child_iterator ObjCProtocolExpr::child_end() { // ObjCMessageExpr Stmt::child_iterator ObjCMessageExpr::child_begin() { - return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; + if (getReceiverKind() == Instance) + return reinterpret_cast<Stmt **>(this + 1); + return getArgs(); } Stmt::child_iterator ObjCMessageExpr::child_end() { - return &SubExprs[0]+ARGS_START+getNumArgs(); + return getArgs() + getNumArgs(); } // Blocks diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index b9a4ee6..2e03beb 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -18,16 +18,25 @@ #include "clang/AST/TypeLoc.h" using namespace clang; + //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// +QualType CXXTypeidExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + // CXXTypeidExpr - has child iterators if the operand is an expression Stmt::child_iterator CXXTypeidExpr::child_begin() { - return isTypeOperand() ? child_iterator() : &Operand.Ex; + return isTypeOperand() ? child_iterator() + : reinterpret_cast<Stmt **>(&Operand); } Stmt::child_iterator CXXTypeidExpr::child_end() { - return isTypeOperand() ? child_iterator() : &Operand.Ex+1; + return isTypeOperand() ? child_iterator() + : reinterpret_cast<Stmt **>(&Operand) + 1; } // CXXBoolLiteralExpr @@ -180,6 +189,13 @@ bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin, return false; } +CXXRecordDecl *OverloadExpr::getNamingClass() const { + if (isa<UnresolvedLookupExpr>(this)) + return cast<UnresolvedLookupExpr>(this)->getNamingClass(); + else + return cast<UnresolvedMemberExpr>(this)->getNamingClass(); +} + Stmt::child_iterator UnresolvedLookupExpr::child_begin() { return child_iterator(); } @@ -443,9 +459,10 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, SourceLocation tyBeginLoc, Expr **Args, unsigned NumArgs, - SourceLocation rParenLoc) + SourceLocation rParenLoc, + bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc, - Cons, false, Args, NumArgs), + Cons, false, Args, NumArgs, ZeroInitialization), TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { } @@ -454,25 +471,25 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructorDecl *D, bool Elidable, Expr **Args, unsigned NumArgs, bool ZeroInitialization, - bool BaseInitialization) { + ConstructionKind ConstructKind) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, Elidable, Args, NumArgs, ZeroInitialization, - BaseInitialization); + ConstructKind); } CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, Expr **args, unsigned numargs, - bool ZeroInitialization, - bool BaseInitialization) + bool ZeroInitialization, + ConstructionKind ConstructKind) : Expr(SC, T, T->isDependentType(), (T->isDependentType() || CallExpr::hasAnyValueDependentArguments(args, numargs))), Constructor(D), Loc(Loc), Elidable(elidable), - ZeroInitialization(ZeroInitialization), - BaseInitialization(BaseInitialization), Args(0), NumArgs(numargs) + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), + Args(0), NumArgs(numargs) { if (NumArgs) { Args = new (C) Stmt*[NumArgs]; @@ -712,15 +729,15 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // If there was a nested name specifier, it names the naming class. // It can't be dependent: after all, we were actually able to do the // lookup. - const RecordType *RT; + CXXRecordDecl *Record = 0; if (getQualifier()) { Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); - RT = T->getAs<RecordType>(); - assert(RT && "qualifier in member expression does not name record"); - + Record = T->getAsCXXRecordDecl(); + assert(Record && "qualifier in member expression does not name record"); + } // Otherwise the naming class must have been the base class. - } else { + else { QualType BaseType = getBaseType().getNonReferenceType(); if (isArrow()) { const PointerType *PT = BaseType->getAs<PointerType>(); @@ -728,11 +745,11 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { BaseType = PT->getPointeeType(); } - RT = BaseType->getAs<RecordType>(); - assert(RT && "base of member expression does not name record"); + Record = BaseType->getAsCXXRecordDecl(); + assert(Record && "base of member expression does not name record"); } - return cast<CXXRecordDecl>(RT->getDecl()); + return Record; } Stmt::child_iterator UnresolvedMemberExpr::child_begin() { diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index eeeeb5c..c1a42d8 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -16,7 +16,9 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Expr.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" @@ -203,6 +205,13 @@ public: return Visit(E->getSubExpr()); } bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); } + + // Has side effects if any element does. + bool VisitInitListExpr(InitListExpr *E) { + for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) + if (Visit(E->getInit(i))) return true; + return false; + } }; } // end anonymous namespace @@ -221,7 +230,7 @@ public: APValue VisitStmt(Stmt *S) { return APValue(); } - + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } APValue VisitDeclRefExpr(DeclRefExpr *E); APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); } @@ -821,6 +830,7 @@ public: bool VisitCallExpr(CallExpr *E); bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitOffsetOfExpr(const OffsetOfExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); bool VisitConditionalOperator(const ConditionalOperator *E); @@ -961,7 +971,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) { return complex_type_class; else if (ArgTy->isFunctionType()) return function_type_class; - else if (ArgTy->isStructureType()) + else if (ArgTy->isStructureOrClassType()) return record_type_class; else if (ArgTy->isUnionType()) return union_type_class; @@ -1109,9 +1119,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { assert(E->getOpcode() == BinaryOperator::NE && "Invalid complex comparison."); return Success(((CR_r == APFloat::cmpGreaterThan || - CR_r == APFloat::cmpLessThan) && + CR_r == APFloat::cmpLessThan || + CR_r == APFloat::cmpUnordered) || (CR_i == APFloat::cmpGreaterThan || - CR_i == APFloat::cmpLessThan)), E); + CR_i == APFloat::cmpLessThan || + CR_i == APFloat::cmpUnordered)), E); } } else { if (E->getOpcode() == BinaryOperator::EQ) @@ -1154,7 +1166,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(CR == APFloat::cmpEqual, E); case BinaryOperator::NE: return Success(CR == APFloat::cmpGreaterThan - || CR == APFloat::cmpLessThan, E); + || CR == APFloat::cmpLessThan + || CR == APFloat::cmpUnordered, E); } } @@ -1191,8 +1204,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } if (E->getOpcode() == BinaryOperator::Sub) { - const QualType Type = E->getLHS()->getType(); - const QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); CharUnits ElementSize = CharUnits::One(); if (!ElementType->isVoidType() && !ElementType->isFunctionType()) @@ -1365,6 +1378,85 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E); } +bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { + CharUnits Result; + unsigned n = E->getNumComponents(); + OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E); + if (n == 0) + return false; + QualType CurrentType = E->getTypeSourceInfo()->getType(); + for (unsigned i = 0; i != n; ++i) { + OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: { + Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); + APSInt IdxResult; + if (!EvaluateInteger(Idx, IdxResult, Info)) + return false; + const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType); + if (!AT) + return false; + CurrentType = AT->getElementType(); + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); + Result += IdxResult.getSExtValue() * ElementSize; + break; + } + + case OffsetOfExpr::OffsetOfNode::Field: { + FieldDecl *MemberDecl = ON.getField(); + const RecordType *RT = CurrentType->getAs<RecordType>(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + unsigned i = 0; + // FIXME: It would be nice if we didn't have to loop here! + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == MemberDecl) + break; + } + assert(i < RL.getFieldCount() && "offsetof field in wrong type"); + Result += CharUnits::fromQuantity( + RL.getFieldOffset(i) / Info.Ctx.getCharWidth()); + CurrentType = MemberDecl->getType().getNonReferenceType(); + break; + } + + case OffsetOfExpr::OffsetOfNode::Identifier: + llvm_unreachable("dependent __builtin_offsetof"); + return false; + + case OffsetOfExpr::OffsetOfNode::Base: { + CXXBaseSpecifier *BaseSpec = ON.getBase(); + if (BaseSpec->isVirtual()) + return false; + + // Find the layout of the class whose base we are looking into. + const RecordType *RT = CurrentType->getAs<RecordType>(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + // Find the base class itself. + CurrentType = BaseSpec->getType(); + const RecordType *BaseRT = CurrentType->getAs<RecordType>(); + if (!BaseRT) + return false; + + // Add the offset to the base. + Result += CharUnits::fromQuantity( + RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())) + / Info.Ctx.getCharWidth()); + break; + } + } + } + return Success(Result.getQuantity(), E); +} + bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Special case unary operators that do not need their subexpression // evaluated. offsetof/sizeof/alignof are all special. @@ -1373,12 +1465,12 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // directly Evaluate it as an l-value. APValue LV; if (!EvaluateLValue(E->getSubExpr(), LV, Info)) - return false; + return false; if (LV.getLValueBase()) - return false; + return false; return Success(LV.getLValueOffset().getQuantity(), E); } - + if (E->getOpcode() == UnaryOperator::LNot) { // LNot's operand isn't necessarily an integer, so we handle it specially. bool bres; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 93edb42..3782985 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -15,15 +15,16 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" -#include <llvm/ADT/SmallSet.h> -#include <llvm/Support/MathExtras.h> +#include "llvm/Support/Format.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), UnfilledBitsInLastByte(0), - MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0), - NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Context) + : Context(Context), Size(0), Alignment(8), Packed(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0), IsUnion(false), + NonVirtualSize(0), NonVirtualAlignment(8), FirstNearlyEmptyVBase(0) { } /// IsNearlyEmpty - Indicates when a class has a vtable pointer, but /// no other data. @@ -31,29 +32,29 @@ 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)) + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); + if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0)) return true; return false; } void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { - const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = - Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo(); - + const ASTRecordLayout::PrimaryBaseInfo &BaseInfo = + Context.getASTRecordLayout(RD).getPrimaryBaseInfo(); + // If the record has a primary base class that is virtual, add it to the set // of primary bases. if (BaseInfo.isVirtual()) IndirectPrimaryBases.insert(BaseInfo.getBase()); - + // 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) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot layout class with dependent bases."); 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()) @@ -64,10 +65,10 @@ void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); @@ -80,12 +81,12 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { /*IsVirtual=*/true); return; } - + // Is this the first nearly empty virtual base? if (!FirstNearlyEmptyVBase) FirstNearlyEmptyVBase = Base; } - + SelectPrimaryVBase(Base); if (PrimaryBase.getBase()) return; @@ -97,11 +98,11 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. if (!RD->isDynamicClass()) return; - + // 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) { + e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot lay out class with dependent bases."); const CXXRecordDecl *Base = @@ -109,15 +110,15 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { 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 + // 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) { + e = RD->bases_end(); i != e; ++i) { // Ignore virtual bases. if (i->isVirtual()) continue; - + const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); @@ -139,44 +140,47 @@ void ASTRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // Otherwise, it is the first nearly empty virtual base that is not an // indirect primary virtual base class, if one exists. if (FirstNearlyEmptyVBase) { - PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, + PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(FirstNearlyEmptyVBase, /*IsVirtual=*/true); return; } - + // Otherwise there is no primary base class. assert(!PrimaryBase.getBase() && "Should not get here with a primary base!"); // Allocate the virtual table pointer at offset zero. assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); - + // Update the size. - Size += Ctx.Target.getPointerWidth(0); + Size += Context.Target.getPointerWidth(0); DataSize = Size; // Update the alignment. - UpdateAlignment(Ctx.Target.getPointerAlign(0)); + UpdateAlignment(Context.Target.getPointerAlign(0)); } void ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // First, determine the primary base class. DeterminePrimaryBase(RD); - + // If we have a primary base class, lay it out. if (const CXXRecordDecl *Base = PrimaryBase.getBase()) { if (PrimaryBase.isVirtual()) { // We have a virtual primary base, insert it as an indirect primary base. IndirectPrimaryBases.insert(Base); + assert(!VisitedVirtualBases.count(Base) && "vbase already visited!"); + VisitedVirtualBases.insert(Base); + LayoutVirtualBase(Base); } else LayoutNonVirtualBase(Base); } - + // Now lay out the non-virtual bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { // Ignore virtual bases. if (I->isVirtual()) @@ -197,83 +201,113 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) { // Layout the base. uint64_t Offset = LayoutBase(RD); - + // Add its base class offset. if (!Bases.insert(std::make_pair(RD, Offset)).second) assert(false && "Added same base offset more than once!"); } -void -ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, +void +ASTRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, const CXXRecordDecl *MostDerivedClass) { + // We already have the offset for the primary base of the most derived class. + if (RD != MostDerivedClass) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // If this is a primary virtual base and we haven't seen it before, add it. + if (PrimaryBase && Layout.getPrimaryBaseWasVirtual() && + !VBases.count(PrimaryBase)) + VBases.insert(std::make_pair(PrimaryBase, Offset)); + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + if (!BaseDecl->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + // Compute the offset of this base. + uint64_t BaseOffset; + + if (I->isVirtual()) { + // If we don't know this vbase yet, don't visit it. It will be visited + // later. + if (!VBases.count(BaseDecl)) { + continue; + } + + // Check if we've already visited this base. + if (!VisitedVirtualBases.insert(BaseDecl)) + continue; + + // We want the vbase offset from the class we're currently laying out. + BaseOffset = VBases[BaseDecl]; + } else if (RD == MostDerivedClass) { + // We want the base offset from the class we're currently laying out. + assert(Bases.count(BaseDecl) && "Did not find base!"); + BaseOffset = Bases[BaseDecl]; + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + } + + AddPrimaryVirtualBaseOffsets(BaseDecl, BaseOffset, MostDerivedClass); + } +} + +void +ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass) { const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseIsVirtual; - if (MostDerivedClass == RD) + if (MostDerivedClass == RD) { PrimaryBase = this->PrimaryBase.getBase(); - else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); + PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual(); + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); PrimaryBase = Layout.getPrimaryBase(); + PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); } for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); - + const CXXRecordDecl *Base = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); if (I->isVirtual()) { - bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); - - // We only want to visit this virtual base if it's either a primary base, - // or not an indirect primary base. - if (Base == PrimaryBase || !IndirectPrimaryBase) { - // Only lay things out once. - if (!VisitedVirtualBases.insert(Base)) - continue; - - if (Base == PrimaryBase) { - assert(IndirectPrimaryBase && - "Base is supposed to be an indirect primary base!"); - - // We only want to add a vbase offset if this primary base is not the - // primary base of the most derived class. - if (PrimaryBase != this->PrimaryBase.getBase() || - !this->PrimaryBase.isVirtual()) { - if (!VBases.insert(std::make_pair(Base, Offset)).second) - assert(false && "Added same vbase offset more than once!"); - } - } else { - // We actually do want to lay out this base. + if (PrimaryBase != Base || !PrimaryBaseIsVirtual) { + bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); + + // Only lay out the virtual base if it's not an indirect primary base. + if (!IndirectPrimaryBase) { + // Only visit virtual bases once. + if (!VisitedVirtualBases.insert(Base)) + continue; + LayoutVirtualBase(Base); } } } - + if (!Base->getNumVBases()) { // This base isn't interesting since it doesn't have any virtual bases. continue; } - // Compute the offset of this base. - uint64_t BaseOffset; - - if (I->isVirtual()) { - // We want the vbase offset from the class we're currently laying out. - assert(VBases.count(Base) && "Did not find virtual base!"); - BaseOffset = VBases[Base]; - } else if (RD == MostDerivedClass) { - // We want the base offset from the class we're currently laying out. - assert(Bases.count(Base) && "Did not find base!"); - BaseOffset = Bases[Base]; - } else { - const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } - - LayoutVirtualBases(Base, BaseOffset, MostDerivedClass); + LayoutVirtualBases(Base, MostDerivedClass); } } @@ -287,7 +321,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { } uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { - const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); // If we have an empty base class, try to place it at offset 0. if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0)) { @@ -298,17 +332,17 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { 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; } @@ -327,44 +361,44 @@ uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) { return Offset; } -bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, +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) { - + 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); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Check bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); 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(); + 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; } @@ -373,35 +407,35 @@ bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD, return true; } -bool ASTRecordLayoutBuilder::canPlaceFieldAtOffset(const FieldDecl *FD, +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); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.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); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { if (!canPlaceRecordAtOffset(RD, ElementOffset)) return false; - + ElementOffset += Info.getSize(); } } - + return true; } @@ -409,39 +443,39 @@ 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); + + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); // Update bases. for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), - E = RD->bases_end(); I != E; ++I) { + E = RD->bases_end(); I != E; ++I) { assert(!I->getType()->isDependentType() && "Cannot layout class with dependent bases."); 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(); + 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, +ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, uint64_t Offset) { QualType T = FD->getType(); @@ -451,19 +485,19 @@ ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const FieldDecl *FD, return; } } - - if (const ConstantArrayType *AT = Ctx.getAsConstantArrayType(T)) { - QualType ElemTy = Ctx.getBaseElementType(AT); + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.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); + const ASTRecordLayout &Info = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); uint64_t ElementOffset = Offset; for (uint64_t I = 0; I != NumElements; ++I) { @@ -495,20 +529,50 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { NonVirtualSize = Size; NonVirtualAlignment = Alignment; - // If this is a C++ class, lay out its virtual bases. - if (RD) - LayoutVirtualBases(RD, 0, RD); + // If this is a C++ class, lay out its virtual bases and add its primary + // virtual base offsets. + if (RD) { + LayoutVirtualBases(RD, RD); + + VisitedVirtualBases.clear(); + AddPrimaryVirtualBaseOffsets(RD, 0, RD); + } // Finally, round the size of the total struct up to the alignment of the // struct itself. FinishLayout(); + +#ifndef NDEBUG + if (RD) { + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } + } +#endif } // FIXME. Impl is no longer needed. void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) { if (ObjCInterfaceDecl *SD = D->getSuperClass()) { - const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD); + const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD); UpdateAlignment(SL.getAlignment()); @@ -528,7 +592,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D, UpdateAlignment(AA->getMaxAlignment()); // Layout each ivar sequentially. llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - Ctx.ShallowCollectObjCIvars(D, Ivars); + Context.ShallowCollectObjCIvars(D, Ivars); for (unsigned i = 0, e = Ivars.size(); i != e; ++i) LayoutField(Ivars[i]); @@ -541,20 +605,82 @@ 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) + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) LayoutField(*Field); } +void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, + uint64_t TypeSize) { + assert(Context.getLangOptions().CPlusPlus && + "Can only have wide bit-fields in C++!"); + + // Itanium C++ ABI 2.4: + // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // sizeof(T')*8 <= n. + + QualType IntegralPODTypes[] = { + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedLongTy, Context.UnsignedLongLongTy + }; + + QualType Type; + for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes); + I != E; ++I) { + uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]); + + if (Size > FieldSize) + break; + + Type = IntegralPODTypes[I]; + } + assert(!Type.isNull() && "Did not find a type!"); + + unsigned TypeAlign = Context.getTypeAlign(Type); + + // We're not going to use any of the unfilled bits in the last byte. + UnfilledBitsInLastByte = 0; + + uint64_t FieldOffset; + + if (IsUnion) { + DataSize = std::max(DataSize, FieldSize); + FieldOffset = 0; + } else { + // The bitfield is allocated starting at the next offset aligned appropriately + // for T', with length n bits. + FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign); + + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); + UnfilledBitsInLastByte = DataSize - NewSizeInBits; + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Update the size. + Size = std::max(Size, DataSize); + + // Remember max struct/class alignment. + UpdateAlignment(TypeAlign); +} + void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); - uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue(); - - std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; - - if (FieldPacked) + + if (FieldSize > TypeSize) { + LayoutWideBitField(FieldSize, TypeSize); + return; + } + + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); @@ -562,33 +688,32 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // 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. + + // 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 + + // Padding members don't affect overall alignment. if (!D->getIdentifier()) FieldAlign = 1; - + // Place this field at the current location. FieldOffsets.push_back(FieldOffset); - + // Update DataSize to include the last byte containing (part of) the bitfield. if (IsUnion) { // FIXME: I think FieldSize should be TypeSize here. DataSize = std::max(DataSize, FieldSize); } else { uint64_t NewSizeInBits = FieldOffset + FieldSize; - + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); UnfilledBitsInLastByte = DataSize - NewSizeInBits; } - + // Update the size. Size = std::max(Size, DataSize); - + // Remember max struct/class alignment. UpdateAlignment(FieldAlign); } @@ -606,21 +731,21 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { uint64_t FieldOffset = IsUnion ? 0 : DataSize; uint64_t FieldSize; unsigned FieldAlign; - + 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()); + const ArrayType* ATy = Context.getAsArrayType(D->getType()); + FieldAlign = Context.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); + FieldSize = Context.Target.getPointerWidth(AS); + FieldAlign = Context.Target.getPointerAlign(AS); } else { - std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType()); + std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; } @@ -636,20 +761,20 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { // 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); @@ -668,7 +793,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { void ASTRecordLayoutBuilder::FinishLayout() { // In C++, records cannot be of size 0. - if (Ctx.getLangOptions().CPlusPlus && Size == 0) + if (Context.getLangOptions().CPlusPlus && Size == 0) Size = 8; // Finally, round the size of the record up to the alignment of the // record itself. @@ -735,7 +860,7 @@ const CXXMethodDecl * ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { assert(RD->isDynamicClass() && "Class does not have any virtual methods!"); - // If a class isnt' polymorphic it doesn't have a key function. + // If a class isn't polymorphic it doesn't have a key function. if (!RD->isPolymorphic()) return 0; @@ -745,13 +870,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace()) return 0; - for (CXXRecordDecl::method_iterator I = RD->method_begin(), - E = RD->method_end(); I != E; ++I) { + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *MD = *I; - + if (!MD->isVirtual()) continue; - + if (MD->isPure()) continue; @@ -759,17 +884,134 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { // they don't have a body until they're defined. if (MD->isImplicit()) continue; - + if (MD->isInlineSpecified()) continue; if (MD->hasInlineBody()) continue; - + // We found it. return MD; } - + return 0; } +static void PrintOffset(llvm::raw_ostream &OS, + uint64_t Offset, unsigned IndentLevel) { + OS << llvm::format("%4d | ", Offset); + OS.indent(IndentLevel * 2); +} + +static void DumpCXXRecordLayout(llvm::raw_ostream &OS, + const CXXRecordDecl *RD, ASTContext &C, + uint64_t Offset, + unsigned IndentLevel, + const char* Description, + bool IncludeVirtualBases) { + const ASTRecordLayout &Info = C.getASTRecordLayout(RD); + + PrintOffset(OS, Offset, IndentLevel); + OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString(); + if (Description) + OS << ' ' << Description; + if (RD->isEmpty()) + OS << " (empty)"; + OS << '\n'; + + IndentLevel++; + + const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); + + // Vtable pointer. + if (RD->isDynamicClass() && !PrimaryBase) { + PrintOffset(OS, Offset, IndentLevel); + OS << '(' << RD << " vtable pointer)\n"; + } + // Dump (non-virtual) bases + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8; + + DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel, + Base == PrimaryBase ? "(primary base)" : "(base)", + /*IncludeVirtualBases=*/false); + } + + // Dump fields. + uint64_t FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *Field = *I; + uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8; + + if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { + if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, + Field->getNameAsCString(), + /*IncludeVirtualBases=*/true); + continue; + } + } + + PrintOffset(OS, FieldOffset, IndentLevel); + OS << Field->getType().getAsString() << ' ' << Field << '\n'; + } + + if (!IncludeVirtualBases) + return; + + // Dump virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + assert(I->isVirtual() && "Found non-virtual class!"); + const CXXRecordDecl *VBase = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8; + DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, + VBase == PrimaryBase ? + "(primary virtual base)" : "(virtual base)", + /*IncludeVirtualBases=*/false); + } + + OS << " sizeof=" << Info.getSize() / 8; + OS << ", dsize=" << Info.getDataSize() / 8; + OS << ", align=" << Info.getAlignment() / 8 << '\n'; + OS << " nvsize=" << Info.getNonVirtualSize() / 8; + OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; + OS << '\n'; +} + +void ASTContext::DumpRecordLayout(const RecordDecl *RD, + llvm::raw_ostream &OS) { + const ASTRecordLayout &Info = getASTRecordLayout(RD); + + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0, + /*IncludeVirtualBases=*/true); + + OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n"; + OS << "Record: "; + RD->dump(); + OS << "\nLayout: "; + OS << "<ASTRecordLayout\n"; + OS << " Size:" << Info.getSize() << "\n"; + OS << " DataSize:" << Info.getDataSize() << "\n"; + OS << " Alignment:" << Info.getAlignment() << "\n"; + OS << " FieldOffsets: ["; + for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) { + if (i) OS << ", "; + OS << Info.getFieldOffset(i); + } + OS << "]>\n"; +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index a4bce75..f277c29 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -26,7 +26,7 @@ namespace clang { class RecordDecl; class ASTRecordLayoutBuilder { - ASTContext &Ctx; + ASTContext &Context; /// Size - The current size of the record layout. uint64_t Size; @@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); void LayoutBitField(const FieldDecl *D); /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -112,8 +113,11 @@ class ASTRecordLayoutBuilder { /// LayoutNonVirtualBase - Lays out a single non-virtual base. void LayoutNonVirtualBase(const CXXRecordDecl *RD); + void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, + const CXXRecordDecl *MostDerivedClass); + /// LayoutVirtualBases - Lays out all the virtual bases. - void LayoutVirtualBases(const CXXRecordDecl *RD, uint64_t Offset, + void LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass); /// LayoutVirtualBase - Lays out a single virtual base. diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 9702382..67fd74c 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 "clang/Basic/TargetInfo.h" #include <cstdio> using namespace clang; @@ -240,6 +241,8 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, // asm string. std::string CurStringPiece; + bool HasVariants = !C.Target.hasNoAsmVariants(); + while (1) { // Done with the string? if (CurPtr == StrEnd) { @@ -251,9 +254,9 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; - case '{': CurStringPiece += "$("; continue; - case '|': CurStringPiece += "$|"; continue; - case '}': CurStringPiece += "$)"; continue; + case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; + case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; + case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: @@ -389,26 +392,53 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, RParenLoc = RPL; } - -ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, - SourceLocation rparenloc, - ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, - Stmt *atCatchList) -: Stmt(ObjCAtCatchStmtClass) { - ExceptionDecl = catchVarDecl; - SubExprs[BODY] = atCatchStmt; - SubExprs[NEXT_CATCH] = NULL; - // FIXME: O(N^2) in number of catch blocks. - if (atCatchList) { - ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList); - - while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) - AtCatchList = NextCatch; - - AtCatchList->SubExprs[NEXT_CATCH] = this; - } - AtCatchLoc = atCatchLoc; - RParenLoc = rparenloc; +ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt) + : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), + NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) +{ + Stmt **Stmts = getStmts(); + Stmts[0] = atTryStmt; + for (unsigned I = 0; I != NumCatchStmts; ++I) + Stmts[I + 1] = CatchStmts[I]; + + if (HasFinally) + Stmts[NumCatchStmts + 1] = atFinallyStmt; +} + +ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, + SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, + unsigned NumCatchStmts, + Stmt *atFinallyStmt) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>()); + return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, + atFinallyStmt); +} + +ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>()); + return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); +} + +SourceRange ObjCAtTryStmt::getSourceRange() const { + SourceLocation EndLoc; + if (HasFinally) + EndLoc = getFinallyStmt()->getLocEnd(); + else if (NumCatchStmts) + EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd(); + else + EndLoc = getTryBody()->getLocEnd(); + + return SourceRange(AtTryLoc, EndLoc); } CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, @@ -627,19 +657,18 @@ Stmt::child_iterator AsmStmt::child_end() { } // ObjCAtCatchStmt -Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } -Stmt::child_iterator ObjCAtCatchStmt::child_end() { - return &SubExprs[0]+END_EXPR; -} +Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; } +Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; } // ObjCAtFinallyStmt Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } // ObjCAtTryStmt -Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } -Stmt::child_iterator ObjCAtTryStmt::child_end() { - return &SubStmts[0]+END_EXPR; +Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); } + +Stmt::child_iterator ObjCAtTryStmt::child_end() { + return getStmts() + 1 + NumCatchStmts + HasFinally; } // ObjCAtThrowStmt diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index ba6218b..ca62ed1 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -143,6 +143,7 @@ namespace { void DumpCXXTemporary(CXXTemporary *Temporary); // ObjC + void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node); void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); void VisitObjCMessageExpr(ObjCMessageExpr* Node); void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); @@ -219,7 +220,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // nodes are where they need to be. if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { OS << "\"typedef " << localType->getUnderlyingType().getAsString() - << " " << localType->getNameAsString() << "\""; + << ' ' << localType << '"'; } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { OS << "\""; // Emit storage class for vardecls. @@ -299,9 +300,35 @@ void StmtDumper::VisitExpr(Expr *Node) { DumpExpr(Node); } +static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { + if (Node->getBasePath().empty()) + return; + + OS << " ("; + bool First = true; + for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(), + E = Node->getBasePath().end(); I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + if (!First) + OS << " -> "; + + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isVirtual()) + OS << "virtual "; + OS << RD->getName(); + First = false; + } + + OS << ')'; +} + void StmtDumper::VisitCastExpr(CastExpr *Node) { DumpExpr(Node); - OS << " <" << Node->getCastKindName() << ">"; + OS << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { @@ -328,15 +355,14 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { case Decl::ObjCClass: OS << "ObjCClass"; break; } - OS << "='" << Node->getDecl()->getNameAsString() - << "' " << (void*)Node->getDecl(); + OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl(); } void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { DumpExpr(Node); OS << " ("; if (!Node->requiresADL()) OS << "no "; - OS << "ADL) = '" << Node->getName().getAsString() << "'"; + OS << "ADL) = '" << Node->getName() << '\''; UnresolvedLookupExpr::decls_iterator I = Node->decls_begin(), E = Node->decls_end(); @@ -349,7 +375,7 @@ void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { DumpExpr(Node); OS << " " << Node->getDecl()->getDeclKindName() - << "Decl='" << Node->getDecl()->getNameAsString() + << "Decl='" << Node->getDecl() << "' " << (void*)Node->getDecl(); if (Node->isFreeIvar()) OS << " isFreeIvar"; @@ -408,7 +434,7 @@ void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { void StmtDumper::VisitMemberExpr(MemberExpr *Node) { DumpExpr(Node); OS << " " << (Node->isArrow() ? "->" : ".") - << Node->getMemberDecl()->getNameAsString() << " " + << Node->getMemberDecl() << ' ' << (void*)Node->getMemberDecl(); } void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { @@ -452,7 +478,9 @@ void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { DumpExpr(Node); OS << " " << Node->getCastName() << "<" << Node->getTypeAsWritten().getAsString() << ">" - << " <" << Node->getCastKindName() << ">"; + << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; } void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { @@ -506,8 +534,33 @@ void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { DumpExpr(Node); OS << " selector=" << Node->getSelector().getAsString(); - if (IdentifierInfo *clsName = Node->getClassName()) - OS << " class=" << clsName->getNameStart(); + switch (Node->getReceiverKind()) { + case ObjCMessageExpr::Instance: + break; + + case ObjCMessageExpr::Class: + OS << " class="; + DumpType(Node->getClassReceiver()); + break; + + case ObjCMessageExpr::SuperInstance: + OS << " super (instance)"; + break; + + case ObjCMessageExpr::SuperClass: + OS << " super (class)"; + break; + } +} + +void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) { + DumpStmt(Node); + if (VarDecl *CatchParam = Node->getCatchParamDecl()) { + OS << " catch parm = "; + DumpDeclarator(CatchParam); + } else { + OS << " catch all"; + } } void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { @@ -525,14 +578,13 @@ void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { DumpExpr(Node); - OS << " " << Node->getProtocol()->getNameAsString(); + OS << ' ' << Node->getProtocol(); } void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { DumpExpr(Node); - OS << " Kind=PropertyRef Property=\"" - << Node->getProperty()->getNameAsString() << "\""; + OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"'; } void StmtDumper::VisitObjCImplicitSetterGetterRefExpr( diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index da43878..52f627d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/Format.h" +#include "clang/AST/Expr.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -388,11 +389,8 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { OS << "\n"; } - for (ObjCAtCatchStmt *catchStmt = - static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts()); - catchStmt; - catchStmt = - static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) { + for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I); Indent() << "@catch("; if (catchStmt->getCatchParamDecl()) { if (Decl *DS = catchStmt->getCatchParamDecl()) @@ -474,7 +472,7 @@ void StmtPrinter::VisitExpr(Expr *Node) { void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), @@ -509,7 +507,7 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { @@ -527,7 +525,7 @@ void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( OS << "."; } if (Node->getGetterMethod()) - OS << Node->getGetterMethod()->getNameAsString(); + OS << Node->getGetterMethod(); } @@ -695,7 +693,7 @@ bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { } else { MemberExpr *ME = cast<MemberExpr>(E); bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); - OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getNameAsString(); + OS << (IsFirst ? "" : ".") << ME->getMemberDecl(); return false; } } @@ -706,6 +704,39 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { OS << ")"; } +void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { + OS << "__builtin_offsetof("; + OS << Node->getTypeSourceInfo()->getType().getAsString() << ", "; + bool PrintedSomething = false; + for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) { + OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i); + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) { + // Array node + OS << "["; + PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex())); + OS << "]"; + PrintedSomething = true; + continue; + } + + // Skip implicit base indirections. + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base) + continue; + + // Field or identifier node. + IdentifierInfo *Id = ON.getFieldName(); + if (!Id) + continue; + + if (PrintedSomething) + OS << "."; + else + PrintedSomething = true; + OS << Id->getName(); + } + OS << ")"; +} + void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); if (Node->isArgumentType()) @@ -746,7 +777,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getMemberDecl()->getNameAsString(); + OS << Node->getMemberDecl(); if (Node->hasExplicitTemplateArgumentList()) OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -1242,14 +1273,26 @@ void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { } void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')'; + OS << "@protocol(" << Node->getProtocol() << ')'; } void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { OS << "["; - Expr *receiver = Mess->getReceiver(); - if (receiver) PrintExpr(receiver); - else OS << Mess->getClassName()->getName(); + switch (Mess->getReceiverKind()) { + case ObjCMessageExpr::Instance: + PrintExpr(Mess->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + OS << Mess->getClassReceiver().getAsString(Policy); + break; + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + OS << "Super"; + break; + } + OS << ' '; Selector selector = Mess->getSelector(); if (selector.isUnarySelector()) { @@ -1304,7 +1347,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { } void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { - OS << Node->getDecl()->getNameAsString(); + OS << Node->getDecl(); } //===----------------------------------------------------------------------===// // Stmt method implementations diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 3a19ec2..d45bb2f 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -261,6 +261,34 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { ID.AddInteger(S->getOpcode()); } +void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { + VisitType(S->getTypeSourceInfo()->getType()); + unsigned n = S->getNumComponents(); + for (unsigned i = 0; i < n; ++i) { + const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i); + ID.AddInteger(ON.getKind()); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + // Expressions handled below. + break; + + case OffsetOfExpr::OffsetOfNode::Field: + VisitDecl(ON.getField()); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + ID.AddPointer(ON.getFieldName()); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // These nodes are implicit, and therefore don't need profiling. + break; + } + } + + VisitExpr(S); +} + void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { VisitExpr(S); ID.AddBoolean(S->isSizeOf()); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index b56c0ceb..14722f7 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -15,9 +15,11 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using namespace llvm; TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) @@ -45,13 +47,13 @@ void TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, bool SuppressNNS) const { if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) - OS << Template->getNameAsString(); + OS << Template; else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (!SuppressNNS) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; - OS << QTN->getDecl()->getNameAsString(); + OS << QTN->getDecl(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { if (!SuppressNNS && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); @@ -64,6 +66,18 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, } } +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + TemplateName N) { + std::string NameStr; + raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + N.print(OS, PrintingPolicy(LO)); + OS.flush(); + return DB << NameStr; +} + void TemplateName::dump() const { LangOptions LO; // FIXME! LO.CPlusPlus = true; diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 27a277d..05e7fdc 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -225,6 +225,11 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isStructureOrClassType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return false; +} bool Type::isVoidPointerType() const { if (const PointerType *PT = getAs<PointerType>()) return PT->getPointeeType()->isVoidType(); @@ -410,6 +415,16 @@ const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { return 0; } +CXXRecordDecl *Type::getAsCXXRecordDecl() const { + if (const RecordType *RT = getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + else if (const InjectedClassNameType *Injected + = getAs<InjectedClassNameType>()) + return Injected->getDecl(); + + return 0; +} + bool Type::isIntegerType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && @@ -999,12 +1014,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { TemplateSpecializationType:: TemplateSpecializationType(ASTContext &Context, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), - Context(Context), + ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation), Template(T), NumArgs(NumArgs) { assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && @@ -1039,9 +1055,11 @@ TemplateSpecializationType::getArg(unsigned Idx) const { void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, ASTContext &Context) { + ID.AddBoolean(IsCurrentInstantiation); T.Profile(ID); for (unsigned Idx = 0; Idx < NumArgs; ++Idx) Args[Idx].Profile(ID, Context); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 340e373..915d7af 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -29,7 +29,7 @@ namespace { public: explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } - + void Print(QualType T, std::string &S); void AppendScope(DeclContext *DC, std::string &S); void PrintTag(TagDecl *T, std::string &S); @@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization( void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, std::string &S) { - PrintTemplateSpecialization(T->getUnderlyingTST(), S); + PrintTemplateSpecialization(T->getInjectedTST(), S); } void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, |