diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-05-04 16:12:48 +0000 |
commit | 8aaf5818a64e9f7687798852af5945b053c68a54 (patch) | |
tree | d6a70c3518b8dea8be7062438d7e8676820ed17f /lib | |
parent | 71438373cd57f0d5d8c93bb5cf690844a0fbc9d0 (diff) | |
download | FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.zip FreeBSD-src-8aaf5818a64e9f7687798852af5945b053c68a54.tar.gz |
Update clang to r103004.
Diffstat (limited to 'lib')
186 files changed, 18136 insertions, 9130 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, diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index f94f6b3..7f71e0a 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -46,7 +46,7 @@ public: AddStmtChoice(Kind kind) : k(kind) {} bool alwaysAdd() const { return (unsigned)k & 0x1; } - bool asLValue() const { return k >= AlwaysAddAsLValue; } + bool asLValue() const { return k >= AsLValueNotAlwaysAdd; } private: Kind k; @@ -108,16 +108,16 @@ private: CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBlockExpr(BlockExpr* E, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); + CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); + CFGBlock *VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); CFGBlock *VisitCaseStmt(CaseStmt *C); CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc); CFGBlock *VisitCompoundStmt(CompoundStmt *C); - CFGBlock *VisitConditionalOperator(ConditionalOperator *C, - AddStmtChoice asc); + CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); - CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -127,6 +127,7 @@ private: CFGBlock *VisitIfStmt(IfStmt *I); CFGBlock *VisitIndirectGotoStmt(IndirectGotoStmt *I); CFGBlock *VisitLabelStmt(LabelStmt *L); + CFGBlock *VisitMemberExpr(MemberExpr *M, AddStmtChoice asc); CFGBlock *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); CFGBlock *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); CFGBlock *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); @@ -337,6 +338,10 @@ bool CFGBuilder::FinishBlock(CFGBlock* B) { /// DeclStmts (which may contain nested control-flow). CFGBlock* CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { tryAgain: + if (!S) { + badCFG = true; + return 0; + } switch (S->getStmtClass()) { default: return VisitStmt(S, asc); @@ -374,6 +379,9 @@ tryAgain: case Stmt::CXXCatchStmtClass: return VisitCXXCatchStmt(cast<CXXCatchStmt>(S)); + case Stmt::CXXMemberCallExprClass: + return VisitCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), asc); + case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); @@ -404,6 +412,9 @@ tryAgain: case Stmt::LabelStmtClass: return VisitLabelStmt(cast<LabelStmt>(S)); + case Stmt::MemberExprClass: + return VisitMemberExpr(cast<MemberExpr>(S), asc); + case Stmt::ObjCAtCatchStmtClass: return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S)); @@ -491,8 +502,16 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, Succ = ConfluenceBlock; Block = NULL; CFGBlock* RHSBlock = addStmt(B->getRHS()); - if (!FinishBlock(RHSBlock)) - return 0; + + if (RHSBlock) { + if (!FinishBlock(RHSBlock)) + return 0; + } + else { + // Create an empty block for cases where the RHS doesn't require + // any explicit statements in the CFG. + RHSBlock = createBlock(); + } // See if this is a known constant. TryResult KnownVal = TryEvaluateBool(B->getLHS()); @@ -627,15 +646,18 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + Succ = ConfluenceBlock; Block = NULL; - CFGBlock* LHSBlock = addStmt(C->getLHS()); + CFGBlock* LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Succ = ConfluenceBlock; Block = NULL; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -676,6 +698,9 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, if (!FinishBlock(ConfluenceBlock)) return 0; + asc = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + // Create a block for the LHS expression if there is an LHS expression. A // GCC extension allows LHS to be NULL, causing the condition to be the // value that is returned instead. @@ -684,7 +709,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, Block = NULL; CFGBlock* LHSBlock = NULL; if (C->getLHS()) { - LHSBlock = addStmt(C->getLHS()); + LHSBlock = addStmt(C->getLHS(), asc); if (!FinishBlock(LHSBlock)) return 0; Block = NULL; @@ -692,7 +717,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(ConditionalOperator *C, // Create the block for the RHS expression. Succ = ConfluenceBlock; - CFGBlock* RHSBlock = addStmt(C->getRHS()); + CFGBlock* RHSBlock = addStmt(C->getRHS(), asc); if (!FinishBlock(RHSBlock)) return 0; @@ -1074,6 +1099,16 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { } } +CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { + if (asc.alwaysAdd()) { + autoCreateBlock(); + AppendStmt(Block, M, asc); + } + return Visit(M->getBase(), + M->isArrow() ? AddStmtChoice::NotAlwaysAdd + : AddStmtChoice::AsLValueNotAlwaysAdd); +} + CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { // Objective-C fast enumeration 'for' statements: // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC @@ -1694,6 +1729,15 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } +CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, + AddStmtChoice asc) { + AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + : AddStmtChoice::AlwaysAdd; + autoCreateBlock(); + AppendStmt(Block, C, AddStmtChoice(K)); + return VisitChildren(C); +} + CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { // Lazily create the indirect-goto dispatch block if there isn't one already. CFGBlock* IBlock = cfg->getIndirectGotoBlock(); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 2b7fcd0..1870195 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -11,24 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/PartialDiagnostic.h" - -#include "clang/Lex/LexDiagnostic.h" -#include "clang/Parse/ParseDiagnostic.h" #include "clang/AST/ASTDiagnostic.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Analysis/AnalysisDiagnostic.h" -#include "clang/Driver/DriverDiagnostic.h" - +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" + #include <vector> #include <map> #include <cstring> @@ -223,9 +223,12 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ErrorOccurred = false; FatalErrorOccurred = false; - NumDiagnostics = 0; - + ErrorLimit = 0; + TemplateBacktraceLimit = 0; + + NumWarnings = 0; NumErrors = 0; + NumErrorsSuppressed = 0; CustomDiagInfo = 0; CurDiagID = ~0U; LastDiagLevel = Ignored; @@ -286,11 +289,18 @@ bool Diagnostic::isBuiltinNote(unsigned DiagID) { } /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic -/// ID is for an extension of some sort. +/// ID is for an extension of some sort. This also returns EnabledByDefault, +/// which is set to indicate whether the diagnostic is ignored by default (in +/// which case -pedantic enables it) or treated as a warning/error by default. /// -bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID) { - return DiagID < diag::DIAG_UPPER_LIMIT && - getBuiltinDiagClass(DiagID) == CLASS_EXTENSION; +bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID, + bool &EnabledByDefault) { + if (DiagID >= diag::DIAG_UPPER_LIMIT || + getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) + return false; + + EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE; + return true; } @@ -529,8 +539,14 @@ bool Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. - if (FatalErrorOccurred) + if (FatalErrorOccurred) { + if (DiagLevel >= Diagnostic::Error) { + ++NumErrors; + ++NumErrorsSuppressed; + } + return false; + } // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. @@ -551,11 +567,20 @@ bool Diagnostic::ProcessDiag() { if (DiagLevel >= Diagnostic::Error) { ErrorOccurred = true; ++NumErrors; + + // If we've emitted a lot of errors, emit a fatal error after it to stop a + // flood of bogus errors. + if (ErrorLimit && NumErrors >= ErrorLimit && + DiagLevel == Diagnostic::Error) + SetDelayedDiagnostic(diag::fatal_too_many_errors); } // Finally, report it. Client->HandleDiagnostic(DiagLevel, Info); - if (Client->IncludeInDiagnosticCounts()) ++NumDiagnostics; + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == Diagnostic::Warning) + ++NumWarnings; + } CurDiagID = ~0U; @@ -1026,8 +1051,15 @@ static void WriteSourceLocation(llvm::raw_ostream &OS, Location = SM->getInstantiationLoc(Location); std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location); - - WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName()); + + const FileEntry *FE = SM->getFileEntryForID(Decomposed.first); + if (FE) + WriteString(OS, FE->getName()); + else { + // Fallback to using the buffer name when there is no entry. + WriteString(OS, SM->getBuffer(Decomposed.first)->getBufferIdentifier()); + } + WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second)); WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second)); } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 3da19ca..ed0de8c 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -78,9 +78,9 @@ namespace { /// identifiers because they are language keywords. This causes the lexer to /// automatically map matching identifiers to specialized token codes. /// -/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be +/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be /// enabled in the specified langauge, set to 1 if it is an extension -/// in the specified language, and set to 2 if disabled in the +/// in the specified language, and set to 0 if disabled in the /// specified language. static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, @@ -90,7 +90,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; - else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1; + else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 27cb9be..3ecab1d 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -60,6 +60,8 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { } const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, + const SourceManager &SM, + SourceLocation Loc, bool *Invalid) const { if (Invalid) *Invalid = false; @@ -94,22 +96,67 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, Entry->getName(), ErrorStr); else - Diag.Report(diag::err_cannot_open_file) + Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file) << Entry->getName() << ErrorStr; Buffer.setInt(true); + + // FIXME: This conditionalization is horrible, but we see spurious failures + // in the test suite due to this warning and no one has had time to hunt it + // down. So for now, we just don't emit this diagnostic on Win32, and hope + // nothing bad happens. + // + // PR6812. +#if !defined(LLVM_ON_WIN32) } else if (FileInfo.st_size != Entry->getSize() || FileInfo.st_mtime != Entry->getModificationTime()) { - // Check that the file's size, modification time, and inode are - // the same as in the file entry (which may have come from a - // stat cache). + // Check that the file's size and modification time are the same + // as in the file entry (which may have come from a stat cache). if (Diag.isDiagnosticInFlight()) - Diag.SetDelayedDiagnostic(diag::err_file_modified, + Diag.SetDelayedDiagnostic(diag::err_file_modified, Entry->getName()); - else - Diag.Report(diag::err_file_modified) << Entry->getName(); + else + Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified) + << Entry->getName(); Buffer.setInt(true); +#endif + } + + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + if (!Buffer.getInt()) { + llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); + const char *BOM = 0; + if (BufStr.startswith("\xFE\xBB\xBF")) + BOM = "UTF-8"; + else if (BufStr.startswith("\xFE\xFF")) + BOM = "UTF-16 (BE)"; + else if (BufStr.startswith("\xFF\xFE")) + BOM = "UTF-16 (LE)"; + else if (BufStr.startswith(llvm::StringRef("\x00\x00\xFE\xFF", 4))) + BOM = "UTF-32 (BE)"; + else if (BufStr.startswith(llvm::StringRef("\xFF\xFE\x00\x00", 4))) + BOM = "UTF-32 (LE)"; + else if (BufStr.startswith("\x2B\x2F\x76")) + BOM = "UTF-7"; + else if (BufStr.startswith("\xF7\x64\x4C")) + BOM = "UTF-1"; + else if (BufStr.startswith("\xDD\x73\x66\x73")) + BOM = "UTF-EBCDIC"; + else if (BufStr.startswith("\x0E\xFE\xFF")) + BOM = "SDSU"; + else if (BufStr.startswith("\xFB\xEE\x28")) + BOM = "BOCU-1"; + else if (BufStr.startswith("\x84\x31\x95\x33")) + BOM = "BOCU-1"; + + if (BOM) { + Diag.Report(FullSourceLoc(Loc, SM), diag::err_unsupported_bom) + << BOM << Entry->getName(); + Buffer.setInt(1); + } } } @@ -470,7 +517,7 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); assert(IR && "getOrCreateContentCache() cannot return NULL"); - return IR->getBuffer(Diag, Invalid); + return IR->getBuffer(Diag, *this, SourceLocation(), Invalid); } bool SourceManager::overrideFileContents(const FileEntry *SourceFile, @@ -717,8 +764,8 @@ const char *SourceManager::getCharacterData(SourceLocation SL, // Note that calling 'getBuffer()' may lazily page in a source file. bool CharDataInvalid = false; const llvm::MemoryBuffer *Buffer - = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag, - &CharDataInvalid); + = getSLocEntry(LocInfo.first).getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); @@ -757,14 +804,16 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc, return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); } -static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag, - ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, - bool &Invalid); -static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI, - llvm::BumpPtrAllocator &Alloc, bool &Invalid) { +static DISABLE_INLINE void +ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid); +static void ComputeLineNumbers(Diagnostic &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid) { // Note that calling 'getBuffer()' may lazily page in the file. - const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid); + const MemoryBuffer *Buffer = FI->getBuffer(Diag, SM, SourceLocation(), + &Invalid); if (Invalid) return; @@ -825,7 +874,7 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (Invalid) *Invalid = MyInvalid; if (MyInvalid) @@ -991,8 +1040,11 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. - const char *Filename = - C->Entry ? C->Entry->getName() : C->getBuffer(Diag)->getBufferIdentifier(); + const char *Filename; + if (C->Entry) + Filename = C->Entry->getName(); + else + Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second); unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second); SourceLocation IncludeLoc = FI.getIncludeLoc(); @@ -1050,7 +1102,7 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { bool MyInvalid = false; - ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid); + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); if (MyInvalid) return SourceLocation(); } @@ -1082,15 +1134,15 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, return SourceLocation(); if (Line > Content->NumLines) { - unsigned Size = Content->getBuffer(Diag)->getBufferSize(); + unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); if (Size > 0) --Size; return getLocForStartOfFile(FirstFID).getFileLocWithOffset(Size); } unsigned FilePos = Content->SourceLineCache[Line - 1]; - const char *Buf = Content->getBuffer(Diag)->getBufferStart() + FilePos; - unsigned BufLength = Content->getBuffer(Diag)->getBufferEnd() - Buf; + const char *Buf = Content->getBuffer(Diag, *this)->getBufferStart() + FilePos; + unsigned BufLength = Content->getBuffer(Diag, *this)->getBufferEnd() - Buf; unsigned i = 0; // Check that the given column is valid. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 136089f..4c0c59a 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -20,10 +20,10 @@ using namespace clang; // TargetInfo Constructor. TargetInfo::TargetInfo(const std::string &T) : Triple(T) { - // Set defaults. Defaults are set for a 32-bit RISC platform, - // like PPC or SPARC. - // These should be overridden by concrete targets as needed. + // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or + // SPARC. These should be overridden by concrete targets as needed. TLSSupported = true; + NoAsmVariants = false; PointerWidth = PointerAlign = 32; IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; @@ -45,6 +45,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char32Type = UnsignedInt; Int64Type = SignedLongLong; SigAtomicType = SignedInt; + UseBitFieldTypeAlignment = true; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; @@ -142,9 +143,10 @@ bool TargetInfo::isTypeSigned(IntType T) const { /// Apply changes to the target information with respect to certain /// language options which change the target configuration. void TargetInfo::setForcedLangOptions(LangOptions &Opts) { - if (Opts.ShortWChar) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + if (Opts.ShortWChar) WCharType = UnsignedShort; - } } //===----------------------------------------------------------------------===// diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1797804..3d5048c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -219,6 +219,8 @@ protected: Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); } public: LinuxTargetInfo(const std::string& triple) @@ -1221,6 +1223,27 @@ public: Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; +} // end anonymous namespace + +namespace { +// x86-32 Haiku target +class HaikuX86_32TargetInfo : public X86_32TargetInfo { +public: + HaikuX86_32TargetInfo(const std::string& triple) + : X86_32TargetInfo(triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__HAIKU__"); } }; } // end anonymous namespace @@ -1373,6 +1396,10 @@ public: SizeType = UnsignedInt; PtrDiffType = SignedInt; + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + // FIXME: Should we just treat this as a feature? IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { @@ -1397,6 +1424,10 @@ public: DoubleAlign = LongLongAlign = LongDoubleAlign = 32; SizeType = UnsignedLong; + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + if (IsThumb) { DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" @@ -2351,6 +2382,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MinGWX86_32TargetInfo(T); case llvm::Triple::Win32: return new VisualStudioWindowsX86_32TargetInfo(T); + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(T); default: return new X86_32TargetInfo(T); } diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index 810d0fb..e7275ca 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -31,13 +31,22 @@ using namespace clang; static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { - const Expr* Receiver = ME->getReceiver(); - - if (!Receiver) - return NULL; + QualType T; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + T = ME->getInstanceReceiver()->getType(); + break; + + case ObjCMessageExpr::SuperInstance: + T = ME->getSuperType(); + break; + + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + return 0; + } - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs<ObjCObjectPointerType>()) + if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>()) return PT->getInterfaceType(); return NULL; @@ -509,11 +518,21 @@ public: void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - - const IdentifierInfo *ClsName = ME->getClassName(); - if (!ClsName) + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: return; - + } + Selector S = ME->getSelector(); if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) return; @@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, llvm::raw_svector_ostream os(buf); os << "The '" << S.getAsString() << "' message should be sent to instances " - "of class '" << ClsName->getName() + "of class '" << Class->getName() << "' and not the class directly"; RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 7c53991..34470af 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, const VarDecl *VD = VR->getDecl(); // BasicStore does not model arrays and structs. - if (VD->getType()->isArrayType() || VD->getType()->isStructureType()) + if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType()) return store; if (VD->hasGlobalStorage()) { diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 4475872..3bcc03f 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (D) { GetRawInt = false; - os << D->getNameAsString(); + os << D; } } diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 06cee5b..776e12b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) { } const Stmt* -clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){ - const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); - if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) - return ME->getReceiver(); - return NULL; -} - -const Stmt* clang::bugreporter::GetDenomExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs<PreStmt>()->getStmt(); if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S)) @@ -144,7 +136,7 @@ public: if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << "Variable '" << VR->getDecl()->getNameAsString() << "' "; + os << "Variable '" << VR->getDecl() << "' "; } else return NULL; @@ -206,7 +198,7 @@ public: return NULL; if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << '\'' << VR->getDecl()->getNameAsString() << '\''; + os << '\'' << VR->getDecl() << '\''; } else return NULL; @@ -402,7 +394,7 @@ public: const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); if (!ME) return 0; - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); if (!Receiver) return 0; const GRState *state = N->getState(); diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 3c4a27c..d26ee1d 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -603,12 +603,33 @@ public: Selector S = ME->getSelector(); - if (Expr* Receiver = ME->getReceiver()) { - const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver); - return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + const ObjCInterfaceDecl* OD = 0; + bool IsInstanceMessage = false; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + OD = getReceiverDecl(ME->getInstanceReceiver()); + IsInstanceMessage = true; + break; + + case ObjCMessageExpr::SuperInstance: + IsInstanceMessage = true; + OD = ME->getSuperType()->getAs<ObjCObjectPointerType>() + ->getInterfaceDecl(); + break; + + case ObjCMessageExpr::Class: + OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + break; + + case ObjCMessageExpr::SuperClass: + OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + break; } - return M[ObjCSummaryKey(ME->getClassName(), S)]; + if (IsInstanceMessage) + return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; + + return M[ObjCSummaryKey(OD->getIdentifier(), S)]; } RetainSummary*& operator[](ObjCSummaryKey K) { @@ -836,7 +857,7 @@ public: RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME, const ObjCInterfaceDecl* ID) { - return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(), + return getInstanceMethodSummary(ME->getSelector(), 0, ID, ME->getMethodDecl(), ME->getType()); } @@ -851,8 +872,21 @@ public: QualType RetTy); RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) { - return getClassMethodSummary(ME->getSelector(), ME->getClassName(), - ME->getClassInfo().Decl, + ObjCInterfaceDecl *Class = 0; + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Class: + case ObjCMessageExpr::SuperClass: + Class = ME->getReceiverInterface(); + break; + + case ObjCMessageExpr::Instance: + case ObjCMessageExpr::SuperInstance: + break; + } + + return getClassMethodSummary(ME->getSelector(), + Class? Class->getIdentifier() : 0, + Class, ME->getMethodDecl(), ME->getType()); } @@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME, // We need the type-information of the tracked receiver object // Retrieve it from the state. - const Expr *Receiver = ME->getReceiver(); + const Expr *Receiver = ME->getInstanceReceiver(); const ObjCInterfaceDecl* ID = 0; // FIXME: Is this really working as expected? There are cases where // we just use the 'ID' from the message expression. - SVal receiverV = state->getSValAsScalarOrLoc(Receiver); + SVal receiverV; + + if (const Expr *Receiver = ME->getInstanceReceiver()) { + receiverV = state->getSValAsScalarOrLoc(Receiver); - // FIXME: Eventually replace the use of state->get<RefBindings> with - // a generic API for reasoning about the Objective-C types of symbolic - // objects. - if (SymbolRef Sym = receiverV.getAsLocSymbol()) - if (const RefVal *T = state->get<RefBindings>(Sym)) - if (const ObjCObjectPointerType* PT = + // FIXME: Eventually replace the use of state->get<RefBindings> with + // a generic API for reasoning about the Objective-C types of symbolic + // objects. + if (SymbolRef Sym = receiverV.getAsLocSymbol()) + if (const RefVal *T = state->get<RefBindings>(Sym)) + if (const ObjCObjectPointerType* PT = T->getType()->getAs<ObjCObjectPointerType>()) - ID = PT->getInterfaceDecl(); + ID = PT->getInterfaceDecl(); - // FIXME: this is a hack. This may or may not be the actual method - // that is called. - if (!ID) { - if (const ObjCObjectPointerType *PT = - Receiver->getType()->getAs<ObjCObjectPointerType>()) - ID = PT->getInterfaceDecl(); + // FIXME: this is a hack. This may or may not be the actual method + // that is called. + if (!ID) { + if (const ObjCObjectPointerType *PT = + Receiver->getType()->getAs<ObjCObjectPointerType>()) + ID = PT->getInterfaceDecl(); + } + } else { + // FIXME: Hack for 'super'. + ID = ME->getReceiverInterface(); } - + // FIXME: The receiver could be a reference to a class, meaning that // we should use the class method. RetainSummary *Summ = getInstanceMethodSummary(ME, ID); // Special-case: are we sending a mesage to "self"? // This is a hack. When we have full-IP this should be removed. - if (isa<ObjCMethodDecl>(LC->getDecl())) { + if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) { if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) { // Get the region associated with 'self'. if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) { @@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, // Get the name of the callee (if it is available). SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee()); if (const FunctionDecl* FD = X.getAsFunctionDecl()) - os << "Call to function '" << FD->getNameAsString() <<'\''; + os << "Call to function '" << FD << '\''; else os << "function call"; } @@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N, } } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { - if (const Expr *receiver = ME->getReceiver()) + if (const Expr *receiver = ME->getInstanceReceiver()) if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) { // The symbol we are tracking is the receiver. AEffects.push_back(Summ->getReceiverEffect()); @@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this // is a call to a class method whose type we can resolve. In such // cases, promote the return type to XXX* (where XXX is the class). - const ObjCInterfaceDecl *D = ME->getClassInfo().Decl; + const ObjCInterfaceDecl *D = ME->getReceiverInterface(); return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D)); } @@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, RetEffect RE = Summ.getRetEffect(); if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { - assert(Receiver); - SVal V = state->getSValAsScalarOrLoc(Receiver); bool found = false; - if (SymbolRef Sym = V.getAsLocSymbol()) - if (state->get<RefBindings>(Sym)) { - found = true; - RE = Summaries.getObjAllocRetEffect(); - } - + if (Receiver) { + SVal V = state->getSValAsScalarOrLoc(Receiver); + if (SymbolRef Sym = V.getAsLocSymbol()) + if (state->get<RefBindings>(Sym)) { + found = true; + RE = Summaries.getObjAllocRetEffect(); + } + } // FIXME: Otherwise, this is a send-to-super instance message. if (!found) RE = RetEffect::MakeNoRet(); } @@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, ExplodedNode* Pred, const GRState *state) { RetainSummary *Summ = - ME->getReceiver() + ME->isInstanceMessage() ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext()) : Summaries.getClassMethodSummary(ME); assert(Summ && "RetainSummary is null"); - EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL, + EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL, ME->arg_begin(), ME->arg_end(), Pred, state); } diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index dec375e..82e93a4 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -31,6 +31,7 @@ add_clang_library(clangChecker FlatStore.cpp GRBlockCounter.cpp GRCoreEngine.cpp + GRCXXExprEngine.cpp GRExprEngine.cpp GRExprEngineExperimentalChecks.cpp GRState.cpp diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index dd1856c9..c619d75 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, os << "Passed-by-value struct argument contains uninitialized data"; if (F.FieldChain.size() == 1) - os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() - << "')"; + os << " (e.g., field: '" << F.FieldChain[0] << "')"; else { os << " (e.g., via the field chain: '"; bool first = true; @@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, first = false; else os << '.'; - os << (*DI)->getNameAsString(); + os << *DI; } os << "')"; } @@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, const GRState *state = C.getState(); - if (const Expr *receiver = ME->getReceiver()) + // FIXME: Handle 'super'? + if (const Expr *receiver = ME->getInstanceReceiver()) if (state->getSVal(receiver).isUndef()) { if (ExplodedNode *N = C.GenerateSink()) { if (!BT_msg_undef) @@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, << ME->getType().getAsString() << "' that will be garbage"; EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); - const Expr *receiver = ME->getReceiver(); - report->addRange(receiver->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, - receiver); + if (const Expr *receiver = ME->getInstanceReceiver()) { + report->addRange(receiver->getSourceRange()); + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + receiver); + } C.EmitReport(report); } @@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); - if (CanRetTy->isStructureType()) { + if (CanRetTy->isStructureOrClassType()) { // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead // have the "use of undefined value" be smarter about where the // undefined value came from. diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp index 2c16f89..eeaed97 100644 --- a/lib/Checker/CastToStructChecker.cpp +++ b/lib/Checker/CastToStructChecker.cpp @@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C, QualType OrigPointeeTy = OrigPTy->getPointeeType(); QualType ToPointeeTy = ToPTy->getPointeeType(); - if (!ToPointeeTy->isStructureType()) + if (!ToPointeeTy->isStructureOrClassType()) return; // We allow cast from void*. diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp index d9606f1..c23be87 100644 --- a/lib/Checker/CheckObjCDealloc.cpp +++ b/lib/Checker/CheckObjCDealloc.cpp @@ -27,10 +27,14 @@ using namespace clang; static bool scan_dealloc(Stmt* S, Selector Dealloc) { if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) - if (ME->getSelector() == Dealloc) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) - return isa<ObjCSuperExpr>(Receiver); + if (ME->getSelector() == Dealloc) { + switch (ME->getReceiverKind()) { + case ObjCMessageExpr::Instance: return false; + case ObjCMessageExpr::SuperInstance: return true; + case ObjCMessageExpr::Class: break; + case ObjCMessageExpr::SuperClass: break; + } + } // Recurse to children. @@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID, // [mMyIvar release] if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) if (ME->getSelector() == Release) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver)) if (E->getDecl() == ID) return true; // [self setMyIvar:nil]; if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S)) - if (ME->getReceiver()) - if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts()) + if (ME->getInstanceReceiver()) + if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts()) if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver)) if (E->getDecl()->getIdentifier() == SelfII) if (ME->getMethodDecl() == PD->getSetterMethodDecl() && @@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "Objective-C class '" << D->getNameAsString() - << "' lacks a 'dealloc' instance method"; + os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method"; BR.EmitBasicReport(name, os.str(), D->getLocStart()); return; @@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, std::string buf; llvm::raw_string_ostream os(buf); - os << "The 'dealloc' instance method in Objective-C class '" - << D->getNameAsString() + os << "The 'dealloc' instance method in Objective-C class '" << D << "' does not send a 'dealloc' message to its super class" " (missing [super dealloc])"; @@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "missing ivar release (leak)" : "missing ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was retained by a synthesized property but " "wasn't released in 'dealloc'"; } else { @@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D, ? "extra ivar release (use-after-release)" : "extra ivar release (Hybrid MM, non-GC)"; - os << "The '" << ID->getNameAsString() + os << "The '" << ID << "' instance variable was not retained by a synthesized property " "but was released in 'dealloc'"; } diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp index 8c43a45..76a0923 100644 --- a/lib/Checker/CheckObjCInstMethSignature.cpp +++ b/lib/Checker/CheckObjCInstMethSignature.cpp @@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived, llvm::raw_string_ostream os(sbuf); os << "The Objective-C class '" - << MethDerived->getClassInterface()->getNameAsString() + << MethDerived->getClassInterface() << "', which is derived from class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "', defines the instance method '" << MethDerived->getSelector().getAsString() << "' whose return type is '" << ResDerived.getAsString() << "'. A method with the same name (same selector) is also defined in " "class '" - << MethAncestor->getClassInterface()->getNameAsString() + << MethAncestor->getClassInterface() << "' and has a return type of '" << ResAncestor.getAsString() << "'. These two types are incompatible, and may result in undefined " diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index efbce61..74e12b1 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "'" << FD->getNameAsString() << "' is a poor random number generator"; + os1 << '\'' << FD << "' is a poor random number generator"; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "Function '" << FD->getNameAsString() + os2 << "Function '" << FD << "' is obsolete because it implements a poor random number generator." << " Use 'arc4random' instead"; @@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { // Issue a warning. llvm::SmallString<256> buf1; llvm::raw_svector_ostream os1(buf1); - os1 << "Return value is not checked in call to '" << FD->getNameAsString() - << "'"; + os1 << "Return value is not checked in call to '" << FD << '\''; llvm::SmallString<256> buf2; llvm::raw_svector_ostream os2(buf2); - os2 << "The return value from the call to '" << FD->getNameAsString() - << "' is not checked. If an error occurs in '" - << FD->getNameAsString() + os2 << "The return value from the call to '" << FD + << "' is not checked. If an error occurs in '" << FD << "', the following code may execute with unexpected privileges"; SourceRange R = CE->getCallee()->getSourceRange(); diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index be1a677..addfc21 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { return ValMgr.makeIntVal(C->getValue(), C->getType()); } + case Stmt::CXXBoolLiteralExprClass: { + const SVal *X = ExprBindings.lookup(E); + if (X) + return *X; + else + return ValMgr.makeIntVal(cast<CXXBoolLiteralExpr>(E)); + } case Stmt::IntegerLiteralClass: { // In C++, this expression may have been bound to a temporary object. SVal const *X = ExprBindings.lookup(E); diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp new file mode 100644 index 0000000..00ac995 --- /dev/null +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -0,0 +1,246 @@ +//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ expression evaluation engine. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; + +void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE, + const FunctionProtoType *FnType, + ExplodedNode *Pred, ExplodedNodeSet &Dst) { + llvm::SmallVector<CallExprWLItem, 20> WorkList; + WorkList.reserve(AE - AI); + WorkList.push_back(CallExprWLItem(AI, Pred)); + + while (!WorkList.empty()) { + CallExprWLItem Item = WorkList.back(); + WorkList.pop_back(); + + if (Item.I == AE) { + Dst.insert(Item.N); + continue; + } + + ExplodedNodeSet Tmp; + const unsigned ParamIdx = Item.I - AI; + bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType() + : false; + if (VisitAsLvalue) + VisitLValue(*Item.I, Item.N, Tmp); + else + Visit(*Item.I, Item.N, Tmp); + + ++(Item.I); + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) + WorkList.push_back(CallExprWLItem(Item.I, *NI)); + } +} + +const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, + const StackFrameContext *SFC) { + Type *T = D->getParent()->getTypeForDecl(); + QualType PT = getContext().getPointerType(QualType(T,0)); + return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); +} + +void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + ExplodedNodeSet Tmp; + Visit(Ex, Pred, Tmp); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Bind the temporary object to the value of the expression. Then bind + // the expression to the location of the object. + SVal V = state->getSVal(Ex); + + const MemRegion *R = + ValMgr.getRegionManager().getCXXObjectRegion(Ex, + Pred->getLocationContext()); + + state = state->bindLoc(loc::MemRegionVal(R), V); + MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); + } +} + +void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), Dest, Pred, Dst); + return; + } + + const CXXConstructorDecl *CD = E->getConstructor(); + assert(CD); + + if (!CD->isThisDeclarationADefinition()) + // FIXME: invalidate the object. + return; + + + // Evaluate other arguments. + ExplodedNodeSet ArgsEvaluated; + const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); + EvalArguments(const_cast<CXXConstructExpr*>(E)->arg_begin(), + const_cast<CXXConstructExpr*>(E)->arg_end(), + FnType, Pred, ArgsEvaluated); + // The callee stack frame context used to create the 'this' parameter region. + const StackFrameContext *SFC = AMgr.getStackFrame(CD, + Pred->getLocationContext(), + E, Builder->getBlock(), Builder->getIndex()); + + const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); + + CallEnter Loc(E, CD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), + NE = ArgsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region. + state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the method type. + const FunctionProtoType *FnType = + MCE->getCallee()->getType()->getAs<FunctionProtoType>(); + assert(FnType && "Method type not available"); + + // Evaluate explicit arguments with a worklist. + ExplodedNodeSet ArgsEvaluated; + EvalArguments(const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(), + const_cast<CXXMemberCallExpr*>(MCE)->arg_end(), + FnType, Pred, ArgsEvaluated); + + // Evaluate the implicit object argument. + ExplodedNodeSet AllArgsEvaluated; + const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); + if (!ME) + return; + Expr *ObjArgExpr = ME->getBase(); + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + if (ME->isArrow()) + Visit(ObjArgExpr, *I, AllArgsEvaluated); + else + VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); + } + + const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); + assert(MD && "not a CXXMethodDecl?"); + + if (!MD->isThisDeclarationADefinition()) + // FIXME: conservative method call evaluation. + return; + + const StackFrameContext *SFC = AMgr.getStackFrame(MD, + Pred->getLocationContext(), + MCE, + Builder->getBlock(), + Builder->getIndex()); + const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); + CallEnter Loc(MCE, MD, Pred->getLocationContext()); + for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), + E = AllArgsEvaluated.end(); I != E; ++I) { + // Set up 'this' region. + const GRState *state = GetState(*I); + state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); + ExplodedNode *N = Builder->generateNode(Loc, state, *I); + if (N) + Dst.Add(N); + } +} + +void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + if (CNE->isArray()) { + // FIXME: allocating an array has not been handled. + return; + } + + unsigned Count = Builder->getCurrentBlockCount(); + DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, + CNE->getType(), Count); + const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion(); + + QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); + + const ElementRegion *EleReg = + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + + // Evaluate constructor arguments. + const FunctionProtoType *FnType = NULL; + const CXXConstructorDecl *CD = CNE->getConstructor(); + if (CD) + FnType = CD->getType()->getAs<FunctionProtoType>(); + ExplodedNodeSet ArgsEvaluated; + EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), + FnType, Pred, ArgsEvaluated); + + // Initialize the object region and bind the 'new' expression. + for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), + E = ArgsEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + if (ObjTy->isRecordType()) { + Store store = state->getStore(); + StoreManager::InvalidatedSymbols IS; + store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS); + state = state->makeWithStore(store); + } else { + if (CNE->hasInitializer()) { + SVal V = state->getSVal(*CNE->constructor_arg_begin()); + state = state->bindLoc(loc::MemRegionVal(EleReg), V); + } else { + // Explicitly set to undefined, because currently we retrieve symbolic + // value from symbolic region. + state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal()); + } + } + state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); + MakeNode(Dst, CNE, *I, state); + } +} + +void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Should do more checking. + ExplodedNodeSet ArgEvaluated; + Visit(CDE->getArgument(), Pred, ArgEvaluated); + for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(), + E = ArgEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + MakeNode(Dst, CDE, *I, state); + } +} + +void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + // Get the this object region from StoreManager. + const MemRegion *R = + ValMgr.getRegionManager().getCXXThisRegion( + getContext().getCanonicalType(TE->getType()), + Pred->getLocationContext()); + + const GRState *state = GetState(Pred); + SVal V = state->getSVal(loc::MemRegionVal(R)); + MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); +} diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index e4ef6b0..23a87d3 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { Eng.WList->Enqueue(Succ, B, Idx+1); } +ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S, + ExplodedNode* Pred, const GRState* St, + ProgramPoint::Kind K) { + const GRState* PredState = GetState(Pred); + + // If the state hasn't changed, don't generate a new node. + if (!BuildSinks && St == PredState && Auditor == 0) { + Dst.Add(Pred); + return NULL; + } + + ExplodedNode* N = generateNode(S, St, Pred, K); + + if (N) { + if (BuildSinks) + N->markAsSink(); + else { + if (Auditor && Auditor->Audit(N, Mgr)) + N->markAsSink(); + + Dst.Add(N); + } + } + + return N; +} + static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K, const LocationContext *LC, const void *tag){ switch (K) { diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index bab8922..67090b8 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXNamedCastExprClass: - case Stmt::CXXStaticCastExprClass: - case Stmt::CXXDynamicCastExprClass: - case Stmt::CXXReinterpretCastExprClass: - case Stmt::CXXConstCastExprClass: - case Stmt::CXXFunctionalCastExprClass: - case Stmt::CXXTypeidExprClass: - case Stmt::CXXBoolLiteralExprClass: - case Stmt::CXXNullPtrLiteralExprClass: - case Stmt::CXXThrowExprClass: - case Stmt::CXXDefaultArgExprClass: - case Stmt::CXXZeroInitValueExprClass: - case Stmt::CXXNewExprClass: - case Stmt::CXXDeleteExprClass: - case Stmt::CXXPseudoDestructorExprClass: - case Stmt::UnresolvedLookupExprClass: - case Stmt::UnaryTypeTraitExprClass: - case Stmt::DependentScopeDeclRefExprClass: - case Stmt::CXXConstructExprClass: + case Stmt::CXXBindReferenceExprClass: case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXConstructExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::CXXDependentScopeMemberExprClass: case Stmt::CXXExprWithTemporariesClass: + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTemporaryObjectExprClass: + case Stmt::CXXThrowExprClass: + case Stmt::CXXTryStmtClass: + case Stmt::CXXTypeidExprClass: case Stmt::CXXUnresolvedConstructExprClass: - case Stmt::CXXDependentScopeMemberExprClass: + case Stmt::CXXZeroInitValueExprClass: + case Stmt::DependentScopeDeclRefExprClass: + case Stmt::UnaryTypeTraitExprClass: + case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: - case Stmt::CXXCatchStmtClass: - case Stmt::CXXTryStmtClass: { + { SaveAndRestore<bool> OldSink(Builder->BuildSinks); Builder->BuildSinks = true; MakeNode(Dst, S, Pred, GetState(Pred)); break; } - default: - // Cases we intentionally have "default" handle: - // AddrLabelExpr, IntegerLiteral, CharacterLiteral + // Cases that should never be evaluated simply because they shouldn't + // appear in the CFG. + case Stmt::BreakStmtClass: + case Stmt::CaseStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::DoStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::LabelStmtClass: + case Stmt::NoStmtClass: + case Stmt::NullStmtClass: + case Stmt::SwitchCaseClass: + llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + break; + // Cases not handled yet; but will handle some day. + case Stmt::DesignatedInitExprClass: + case Stmt::ExtVectorElementExprClass: + case Stmt::GNUNullExprClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::ImplicitValueInitExprClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAtTryStmtClass: + case Stmt::ObjCEncodeExprClass: + case Stmt::ObjCImplicitSetterGetterRefExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::ObjCProtocolExprClass: + case Stmt::ObjCSelectorExprClass: + case Stmt::ObjCStringLiteralClass: + case Stmt::ObjCSuperExprClass: + case Stmt::ParenListExprClass: + case Stmt::PredefinedExprClass: + case Stmt::ShuffleVectorExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::VAArgExprClass: + // Fall through. + + // Cases we intentionally don't evaluate, since they don't need + // to be explicitly evaluated. + case Stmt::AddrLabelExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::CXXBoolLiteralExprClass: + case Stmt::FloatingLiteralClass: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; @@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; } + case Stmt::CXXNewExprClass: { + CXXNewExpr *NE = cast<CXXNewExpr>(S); + VisitCXXNewExpr(NE, Pred, Dst); + break; + } + + case Stmt::CXXDeleteExprClass: { + CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S); + VisitCXXDeleteExpr(CDE, Pred, Dst); + break; + } // FIXME: ChooseExpr is really a constant. We need to fix // the CFG do not model them as explicit control-flow. @@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::ImplicitCastExprClass: - case Stmt::CStyleCastExprClass: { + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::CXXDynamicCastExprClass: + case Stmt::CXXReinterpretCastExprClass: + case Stmt::CXXConstCastExprClass: + case Stmt::CXXFunctionalCastExprClass: { CastExpr* C = cast<CastExpr>(S); VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; @@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); break; + case Stmt::OffsetOfExprClass: + VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst); + break; + case Stmt::SizeOfAlignOfExprClass: VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst); break; @@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; // In C++, binding an rvalue to a reference requires to create an object. + case Stmt::CXXBoolLiteralExprClass: case Stmt::IntegerLiteralClass: CreateCXXTemporaryObject(Ex, Pred, Dst); return; @@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, } } -//===----------------------------------------------------------------------===// -// Transfer function: Function calls. -//===----------------------------------------------------------------------===// - -namespace { -class CallExprWLItem { -public: - CallExpr::arg_iterator I; - ExplodedNode *N; - - CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n) - : I(i), N(n) {} -}; -} // end anonymous namespace - void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, @@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, continue; } - const GRState* state = Pred->getState(); + const GRState* state = GetState(Pred); SVal V = state->getSVal(Ex); if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) { // First assume that the condition is true. @@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // But first evaluate the receiver (if any). ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (Expr *Receiver = ME->getReceiver()) { + if (Expr *Receiver = ME->getInstanceReceiver()) { ExplodedNodeSet Tmp; Visit(Receiver, Pred, Tmp); @@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, SaveAndRestore<bool> OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); - if (const Expr *Receiver = ME->getReceiver()) { - const GRState *state = Pred->getState(); + if (const Expr *Receiver = ME->getInstanceReceiver()) { + const GRState *state = GetState(Pred); // Bifurcate the state into nil and non-nil ones. DefinedOrUnknownSVal receiverVal = @@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Dispatch to plug-in transfer function. EvalObjCMessageExpr(DstEval, ME, Pred, notNilState); } - else { - IdentifierInfo* ClsName = ME->getClassName(); + else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) { + IdentifierInfo* ClsName = Iface->getIdentifier(); Selector S = ME->getSelector(); // Check for special instance methods. @@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, QualType T = getContext().getCanonicalType(E->getType()); unsigned NumInitElements = E->getNumInits(); - if (T->isArrayType() || T->isStructureType() || - T->isUnionType() || T->isVectorType()) { - + if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList(); // Handle base case where the initializer has no elements. @@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } +void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { + Expr::EvalResult Res; + if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); + assert(OOE->getType()->isIntegerType()); + assert(IV.isSigned() == OOE->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X)); + return; + } + // FIXME: Handle the case where __builtin_offsetof is not a constant. + Dst.Add(Pred); +} void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { @@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, case UnaryOperator::OffsetOf: { Expr::EvalResult Res; if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); - assert(U->getType()->isIntegerType()); - assert(IV.isSigned() == U->getType()->isSignedIntegerType()); - SVal X = ValMgr.makeIntVal(IV); - MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); - return; - } + const APSInt &IV = Res.Val.getInt(); + assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); + assert(U->getType()->isIntegerType()); + assert(IV.isSigned() == U->getType()->isSignedIntegerType()); + SVal X = ValMgr.makeIntVal(IV); + MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); + return; + } // FIXME: Handle the case where __builtin_offsetof is not a constant. Dst.Add(Pred); return; } - + case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH. case UnaryOperator::Extension: { @@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } - -void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, - ExplodedNodeSet & Dst) { - // Get the this object region from StoreManager. - const MemRegion *R = - ValMgr.getRegionManager().getCXXThisRegion( - getContext().getCanonicalType(TE->getType()), - Pred->getLocationContext()); - - const GRState *state = GetState(Pred); - SVal V = state->getSVal(loc::MemRegionVal(R)); - MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); -} - void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); @@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, ExplodedNodeSet Tmp3; for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) { - SVal LeftV = (*I1)->getState()->getSVal(LHS); + SVal LeftV = GetState(*I1)->getSVal(LHS); ExplodedNodeSet Tmp2; Visit(RHS, *I1, Tmp2); @@ -3147,184 +3190,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, CheckerVisit(B, Dst, Tmp3, false); } -void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - ExplodedNodeSet Tmp; - Visit(Ex, Pred, Tmp); - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { - const GRState *state = GetState(*I); - - // Bind the temporary object to the value of the expression. Then bind - // the expression to the location of the object. - SVal V = state->getSVal(Ex); - - const MemRegion *R = - ValMgr.getRegionManager().getCXXObjectRegion(Ex, - Pred->getLocationContext()); - - state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R))); - } -} - -void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (E->isElidable()) { - VisitAggExpr(E->getArg(0), Dest, Pred, Dst); - return; - } - - const CXXConstructorDecl *CD = E->getConstructor(); - assert(CD); - - if (!CD->isThisDeclarationADefinition()) - // FIXME: invalidate the object. - return; - - - // Evaluate other arguments. - CXXConstructExpr::arg_iterator AB - = const_cast<CXXConstructExpr*>(E)->arg_begin(); - CXXConstructExpr::arg_iterator AE - = const_cast<CXXConstructExpr*>(E)->arg_end(); - llvm::SmallVector<CallExprWLItem, 20> WorkList; - WorkList.reserve(AE - AB); - WorkList.push_back(CallExprWLItem(AB, Pred)); - ExplodedNodeSet ArgsEvaluated; - const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>(); - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - // Evaluate the argument. - ExplodedNodeSet Tmp; - const unsigned ParamIdx = Item.I - AB; - - bool VisitAsLvalue = false; - - if (ParamIdx < Proto->getNumArgs()) - VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType(); - - if (VisitAsLvalue) - VisitLValue(*Item.I, Item.N, Tmp); - else - Visit(*Item.I, Item.N, Tmp); - - ++(Item.I); - - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } - // The callee stack frame context used to create the 'this' parameter region. - const StackFrameContext *SFC = AMgr.getStackFrame(CD, - Pred->getLocationContext(), - E, Builder->getBlock(), Builder->getIndex()); - - const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); - - CallEnter Loc(E, CD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), - NE = ArgsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); - // Setup 'this' region. - state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) - Dst.Add(N); - } -} - -void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(), - AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end(); - llvm::SmallVector<CallExprWLItem, 20> WorkList; - WorkList.reserve(AE - AB); - WorkList.push_back(CallExprWLItem(AB, Pred)); - ExplodedNodeSet ArgsEvaluated; - - while (!WorkList.empty()) { - CallExprWLItem Item = WorkList.back(); - WorkList.pop_back(); - - if (Item.I == AE) { - ArgsEvaluated.insert(Item.N); - continue; - } - - ExplodedNodeSet Tmp; - const unsigned ParamIdx = Item.I - AB; - bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType(); - - if (VisitAsLvalue) - VisitLValue(*Item.I, Item.N, Tmp); - else - Visit(*Item.I, Item.N, Tmp); - - ++(Item.I); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI) - WorkList.push_back(CallExprWLItem(Item.I, *NI)); - } - // Evaluate the implicit object argument. - ExplodedNodeSet AllArgsEvaluated; - const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); - if (!ME) - return; - Expr *ObjArgExpr = ME->getBase(); - for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(), - E = ArgsEvaluated.end(); I != E; ++I) { - if (ME->isArrow()) - Visit(ObjArgExpr, *I, AllArgsEvaluated); - else - VisitLValue(ObjArgExpr, *I, AllArgsEvaluated); - } - - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - - if (!MD->isThisDeclarationADefinition()) - // FIXME: conservative method call evaluation. - return; - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, MD, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), - E = AllArgsEvaluated.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr)); - ExplodedNode *N = Builder->generateNode(Loc, state, *I); - if (N) - Dst.Add(N); - } -} - -const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, - const StackFrameContext *SFC) { - Type *T = D->getParent()->getTypeForDecl(); - QualType PT = getContext().getPointerType(QualType(T,0)); - return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); -} - //===----------------------------------------------------------------------===// // Checker registration/lookup. //===----------------------------------------------------------------------===// diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9f12ab6..9a664c7 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const { } void FieldRegion::dumpToStream(llvm::raw_ostream& os) const { - os << superRegion << "->" << getDecl()->getNameAsString(); + os << superRegion << "->" << getDecl(); } void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}'; + os << "ivar{" << superRegion << ',' << getDecl() << '}'; } void StringRegion::dumpToStream(llvm::raw_ostream& os) const { @@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const { } void VarRegion::dumpToStream(llvm::raw_ostream& os) const { - os << cast<VarDecl>(D)->getNameAsString(); + os << cast<VarDecl>(D); } void RegionRawOffset::dump() const { @@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { const MemRegion *MemRegion::getBaseRegion() const { const MemRegion *R = this; while (true) { - if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { - R = ER->getSuperRegion(); - continue; - } - if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) { - R = FR->getSuperRegion(); - continue; + switch (R->getKind()) { + case MemRegion::ElementRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + R = cast<SubRegion>(R)->getSuperRegion(); + continue; + default: + break; } break; } diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp index 29bac9c..48f03a3 100644 --- a/lib/Checker/NSAutoreleasePoolChecker.cpp +++ b/lib/Checker/NSAutoreleasePoolChecker.cpp @@ -56,7 +56,7 @@ void NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME) { - const Expr *receiver = ME->getReceiver(); + const Expr *receiver = ME->getInstanceReceiver(); if (!receiver) return; diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp index 9130bfa..e30d54c 100644 --- a/lib/Checker/NSErrorChecker.cpp +++ b/lib/Checker/NSErrorChecker.cpp @@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param, else os << "documented in CoreFoundation/CFError.h the parameter '"; - os << Param->getNameAsString() << "' may be null."; + os << Param << "' may be null."; BugReport *report = new BugReport(*this, os.str(), *I); // FIXME: Notable symbols are now part of the report. We should diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp index 04d897a..0e47621 100644 --- a/lib/Checker/ObjCUnusedIVarsChecker.cpp +++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp @@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D, if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); - os << "Instance variable '" << I->first->getNameAsString() - << "' in class '" << ID->getNameAsString() + os << "Instance variable '" << I->first << "' in class '" << ID << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index c97da33..1e15d43 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -14,22 +14,22 @@ // parameters are created lazily. // //===----------------------------------------------------------------------===// -#include "clang/Checker/PathSensitive/MemRegion.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/PathSensitive/GRStateTrait.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Support/Optional.h" -#include "clang/Basic/TargetInfo.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" - -#include "llvm/ADT/ImmutableMap.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" +#include "clang/Checker/PathSensitive/MemRegion.h" #include "llvm/ADT/ImmutableList.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/raw_ostream.h" using namespace clang; +using llvm::Optional; //===----------------------------------------------------------------------===// // Representation of binding keys. @@ -346,8 +346,6 @@ public: // Part of public interface to class. Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store, const TypedRegion *R); - const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); - //===------------------------------------------------------------------===// // State pruning. //===------------------------------------------------------------------===// @@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { return true; } -const ElementRegion * -RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) { - ASTContext &Ctx = getContext(); - SVal idx = ValMgr.makeZeroArrayIndex(); - assert(!T.isNull()); - return MRMgr.getElementRegion(T, idx, R, Ctx); -} - SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { assert(!isa<UnknownVal>(L) && "location unknown"); assert(!isa<UndefinedVal>(L) && "location undefined"); @@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } #endif - if (RTy->isStructureType() || RTy->isClassType()) + if (RTy->isStructureOrClassType()) return RetrieveStruct(store, R); // FIXME: Handle unions. @@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(getContext()); - assert(T->isStructureType() || T->isClassType()); + assert(T->isStructureOrClassType()); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) - if (TR->getValueType(getContext())->isStructureType()) + if (TR->getValueType(getContext())->isStructureOrClassType()) return BindStruct(store, TR, V); // Special case: the current region represents a cast and it and the super @@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR, if (T->isArrayType()) return BindArray(store, VR, InitVal); - if (T->isStructureType()) + if (T->isStructureOrClassType()) return BindStruct(store, VR, InitVal); return Bind(store, ValMgr.makeLoc(VR), InitVal); @@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store, V = ValMgr.makeNull(); else if (T->isIntegerType()) V = ValMgr.makeZeroVal(T); - else if (T->isStructureType() || T->isArrayType()) { + else if (T->isStructureOrClassType() || T->isArrayType()) { // Set the default value to a zero constant when it is a structure // or array. The type doesn't really matter. V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy); @@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, SVal Idx = ValMgr.makeArrayIndex(i); const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); - if (ElementTy->isStructureType()) + if (ElementTy->isStructureOrClassType()) store = BindStruct(store, ER, *VI); else store = Bind(store, ValMgr.makeLoc(ER), *VI); @@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, return store; QualType T = R->getValueType(getContext()); - assert(T->isStructureType()); + assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs<RecordType>(); RecordDecl* RD = RT->getDecl(); @@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, if (FTy->isArrayType()) store = BindArray(store, FR, *VI); - else if (FTy->isStructureType()) + else if (FTy->isStructureOrClassType()) store = BindStruct(store, FR, *VI); else store = Bind(store, ValMgr.makeLoc(FR), *VI); diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp index 4bfa2cd..d756be7 100644 --- a/lib/Checker/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const { } case nonloc::LazyCompoundValKind: { const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this); - os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion() + os << "lazyCompoundVal{" << const_cast<void *>(C.getStore()) + << ',' << C.getRegion() << '}'; break; } diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp index fb1d74a..dd38a43 100644 --- a/lib/Checker/SimpleSValuator.cpp +++ b/lib/Checker/SimpleSValuator.cpp @@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) { if (castTy->isUnionType()) return UnknownVal(); - assert(castTy->isIntegerType()); - unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); + if (castTy->isIntegerType()) { + unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy); - if (!isa<loc::ConcreteInt>(val)) - return ValMgr.makeLocAsInteger(val, BitWidth); + if (!isa<loc::ConcreteInt>(val)) + return ValMgr.makeLocAsInteger(val, BitWidth); - llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue(); - i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); - i.extOrTrunc(BitWidth); - return ValMgr.makeIntVal(i); + llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue(); + i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy)); + i.extOrTrunc(BitWidth); + return ValMgr.makeIntVal(i); + } + + // All other cases: return 'UnknownVal'. This includes casting pointers + // to floats, which is probably badness it itself, but this is a good + // intermediate solution until we do something better. + return UnknownVal(); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp index e524cb3..c12065b 100644 --- a/lib/Checker/Store.cpp +++ b/lib/Checker/Store.cpp @@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { return true; } +const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, + QualType T) { + SVal idx = ValMgr.makeZeroArrayIndex(); + assert(!T.isNull()); + return MRMgr.getElementRegion(T, idx, R, Ctx); +} + const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) { ASTContext& Ctx = StateMgr.getContext(); @@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) if (IsCompleteType(Ctx, PointeeTy)) { // Compute the size in **bytes**. CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy); - - // Is the offset a multiple of the size? If so, we can layer the - // ElementRegion (with elementType == PointeeTy) directly on top of - // the base region. - if (off % pointeeTySize == 0) { - newIndex = off / pointeeTySize; - newSuperR = baseR; + if (!pointeeTySize.isZero()) { + // Is the offset a multiple of the size? If so, we can layer the + // ElementRegion (with elementType == PointeeTy) directly on top of + // the base region. + if (off % pointeeTySize == 0) { + newIndex = off / pointeeTySize; + newSuperR = baseR; + } } } diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index d75e5d2..e9b8f09 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -13,23 +13,30 @@ //===----------------------------------------------------------------------===// #include "GRExprEngineInternalChecks.h" -#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" #include <fcntl.h> using namespace clang; +using llvm::Optional; namespace { class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> { enum SubChecks { OpenFn = 0, + PthreadOnceFn = 1, NumChecks }; BugType *BTypes[NumChecks]; public: + Optional<uint64_t> Val_O_CREAT; + +public: UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } static void *getTag() { static unsigned tag = 0; return &tag; } @@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) { // "open" (man 2 open) //===----------------------------------------------------------------------===// -static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { +static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT) { + // The definition of O_CREAT is platform specific. We need a better way + // of querying this information from the checking environment. + if (!UC.Val_O_CREAT.hasValue()) { + if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple) + UC.Val_O_CREAT = 0x0200; + else { + // FIXME: We need a more general way of getting the O_CREAT value. + // We could possibly grovel through the preprocessor state, but + // that would require passing the Preprocessor object to the GRExprEngine. + return; + } + } + LazyInitialize(BT, "Improper use of 'open'"); // Look at the 'oflags' argument for the O_CREAT flag. @@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } NonLoc oflags = cast<NonLoc>(V); NonLoc ocreateFlag = - cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT, + cast<NonLoc>(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(), oflagsEx->getType())); SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, oflags, ocreateFlag, @@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) { } //===----------------------------------------------------------------------===// +// pthread_once +//===----------------------------------------------------------------------===// + +static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &, + const CallExpr *CE, BugType *&BT) { + + // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. + // They can possibly be refactored. + + LazyInitialize(BT, "Improper use of 'pthread_once'"); + + if (CE->getNumArgs() < 1) + return; + + // Check if the first argument is stack allocated. If so, issue a warning + // because that's likely to be bad news. + const GRState *state = C.getState(); + const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); + if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) + return; + + ExplodedNode *N = C.GenerateSink(state); + if (!N) + return; + + llvm::SmallString<256> S; + llvm::raw_svector_ostream os(S); + os << "Call to 'pthread_once' uses"; + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) + os << " the local variable '" << VR->getDecl()->getName() << '\''; + else + os << " stack allocated memory"; + os << " for the \"control\" value. Using such transient memory for " + "the control value is potentially dangerous."; + if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) + os << " Perhaps you intended to declare the variable as 'static'?"; + + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); + report->addRange(CE->getArg(0)->getSourceRange()); + C.EmitReport(report); +} + +//===----------------------------------------------------------------------===// // Central dispatch function. //===----------------------------------------------------------------------===// -typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT); +typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC, + const CallExpr *CE, BugType *&BT); namespace { class SubCheck { SubChecker SC; + UnixAPIChecker *UC; BugType **BT; public: - SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} - SubCheck() : SC(NULL), BT(NULL) {} + SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc), + BT(&bt) {} + SubCheck() : SC(NULL), UC(NULL), BT(NULL) {} void run(CheckerContext &C, const CallExpr *CE) const { if (SC) - SC(C, CE, *BT); + SC(C, *UC, CE, *BT); } }; } // end anonymous namespace @@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { const SubCheck &SC = llvm::StringSwitch<SubCheck>(FI->getName()) - .Case("open", SubCheck(CheckOpen, BTypes[OpenFn])) + .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn])) + .Case("pthread_once", SubCheck(CheckPthreadOnce, this, + BTypes[PthreadOnceFn])) .Default(SubCheck()); SC.run(C, CE); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 5097341..db24def 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -706,7 +706,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, BlockDeclRefDecls); // FIXME: This leaks ImplicitParamDecl *SelfDecl = - ImplicitParamDecl::Create(getContext(), 0, + ImplicitParamDecl::Create(getContext(), const_cast<BlockDecl*>(BD), SourceLocation(), II, ParmTy); @@ -812,7 +812,8 @@ CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) { Pad.getQuantity()), ArrayType::Normal, 0); ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(), - 0, QualType(PadTy), 0, VarDecl::None); + 0, QualType(PadTy), 0, + VarDecl::None, VarDecl::None); Expr *E; E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), SourceLocation()); @@ -860,7 +861,9 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -941,8 +944,9 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); if (NoteForHelperp) { @@ -1025,8 +1029,9 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); // dst->x @@ -1089,8 +1094,9 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, false, - true); + FunctionDecl::Static, + FunctionDecl::None, + false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); llvm::Value *V = CGF.GetAddrOfLocalVar(Src); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index efee0e3..5646d00 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -38,6 +38,7 @@ namespace llvm { class GlobalValue; class TargetData; class FunctionType; + class PointerType; class Value; class LLVMContext; } @@ -127,7 +128,7 @@ protected: llvm::LLVMContext &VMContext; public: - const llvm::Type *PtrToInt8Ty; + const llvm::PointerType *PtrToInt8Ty; struct HelperInfo { int index; int flag; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 38c40ed..95c41db 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -682,13 +682,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BIsqrt: case Builtin::BIsqrtf: case Builtin::BIsqrtl: { - // Rewrite sqrt to intrinsic if allowed. - if (!FD->hasAttr<ConstAttr>()) - break; - Value *Arg0 = EmitScalarExpr(E->getArg(0)); - const llvm::Type *ArgType = Arg0->getType(); - Value *F = CGM.getIntrinsic(Intrinsic::sqrt, &ArgType, 1); - return RValue::get(Builder.CreateCall(F, Arg0, "tmp")); + // TODO: there is currently no set of optimizer flags + // sufficient for us to rewrite sqrt to @llvm.sqrt. + // -fmath-errno=0 is not good enough; we need finiteness. + // We could probably precondition the call with an ult + // against 0, but is that worth the complexity? + break; } case Builtin::BIpow: @@ -983,8 +982,38 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateStore(Ops[1], Ops[0]); } case X86::BI__builtin_ia32_palignr: { - Function *F = CGM.getIntrinsic(Intrinsic::x86_ssse3_palign_r); - return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size()); + unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); + + // If palignr is shifting the pair of input vectors less than 9 bytes, + // emit a shuffle instruction. + if (shiftVal <= 8) { + const llvm::Type *IntTy = llvm::Type::getInt32Ty(VMContext); + + llvm::SmallVector<llvm::Constant*, 8> Indices; + for (unsigned i = 0; i != 8; ++i) + Indices.push_back(llvm::ConstantInt::get(IntTy, shiftVal + i)); + + Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); + return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); + } + + // If palignr is shifting the pair of input vectors more than 8 but less + // than 16 bytes, emit a logical right shift of the destination. + if (shiftVal < 16) { + // MMX has these as 1 x i64 vectors for some odd optimization reasons. + const llvm::Type *EltTy = llvm::Type::getInt64Ty(VMContext); + const llvm::Type *VecTy = llvm::VectorType::get(EltTy, 1); + + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); + Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8); + + // create i32 constant + llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + 2, "palignr"); + } + + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. + return llvm::Constant::getNullValue(ConvertType(E->getType())); } case X86::BI__builtin_ia32_palignr128: { unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); @@ -1025,5 +1054,49 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + llvm::SmallVector<Value*, 4> Ops; + + for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: return 0; + + // vec_st + case PPC::BI__builtin_altivec_stvx: + case PPC::BI__builtin_altivec_stvxl: + case PPC::BI__builtin_altivec_stvebx: + case PPC::BI__builtin_altivec_stvehx: + case PPC::BI__builtin_altivec_stvewx: + { + Ops[2] = Builder.CreateBitCast(Ops[2], llvm::Type::getInt8PtrTy(VMContext)); + Ops[1] = !isa<Constant>(Ops[1]) || !cast<Constant>(Ops[1])->isNullValue() + ? Builder.CreateGEP(Ops[2], Ops[1], "tmp") : Ops[2]; + Ops.pop_back(); + + switch (BuiltinID) { + default: assert(0 && "Unsupported vavg intrinsic!"); + case PPC::BI__builtin_altivec_stvx: + ID = Intrinsic::ppc_altivec_stvx; + break; + case PPC::BI__builtin_altivec_stvxl: + ID = Intrinsic::ppc_altivec_stvxl; + break; + case PPC::BI__builtin_altivec_stvebx: + ID = Intrinsic::ppc_altivec_stvebx; + break; + case PPC::BI__builtin_altivec_stvehx: + ID = Intrinsic::ppc_altivec_stvehx; + break; + case PPC::BI__builtin_altivec_stvewx: + ID = Intrinsic::ppc_altivec_stvewx; + break; + } + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), ""); + } + } return 0; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 93a182f..74cf113 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -297,15 +297,15 @@ void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name, getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer()); } -static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex, +static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty); - Vtable = CGF.Builder.CreateLoad(Vtable); + llvm::Value *VTable = CGF.Builder.CreateBitCast(This, Ty); + VTable = CGF.Builder.CreateLoad(VTable); llvm::Value *VFuncPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn"); + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); return CGF.Builder.CreateLoad(VFuncPtr); } @@ -313,7 +313,7 @@ llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, const llvm::Type *Ty) { MD = MD->getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } @@ -323,7 +323,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *&This, const llvm::Type *Ty) { DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl()); uint64_t VTableIndex = - CGM.getVTables().getMethodVtableIndex(GlobalDecl(DD, Type)); + CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index cb1ecc1..92d15d9 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -528,7 +528,7 @@ static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) { } const llvm::Type * -CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) { +CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); if (!HasIncompleteReturnTypeOrArgumentTypes(FPT)) @@ -586,8 +586,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, case ABIArgInfo::Indirect: PAL.push_back(llvm::AttributeWithIndex::get(Index, - llvm::Attribute::StructRet | - llvm::Attribute::NoAlias)); + llvm::Attribute::StructRet)); ++Index; // sret disables readnone and readonly FuncAttrs &= ~(llvm::Attribute::ReadOnly | @@ -870,7 +869,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &CallArgs, - const Decl *TargetDecl) { + const Decl *TargetDecl, + llvm::Instruction **callOrInvoke) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. llvm::SmallVector<llvm::Value*, 16> Args; @@ -996,6 +996,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Args.data(), Args.data()+Args.size()); EmitBlock(Cont); } + if (callOrInvoke) { + *callOrInvoke = CS.getInstruction(); + } CS.setAttributes(Attrs); CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 177e862..a604eef 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -20,65 +20,61 @@ using namespace clang; using namespace CodeGen; static uint64_t -ComputeNonVirtualBaseClassOffset(ASTContext &Context, - const CXXBasePath &Path, - unsigned Start) { +ComputeNonVirtualBaseClassOffset(ASTContext &Context, + const CXXRecordDecl *DerivedClass, + CXXBaseSpecifierArray::iterator Start, + CXXBaseSpecifierArray::iterator End) { uint64_t Offset = 0; - - for (unsigned i = Start, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; + + const CXXRecordDecl *RD = DerivedClass; + + for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) { + const CXXBaseSpecifier *Base = *I; + assert(!Base->isVirtual() && "Should not see virtual bases here!"); // Get the layout. - const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXBaseSpecifier *BS = Element.Base; - assert(!BS->isVirtual() && "Should not see virtual bases here!"); - - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl()); + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); // Add the offset. - Offset += Layout.getBaseClassOffset(Base) / 8; + Offset += Layout.getBaseClassOffset(BaseDecl); + + RD = BaseDecl; } - - return Offset; + + // FIXME: We should not use / 8 here. + return Offset / 8; } llvm::Constant * -CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass) { - if (Class == BaseClass) - return 0; - - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast<CXXRecordDecl *>(Class)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } +CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, + const CXXBaseSpecifierArray &BasePath) { + assert(!BasePath.empty() && "Base path should not be empty!"); - uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), - Paths.front(), 0); + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, + BasePath.begin(), BasePath.end()); if (!Offset) return 0; - + const llvm::Type *PtrDiffTy = - Types.ConvertType(getContext().getPointerDiffType()); - + Types.ConvertType(getContext().getPointerDiffType()); + return llvm::ConstantInt::get(PtrDiffTy, Offset); } -/// Gets the address of a virtual base class within a complete object. +/// Gets the address of a direct base class within a complete object. /// This should only be used for (1) non-virtual bases or (2) virtual bases /// when the type is known to be complete (e.g. in complete destructors). /// /// The object pointed to by 'This' is assumed to be non-null. llvm::Value * -CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, - bool isBaseVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base) { +CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual) { // 'this' must be a pointer (in some address space) to Derived. assert(This->getType()->isPointerTy() && cast<llvm::PointerType>(This->getType())->getElementType() @@ -87,7 +83,7 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, // Compute the offset of the virtual base. uint64_t Offset; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); - if (isBaseVirtual) + if (BaseIsVirtual) Offset = Layout.getVBaseClassOffset(Base); else Offset = Layout.getBaseClassOffset(Base); @@ -105,51 +101,63 @@ CodeGenFunction::GetAddressOfBaseOfCompleteClass(llvm::Value *This, return V; } -llvm::Value * -CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool NullCheckValue) { - QualType BTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(BaseClass)); - const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy)); - - if (Class == BaseClass) { - // Just cast back. - return Builder.CreateBitCast(Value, BasePtrTy); - } +static llvm::Value * +ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, + uint64_t NonVirtual, llvm::Value *Virtual) { + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + llvm::Value *NonVirtualOffset = 0; + if (NonVirtual) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual); + + llvm::Value *BaseOffset; + if (Virtual) { + if (NonVirtualOffset) + BaseOffset = CGF.Builder.CreateAdd(Virtual, NonVirtualOffset); + else + BaseOffset = Virtual; + } else + BaseOffset = NonVirtualOffset; + + // Apply the base offset. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + ThisPtr = CGF.Builder.CreateBitCast(ThisPtr, Int8PtrTy); + ThisPtr = CGF.Builder.CreateGEP(ThisPtr, BaseOffset, "add.ptr"); - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast<CXXRecordDecl *>(Class)-> - isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClass), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } + return ThisPtr; +} - unsigned Start = 0; - llvm::Value *VirtualOffset = 0; +llvm::Value * +CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, + bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); - const CXXBasePath &Path = Paths.front(); + CXXBaseSpecifierArray::iterator Start = BasePath.begin(); const CXXRecordDecl *VBase = 0; - for (unsigned i = 0, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; - if (Element.Base->isVirtual()) { - Start = i+1; - QualType VBaseType = Element.Base->getType(); - VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl()); - } + + // Get the virtual base. + if ((*Start)->isVirtual()) { + VBase = + cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl()); + ++Start; } + + uint64_t NonVirtualOffset = + ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, + Start, BasePath.end()); - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), Paths.front(), Start); + // Get the base pointer type. + const llvm::Type *BasePtrTy = + ConvertType((BasePath.end()[-1])->getType())->getPointerTo(); - if (!Offset && !VBase) { + if (!NonVirtualOffset && !VBase) { // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } - + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -165,28 +173,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } - + + llvm::Value *VirtualOffset = 0; + if (VBase) - VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase); + VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = 0; - if (Offset) - NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - llvm::Value *BaseOffset; - if (VBase) { - if (NonVirtualOffset) - BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - else - BaseOffset = VirtualOffset; - } else - BaseOffset = NonVirtualOffset; - - // Apply the base offset. - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - Value = Builder.CreateBitCast(Value, Int8PtrTy); - Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr"); + // Apply the offsets. + Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, + VirtualOffset); // Cast back. Value = Builder.CreateBitCast(Value, BasePtrTy); @@ -210,21 +205,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *Class, - const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue) { + assert(!BasePath.empty() && "Base path should not be empty!"); + QualType DerivedTy = - getContext().getCanonicalType( - getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClass))); + getContext().getCanonicalType(getContext().getTagDeclType(Derived)); const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); - if (Class == DerivedClass) { - // Just cast back. - return Builder.CreateBitCast(Value, DerivedPtrTy); - } - llvm::Value *NonVirtualOffset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, Class); + CGM.GetNonVirtualBaseClassOffset(Derived, BasePath); if (!NonVirtualOffset) { // No offset, we can just cast back. @@ -274,23 +265,16 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, /// EmitCopyCtorCall - Emit a call to a copy constructor. static void -EmitCopyCtorCall(CodeGenFunction &CGF, - const CXXConstructorDecl *CopyCtor, CXXCtorType CopyCtorType, - llvm::Value *ThisPtr, llvm::Value *VTT, llvm::Value *Src) { - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, CopyCtorType); +EmitCopyCtorCall(CodeGenFunction &CGF, const CXXConstructorDecl *CopyCtor, + llvm::Value *ThisPtr, llvm::Value *Src) { + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, Ctor_Complete); CallArgList CallArgs; // Push the this ptr. CallArgs.push_back(std::make_pair(RValue::get(ThisPtr), CopyCtor->getThisType(CGF.getContext()))); - - // Push the VTT parameter if necessary. - if (VTT) { - QualType T = CGF.getContext().getPointerType(CGF.getContext().VoidPtrTy); - CallArgs.push_back(std::make_pair(RValue::get(VTT), T)); - } - + // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); @@ -325,13 +309,8 @@ EmitCopyCtorCall(CodeGenFunction &CGF, // FIXME. Consolidate this with EmitCXXAggrConstructorCall. void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); - assert(CA && "VLA cannot be copied over"); - bool BitwiseCopy = BaseClassDecl->hasTrivialCopyConstructor(); - + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl) { // Create a temporary for the loop index and initialize it with 0. llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), "loop.index"); @@ -347,7 +326,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, llvm::BasicBlock *ForBody = createBasicBlock("for.body"); // Generate: if (loop-index < number-of-elements fall to the loop body, // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); + uint64_t NumElements = getContext().getConstantArrayElementCount(Array); llvm::Value * NumElementsPtr = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); llvm::Value *Counter = Builder.CreateLoad(IndexPtr); @@ -362,95 +341,8 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, Counter = Builder.CreateLoad(IndexPtr); Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - if (BitwiseCopy) - EmitAggregateCopy(Dest, Src, Ty); - else if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0)) - EmitCopyCtorCall(*this, BaseCopyCtor, Ctor_Complete, Dest, 0, Src); - - EmitBlock(ContinueBlock); - - // Emit the increment of the loop counter. - llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1); - Counter = Builder.CreateLoad(IndexPtr); - NextVal = Builder.CreateAdd(Counter, NextVal, "inc"); - Builder.CreateStore(NextVal, IndexPtr); - - // Finally, branch back up to the condition for the next iteration. - EmitBranch(CondBlock); - - // Emit the fall-through block. - EmitBlock(AfterFor, true); -} - -/// EmitClassAggrCopyAssignment - This routine generates code to assign a class -/// array of objects from SrcValue to DestValue. Assignment can be either a -/// bitwise assignment or via a copy assignment operator function call. -/// FIXME. This can be consolidated with EmitClassAggrMemberwiseCopy -void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, - llvm::Value *Src, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array); - assert(CA && "VLA cannot be asssigned"); - bool BitwiseAssign = BaseClassDecl->hasTrivialCopyAssignment(); - - // Create a temporary for the loop index and initialize it with 0. - llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext), - "loop.index"); - llvm::Value* zeroConstant = - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)); - Builder.CreateStore(zeroConstant, IndexPtr); - // Start the loop with a block that tests the condition. - llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); - llvm::BasicBlock *AfterFor = createBasicBlock("for.end"); - - EmitBlock(CondBlock); - - llvm::BasicBlock *ForBody = createBasicBlock("for.body"); - // Generate: if (loop-index < number-of-elements fall to the loop body, - // otherwise, go to the block after the for-loop. - uint64_t NumElements = getContext().getConstantArrayElementCount(CA); - llvm::Value * NumElementsPtr = - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), NumElements); - llvm::Value *Counter = Builder.CreateLoad(IndexPtr); - llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElementsPtr, - "isless"); - // If the condition is true, execute the body. - Builder.CreateCondBr(IsLess, ForBody, AfterFor); - - EmitBlock(ForBody); - llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc"); - // Inside the loop body, emit the assignment operator call on array element. - Counter = Builder.CreateLoad(IndexPtr); - Src = Builder.CreateInBoundsGEP(Src, Counter, "srcaddress"); - Dest = Builder.CreateInBoundsGEP(Dest, Counter, "destaddress"); - const CXXMethodDecl *MD = 0; - if (BitwiseAssign) - EmitAggregateCopy(Dest, Src, Ty); - else { - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassAggrCopyAssignment - No user assign"); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); - } + EmitClassMemberwiseCopy(Dest, Src, ClassDecl); + EmitBlock(ContinueBlock); // Emit the increment of the loop counter. @@ -468,7 +360,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. -static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { +static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, + bool ForVirtualBase) { if (!CodeGenVTables::needsVTTParameter(GD)) { // This constructor/destructor does not need a VTT parameter. return 0; @@ -486,9 +379,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { if (RD == Base) { assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) && "doing no-op VTT offset in base dtor/ctor?"); + assert(!ForVirtualBase && "Can't have same class as virtual base!"); SubVTTIndex = 0; } else { - SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, Base); + const ASTRecordLayout &Layout = + CGF.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = ForVirtualBase ? + Layout.getVBaseClassOffset(Base) : Layout.getBaseClassOffset(Base); + + SubVTTIndex = + CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!"); } @@ -511,75 +411,16 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) { /// or via a copy constructor call. void CodeGenFunction::EmitClassMemberwiseCopy( llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, QualType Ty) { - CXXCtorType CtorType = Ctor_Complete; - - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - - // We want to call the base constructor. - CtorType = Ctor_Base; - } - if (BaseClassDecl->hasTrivialCopyConstructor()) { - EmitAggregateCopy(Dest, Src, Ty); + const CXXRecordDecl *ClassDecl) { + if (ClassDecl->hasTrivialCopyConstructor()) { + EmitAggregateCopy(Dest, Src, getContext().getTagDeclType(ClassDecl)); return; } - CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(getContext(), 0); - if (!BaseCopyCtor) - return; + CXXConstructorDecl *CopyCtor = ClassDecl->getCopyConstructor(getContext(), 0); + assert(CopyCtor && "Did not have copy ctor!"); - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType)); - EmitCopyCtorCall(*this, BaseCopyCtor, CtorType, Dest, VTT, Src); -} - -/// EmitClassCopyAssignment - This routine generates code to copy assign a class -/// object from SrcValue to DestValue. Assignment can be either a bitwise -/// assignment of via an assignment operator call. -// FIXME. Consolidate this with EmitClassMemberwiseCopy as they share a lot. -void CodeGenFunction::EmitClassCopyAssignment( - llvm::Value *Dest, llvm::Value *Src, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty) { - if (ClassDecl) { - Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - } - if (BaseClassDecl->hasTrivialCopyAssignment()) { - EmitAggregateCopy(Dest, Src, Ty); - return; - } - - const CXXMethodDecl *MD = 0; - BaseClassDecl->hasConstCopyAssignment(getContext(), MD); - assert(MD && "EmitClassCopyAssignment - missing copy assign"); - - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *LTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, LTy); - - CallArgList CallArgs; - // Push the this (Dest) ptr. - CallArgs.push_back(std::make_pair(RValue::get(Dest), - MD->getThisType(getContext()))); - - // Push the Src ptr. - QualType SrcTy = MD->getParamDecl(0)->getType(); - RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : - RValue::getAggregate(Src); - CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, MD); + EmitCopyCtorCall(*this, CopyCtor, Dest, Src); } /// SynthesizeCXXCopyConstructor - This routine implicitly defines body of a @@ -600,30 +441,25 @@ void CodeGenFunction::EmitClassCopyAssignment( void CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { const CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(CurGD.getDecl()); + CXXCtorType CtorType = CurGD.getCtorType(); + (void) CtorType; + const CXXRecordDecl *ClassDecl = Ctor->getParent(); assert(!ClassDecl->hasUserDeclaredCopyConstructor() && "SynthesizeCXXCopyConstructor - copy constructor has definition already"); assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor"); - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy constrution of virtual base NYI - if (Base->isVirtual()) - continue; + llvm::Value *ThisPtr = LoadCXXThis(); - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - EmitClassMemberwiseCopy(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } + // Find the source pointer. + unsigned SrcArgIndex = Args.size() - 1; + assert(CtorType == Ctor_Base || SrcArgIndex == 1); + assert(CtorType != Ctor_Base || + (ClassDecl->getNumVBases() != 0 && SrcArgIndex == 2) || + SrcArgIndex == 1); + + llvm::Value *SrcPtr = + Builder.CreateLoad(GetAddrOfLocalVar(Args[SrcArgIndex].first)); for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { @@ -638,27 +474,26 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForField(ThisPtr, Field, 0); + LValue RHS = EmitLValueForField(SrcPtr, Field, 0); if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); + const llvm::Type *BasePtr = ConvertType(FieldType)->getPointerTo(); llvm::Value *DestBaseAddrPtr = Builder.CreateBitCast(LHS.getAddress(), BasePtr); llvm::Value *SrcBaseAddrPtr = Builder.CreateBitCast(RHS.getAddress(), BasePtr); EmitClassAggrMemberwiseCopy(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); + FieldClassDecl); } else EmitClassMemberwiseCopy(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); + FieldClassDecl); continue; } // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForFieldInitialization(LoadOfThis, Field, 0); - LValue RHS = EmitLValueForFieldInitialization(LoadOfSrc, Field, 0); + LValue LHS = EmitLValueForFieldInitialization(ThisPtr, Field, 0); + LValue RHS = EmitLValueForFieldInitialization(SrcPtr, Field, 0); if (!hasAggregateLLVMType(Field->getType())) { RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); @@ -675,100 +510,6 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const FunctionArgList &Args) { InitializeVTablePointers(ClassDecl); } -/// SynthesizeCXXCopyAssignment - Implicitly define copy assignment operator. -/// Before the implicitly-declared copy assignment operator for a class is -/// implicitly defined, all implicitly- declared copy assignment operators for -/// its direct base classes and its nonstatic data members shall have been -/// implicitly defined. [12.8-p12] -/// The implicitly-defined copy assignment operator for class X performs -/// memberwise assignment of its subob- jects. The direct base classes of X are -/// assigned first, in the order of their declaration in -/// the base-specifier-list, and then the immediate nonstatic data members of X -/// are assigned, in the order in which they were declared in the class -/// definition.Each subobject is assigned in the manner appropriate to its type: -/// if the subobject is of class type, the copy assignment operator for the -/// class is used (as if by explicit qualification; that is, ignoring any -/// possible virtual overriding functions in more derived classes); -/// -/// if the subobject is an array, each element is assigned, in the manner -/// appropriate to the element type; -/// -/// if the subobject is of scalar type, the built-in assignment operator is -/// used. -void CodeGenFunction::SynthesizeCXXCopyAssignment(const FunctionArgList &Args) { - const CXXMethodDecl *CD = cast<CXXMethodDecl>(CurGD.getDecl()); - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext()); - assert(!ClassDecl->hasUserDeclaredCopyAssignment() && - "SynthesizeCXXCopyAssignment - copy assignment has user declaration"); - - FunctionArgList::const_iterator i = Args.begin(); - const VarDecl *ThisArg = i->first; - llvm::Value *ThisObj = GetAddrOfLocalVar(ThisArg); - llvm::Value *LoadOfThis = Builder.CreateLoad(ThisObj, "this"); - const VarDecl *SrcArg = (i+1)->first; - llvm::Value *SrcObj = GetAddrOfLocalVar(SrcArg); - llvm::Value *LoadOfSrc = Builder.CreateLoad(SrcObj); - - for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - // FIXME. copy assignment of virtual base NYI - if (Base->isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - EmitClassCopyAssignment(LoadOfThis, LoadOfSrc, ClassDecl, BaseClassDecl, - Base->getType()); - } - - for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - FieldEnd = ClassDecl->field_end(); - Field != FieldEnd; ++Field) { - QualType FieldType = getContext().getCanonicalType((*Field)->getType()); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *DestBaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - llvm::Value *SrcBaseAddrPtr = - Builder.CreateBitCast(RHS.getAddress(), BasePtr); - EmitClassAggrCopyAssignment(DestBaseAddrPtr, SrcBaseAddrPtr, Array, - FieldClassDecl, FieldType); - } - else - EmitClassCopyAssignment(LHS.getAddress(), RHS.getAddress(), - 0 /*ClassDecl*/, FieldClassDecl, FieldType); - continue; - } - // Do a built-in assignment of scalar data members. - LValue LHS = EmitLValueForField(LoadOfThis, *Field, 0); - LValue RHS = EmitLValueForField(LoadOfSrc, *Field, 0); - if (!hasAggregateLLVMType(Field->getType())) { - RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType()); - EmitStoreThroughLValue(RVRHS, LHS, Field->getType()); - } else if (Field->getType()->isAnyComplexType()) { - ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(), - RHS.isVolatileQualified()); - StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified()); - } else { - EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType()); - } - } - - // return *this; - Builder.CreateStore(LoadOfThis, ReturnValue); -} - static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXBaseOrMemberInitializer *BaseInit, @@ -782,15 +523,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); - // FIXME: This method of determining whether a base is virtual is ridiculous; - // it should be part of BaseInit. - bool isBaseVirtual = false; - for (CXXRecordDecl::base_class_const_iterator I = ClassDecl->vbases_begin(), - E = ClassDecl->vbases_end(); I != E; ++I) - if (I->getType()->getAs<RecordType>()->getDecl() == BaseClassDecl) { - isBaseVirtual = true; - break; - } + bool isBaseVirtual = BaseInit->isBaseVirtual(); // The base constructor doesn't construct virtual bases. if (CtorType == Ctor_Base && isBaseVirtual) @@ -798,9 +531,10 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, // We can pretend to be a complete class because it only matters for // virtual bases, and we only do virtual bases for complete ctors. - llvm::Value *V = ThisPtr; - V = CGF.GetAddressOfBaseOfCompleteClass(V, isBaseVirtual, - ClassDecl, BaseClassDecl); + llvm::Value *V = + CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl, + BaseClassDecl, + BaseInit->isBaseVirtual()); CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); @@ -809,7 +543,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CodeGenFunction::EHCleanupBlock Cleanup(CGF); CXXDestructorDecl *DD = BaseClassDecl->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Base, V); + CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V); } } @@ -850,7 +584,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LHS.isVolatileQualified()); } else { CGF.EmitAggExpr(MemberInit->getInit(), LHS.getAddress(), - LHS.isVolatileQualified(), false, true); + LHS.isVolatileQualified(), + /*IgnoreResult*/ false, + /*IsInitializer*/ true); if (!CGF.Exceptions) return; @@ -868,7 +604,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); CXXDestructorDecl *DD = RD->getDestructor(CGF.getContext()); - CGF.EmitCXXDestructorCall(DD, Dtor_Complete, LHS.getAddress()); + CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } } } @@ -976,8 +713,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> MemberInitializers; - // FIXME: Add vbase initialization - for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(), E = CD->init_end(); B != E; ++B) { @@ -1028,7 +763,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // variant, then call the appropriate operator delete() on the way // out. if (DtorType == Dtor_Deleting) { - EmitCXXDestructorCall(Dtor, Dtor_Complete, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // If this is the complete variant, just invoke the base variant; @@ -1036,7 +772,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { // this optimization if the body is a function-try-block, because // we'd introduce *two* handler blocks. } else if (!isTryBody && DtorType == Dtor_Complete) { - EmitCXXDestructorCall(Dtor, Dtor_Base, LoadCXXThis()); + EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, + LoadCXXThis()); SkipBody = true; // Otherwise, we're in the base variant, so we need to ensure the @@ -1117,11 +854,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, if (BaseClassDecl->hasTrivialDestructor()) continue; const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(), - true, - ClassDecl, - BaseClassDecl); - EmitCXXDestructorCall(D, Dtor_Base, V); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), + ClassDecl, BaseClassDecl, + /*BaseIsVirtual=*/true); + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V); } return; } @@ -1175,7 +912,8 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, Array, BaseAddrPtr); } else EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()), - Dtor_Complete, LHS.getAddress()); + Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); } // Destroy non-virtual bases. @@ -1193,12 +931,14 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); - - llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*NullCheckValue=*/false); - EmitCXXDestructorCall(D, Dtor_Base, V); + + const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext()); + llvm::Value *V = + GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl, + BaseClassDecl, + /*BaseIsVirtual=*/false); + + EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V); } } @@ -1271,7 +1011,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, { CXXTemporariesCleanupScope Scope(*this); - EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd); + EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address, + ArgBeg, ArgEnd); } EmitBlock(ContinueBlock); @@ -1345,7 +1086,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, Counter = Builder.CreateLoad(IndexPtr); Counter = Builder.CreateSub(Counter, One); llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx"); - EmitCXXDestructorCall(D, Dtor_Complete, Address); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Address); EmitBlock(ContinueBlock); @@ -1390,6 +1131,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, FunctionDecl::Static, + FunctionDecl::None, false, true); StartFunction(FD, R, Fn, Args, SourceLocation()); QualType BaseElementTy = getContext().getBaseElementType(Array); @@ -1407,7 +1149,7 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, - CXXCtorType Type, + CXXCtorType Type, bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) { @@ -1429,7 +1171,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, return; } - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); @@ -1450,7 +1192,8 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ++I; // vtt - if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType))) { + if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), + /*ForVirtualBase=*/false)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); @@ -1502,8 +1245,10 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, + bool ForVirtualBase, llvm::Value *This) { - llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type)); + llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), + ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type); EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); @@ -1538,7 +1283,8 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, void CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass) { const CXXRecordDecl *RD = Base.getBase(); @@ -1548,7 +1294,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, // Check if we need to use a vtable from the VTT. if (CodeGenVTables::needsVTTParameter(CurGD) && - (RD->getNumVBases() || BaseIsMorallyVirtual)) { + (RD->getNumVBases() || NearestVBase)) { // Get the secondary vpointer index. uint64_t VirtualPointerIndex = CGM.getVTables().getSecondaryVirtualPointerIndex(VTableClass, Base); @@ -1567,20 +1313,27 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, } // Compute where to store the address point. - llvm::Value *VTableField; + llvm::Value *VirtualOffset = 0; + uint64_t NonVirtualOffset = 0; - if (CodeGenVTables::needsVTTParameter(CurGD) && BaseIsMorallyVirtual) { + if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. - VTableField = GetAddressOfBaseClass(LoadCXXThis(), VTableClass, RD, - /*NullCheckValue=*/false); + VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass, + NearestVBase); + NonVirtualOffset = OffsetFromNearestVBase / 8; } else { - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - VTableField = Builder.CreateBitCast(LoadCXXThis(), Int8PtrTy); - VTableField = - Builder.CreateConstInBoundsGEP1_64(VTableField, Base.getBaseOffset() / 8); + // We can just use the base offset in the complete class. + NonVirtualOffset = Base.getBaseOffset() / 8; } + + // Apply the offsets. + llvm::Value *VTableField = LoadCXXThis(); + + if (NonVirtualOffset || VirtualOffset) + VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField, + NonVirtualOffset, + VirtualOffset); // Finally, store the address point. const llvm::Type *AddressPointPtrTy = @@ -1591,7 +1344,8 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, void CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, - bool BaseIsMorallyVirtual, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -1600,7 +1354,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, // been set. if (!BaseIsNonVirtualPrimaryBase) { // Initialize the vtable pointer for this base. - InitializeVTablePointer(Base, BaseIsMorallyVirtual, VTable, VTableClass); + InitializeVTablePointer(Base, NearestVBase, OffsetFromNearestVBase, + VTable, VTableClass); } const CXXRecordDecl *RD = Base.getBase(); @@ -1616,7 +1371,7 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, continue; uint64_t BaseOffset; - bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; + uint64_t BaseOffsetFromNearestVBase; bool BaseDeclIsNonVirtualPrimaryBase; if (I->isVirtual()) { @@ -1628,17 +1383,20 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, getContext().getASTRecordLayout(VTableClass); BaseOffset = Layout.getVBaseClassOffset(BaseDecl); - BaseDeclIsMorallyVirtual = true; + BaseOffsetFromNearestVBase = 0; BaseDeclIsNonVirtualPrimaryBase = false; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); + BaseOffsetFromNearestVBase = + OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl); BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; } InitializeVTablePointers(BaseSubobject(BaseDecl, BaseOffset), - BaseDeclIsMorallyVirtual, + I->isVirtual() ? BaseDecl : NearestVBase, + BaseOffsetFromNearestVBase, BaseDeclIsNonVirtualPrimaryBase, VTable, VTableClass, VBases); } @@ -1654,8 +1412,8 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { // Initialize the vtable pointers for this class and all of its bases. VisitedVirtualBasesSetTy VBases; - InitializeVTablePointers(BaseSubobject(RD, 0), - /*BaseIsMorallyVirtual=*/false, + InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0, + /*OffsetFromNearestVBase=*/0, /*BaseIsNonVirtualPrimaryBase=*/false, VTable, RD, VBases); } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index bcbda8a..4963e73 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -320,27 +320,9 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); - FieldOffset += FieldSize; - FType = CGM.getContext().UnsignedLongTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "Size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); EltTys.clear(); @@ -360,49 +342,13 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__reserved", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__reserved", &FieldOffset)); FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__FuncPtr", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); + EltTys.push_back(CreateMemberType(Unit, FType, "__FuncPtr", &FieldOffset)); - FieldOffset += FieldSize; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); FieldTy = DescTy; FieldSize = CGM.getContext().getTypeSize(Ty); @@ -525,13 +471,20 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, uint64_t FieldOffset = RL.getFieldOffset(FieldNo); + unsigned Flags = 0; + AccessSpecifier Access = I->getAccess(); + if (Access == clang::AS_private) + Flags |= llvm::DIType::FlagPrivate; + else if (Access == clang::AS_protected) + Flags |= llvm::DIType::FlagProtected; + // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); + FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } } @@ -626,7 +579,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, // It doesn't make sense to give a virtual destructor a vtable index, // since a single destructor has two entries in the vtable. if (!isa<CXXDestructorDecl>(Method)) - VIndex = CGM.getVTables().getMethodVtableIndex(Method); + VIndex = CGM.getVTables().getMethodVTableIndex(Method); ContainingType = RecordTy; } @@ -734,8 +687,8 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { return VTablePtrType; } -/// getVtableName - Get vtable name for the given Class. -llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { +/// getVTableName - Get vtable name for the given Class. +llvm::StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // Otherwise construct gdb compatible name name. std::string Name = "_vptr$" + RD->getNameAsString(); @@ -746,10 +699,10 @@ llvm::StringRef CGDebugInfo::getVtableName(const CXXRecordDecl *RD) { } -/// CollectVtableInfo - If the C++ class has vtable info then insert appropriate +/// CollectVTableInfo - If the C++ class has vtable info then insert appropriate /// debug info entry in EltTys vector. void CGDebugInfo:: -CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, +CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -764,7 +717,7 @@ CollectVtableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); llvm::DIType VPTR = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - getVtableName(RD), Unit, + getVTableName(RD), Unit, 0, Size, 0, 0, 0, getOrCreateVTablePtrType(Unit)); EltTys.push_back(VPTR); @@ -832,7 +785,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); if (CXXDecl) { CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); - CollectVtableInfo(CXXDecl, Unit, EltTys); + CollectVTableInfo(CXXDecl, Unit, EltTys); } CollectRecordFields(RD, Unit, EltTys); llvm::MDNode *ContainingType = NULL; @@ -1293,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast<MemberPointerType>(Ty), Unit); - case Type::InjectedClassName: case Type::TemplateSpecialization: case Type::Elaborated: case Type::QualifiedName: @@ -1318,6 +1270,21 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, return llvm::DIType(); } +/// CreateMemberType - Create new member and increase Offset by FType's size. +llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, + uint64_t *Offset) { + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + uint64_t FieldSize = CGM.getContext().getTypeSize(FType); + unsigned FieldAlign = CGM.getContext().getTypeAlign(FType); + llvm::DIType Ty = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, + Unit, Name, Unit, 0, + FieldSize, FieldAlign, + *Offset, 0, FieldTy); + *Offset += FieldSize; + return Ty; +} + /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, @@ -1341,17 +1308,15 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, } } Name = getFunctionName(FD); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. CGM.getMangledName(LinkageName, GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); LinkageName.setString(Name); - if (!Name.empty() && Name[0] == '\01') - Name = Name.substr(1); } + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); // It is expected that CurLoc is set before using EmitFunctionStart. // Usually, CurLoc points to the left bracket location of compound @@ -1437,72 +1402,19 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, FieldOffset = 0; FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__isa", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__forwarding", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__flags", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__isa", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__forwarding", &FieldOffset)); FType = CGM.getContext().IntTy; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__size", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - + EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); + bool HasCopyAndDispose = CGM.BlockRequiresCopying(Type); if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__copy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; - - FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, - "__destroy_helper", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", + &FieldOffset)); + EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", + &FieldOffset)); } CharUnits Align = CGM.getContext().getDeclAlign(VD); @@ -1517,20 +1429,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, llvm::APInt pad(32, NumPaddingBytes); FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); - FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = CGM.getContext().getTypeAlign(FType); - FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, - Unit, "", Unit, - 0, FieldSize, FieldAlign, - FieldOffset, 0, FieldTy); - EltTys.push_back(FieldTy); - FieldOffset += FieldSize; + EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); } } FType = Type; - FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); + llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); FieldAlign = Align.getQuantity()*8; @@ -1558,13 +1462,6 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Value *Storage, CGBuilderTy &Builder) { assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel) - return; - llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); llvm::DIType Ty; uint64_t XOffset = 0; @@ -1608,11 +1505,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag, const ValueDecl *VD = BDRE->getDecl(); assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); - // Do not emit variable debug information while generating optimized code. - // The llvm optimizer and code generator are not yet ready to support - // optimized code debugging. - const CodeGenOptions &CGO = CGM.getCodeGenOpts(); - if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0) + if (Builder.GetInsertBlock() == 0) return; uint64_t XOffset = 0; @@ -1708,7 +1601,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal, 0); } - llvm::StringRef DeclName = Var->getName(); + llvm::StringRef DeclName = D->getName(); llvm::DIDescriptor DContext = getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()), Unit); DebugFactory.CreateGlobalVariable(DContext, DeclName, diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8397245..c16379a 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -112,7 +112,7 @@ class CGDebugInfo { void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl<llvm::DIDescriptor> &E); - void CollectVtableInfo(const CXXRecordDecl *Decl, + void CollectVTableInfo(const CXXRecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys); @@ -196,13 +196,17 @@ private: /// CreateTypeNode - Create type metadata for a source language type. llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F); + /// CreateMemberType - Create new member and increase Offset by FType's size. + llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, + llvm::StringRef Name, uint64_t *Offset); + /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. llvm::StringRef getFunctionName(const FunctionDecl *FD); - /// getVtableName - Get vtable name for the given Class. - llvm::StringRef getVtableName(const CXXRecordDecl *Decl); + /// getVTableName - Get vtable name for the given Class. + llvm::StringRef getVTableName(const CXXRecordDecl *Decl); }; } // namespace CodeGen diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 07d219f..ba3a2b4 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -31,11 +31,44 @@ using namespace CodeGen; void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { - default: - CGM.ErrorUnsupported(&D, "decl"); - return; + case Decl::TranslationUnit: + case Decl::Namespace: + case Decl::UnresolvedUsingTypename: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + case Decl::TemplateTypeParm: + case Decl::UnresolvedUsingValue: + case Decl::NonTypeTemplateParm: + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::Field: + case Decl::ObjCIvar: + case Decl::ObjCAtDefsField: case Decl::ParmVar: - assert(0 && "Parmdecls should not be in declstmts!"); + case Decl::ImplicitParam: + case Decl::ClassTemplate: + case Decl::FunctionTemplate: + case Decl::TemplateTemplateParm: + case Decl::ObjCMethod: + case Decl::ObjCCategory: + case Decl::ObjCProtocol: + case Decl::ObjCInterface: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCProperty: + case Decl::ObjCCompatibleAlias: + case Decl::LinkageSpec: + case Decl::ObjCPropertyImpl: + case Decl::ObjCClass: + case Decl::ObjCForwardProtocol: + case Decl::FileScopeAsm: + case Decl::Friend: + case Decl::FriendTemplate: + case Decl::Block: + + assert(0 && "Declaration not should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; @@ -44,6 +77,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Using: // using X; [C++] case Decl::UsingShadow: case Decl::UsingDirective: // using namespace X; [C++] + case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] // None of these decls require codegen support. return; @@ -197,6 +231,9 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage) { + // Bail out early if the block is unreachable. + if (!Builder.GetInsertBlock()) return; + llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); @@ -205,6 +242,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D, // Store into LocalDeclMap before generating initializer to handle // circular references. DMEntry = GV; + if (getContext().getLangOptions().CPlusPlus) + CGM.setStaticLocalDeclAddress(&D, GV); // Make sure to evaluate VLA bounds now so that we have them for later. // @@ -610,6 +649,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { DtorTy = getContext().getBaseElementType(Array); if (const RecordType *RT = DtorTy->getAs<RecordType>()) if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + llvm::Value *Loc = DeclPtr; + if (isByRef) + Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), + D.getNameAsString()); + if (!ClassDecl->hasTrivialDestructor()) { const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext()); assert(D && "EmitLocalBlockVarDecl - destructor is nul"); @@ -622,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); // Make sure to jump to the exit block. @@ -634,20 +678,22 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(DeclPtr, BasePtr); + Builder.CreateBitCast(Loc, BasePtr); EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); } } else { { DelayedCleanupBlock Scope(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); // Make sure to jump to the exit block. EmitBranch(Scope.getCleanupExitBlock()); } if (Exceptions) { EHCleanupBlock Cleanup(*this); - EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr); + EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, + Loc); } } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 40c18ca..f6c805f 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -219,9 +219,14 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, SourceLocation()); // Emit the dtors, in reverse order from construction. - for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) - Builder.CreateCall(DtorsAndObjects[e - i - 1].first, - DtorsAndObjects[e - i - 1].second); + for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) { + llvm::Constant *Callee = DtorsAndObjects[e - i - 1].first; + llvm::CallInst *CI = Builder.CreateCall(Callee, + DtorsAndObjects[e - i - 1].second); + // Make sure the call and the callee agree on calling convention. + if (llvm::Function *F = dyn_cast<llvm::Function>(Callee)) + CI->setCallingConv(F->getCallingConv()); + } FinishFunction(); } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 1e15066..c1d05bf 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -122,82 +122,71 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev"); } -// CopyObject - Utility to copy an object. Calls copy constructor as necessary. -// DestPtr is casted to the right type. -static void CopyObject(CodeGenFunction &CGF, const Expr *E, - llvm::Value *DestPtr, llvm::Value *ExceptionPtrPtr) { - QualType ObjectType = E->getType(); - - // Store the throw exception in the exception object. - if (!CGF.hasAggregateLLVMType(ObjectType)) { - llvm::Value *Value = CGF.EmitScalarExpr(E); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(); - - CGF.Builder.CreateStore(Value, - CGF.Builder.CreateBitCast(DestPtr, ValuePtrTy)); - } else { - const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(); - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); - - llvm::Value *This = CGF.Builder.CreateBitCast(DestPtr, Ty); - if (RD->hasTrivialCopyConstructor()) { - CGF.EmitAggExpr(E, This, false); - } else if (CXXConstructorDecl *CopyCtor - = RD->getCopyConstructor(CGF.getContext(), 0)) { - llvm::Value *CondPtr = 0; - if (CGF.Exceptions) { - CodeGenFunction::EHCleanupBlock Cleanup(CGF); - llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF); - - llvm::BasicBlock *CondBlock = CGF.createBasicBlock("cond.free"); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CondPtr = CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), - "doEHfree"); - - CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CondPtr), - CondBlock, Cont); - CGF.EmitBlock(CondBlock); - - // Load the exception pointer. - llvm::Value *ExceptionPtr = CGF.Builder.CreateLoad(ExceptionPtrPtr); - CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr); - - CGF.EmitBlock(Cont); - } - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), - CondPtr); - - llvm::Value *Src = CGF.EmitLValue(E).getAddress(); - - if (CondPtr) - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), - CondPtr); - - llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest(); - CGF.setInvokeDest(TerminateHandler); - - // Stolen from EmitClassAggrMemberwiseCopy - llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, - Ctor_Complete); - CallArgList CallArgs; - CallArgs.push_back(std::make_pair(RValue::get(This), - CopyCtor->getThisType(CGF.getContext()))); - - // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - CopyCtor->getParamDecl(0)->getType())); - const FunctionProtoType *FPT - = CopyCtor->getType()->getAs<FunctionProtoType>(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), - Callee, ReturnValueSlot(), CallArgs, CopyCtor); - CGF.setInvokeDest(PrevLandingPad); - } else - llvm_unreachable("uncopyable object"); +// Emits an exception expression into the given location. This +// differs from EmitAnyExprToMem only in that, if a final copy-ctor +// call is required, an exception within that copy ctor causes +// std::terminate to be invoked. +static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, + llvm::Value *ExnLoc) { + // We want to release the allocated exception object if this + // expression throws. We do this by pushing an EH-only cleanup + // block which, furthermore, deactivates itself after the expression + // is complete. + llvm::AllocaInst *ShouldFreeVar = + CGF.CreateTempAlloca(llvm::Type::getInt1Ty(CGF.getLLVMContext()), + "should-free-exnobj.var"); + CGF.InitTempAlloca(ShouldFreeVar, + llvm::ConstantInt::getFalse(CGF.getLLVMContext())); + + // A variable holding the exception pointer. This is necessary + // because the throw expression does not necessarily dominate the + // cleanup, for example if it appears in a conditional expression. + llvm::AllocaInst *ExnLocVar = + CGF.CreateTempAlloca(ExnLoc->getType(), "exnobj.var"); + + llvm::BasicBlock *SavedInvokeDest = CGF.getInvokeDest(); + { + CodeGenFunction::EHCleanupBlock Cleanup(CGF); + llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj"); + llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done"); + + llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar, + "should-free-exnobj"); + CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB); + CGF.EmitBlock(FreeBB); + llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj"); + CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal); + CGF.EmitBlock(DoneBB); } + llvm::BasicBlock *Cleanup = CGF.getInvokeDest(); + + CGF.Builder.CreateStore(ExnLoc, ExnLocVar); + CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(CGF.getLLVMContext()), + ShouldFreeVar); + + // __cxa_allocate_exception returns a void*; we need to cast this + // to the appropriate type for the object. + const llvm::Type *Ty = CGF.ConvertType(E->getType())->getPointerTo(); + llvm::Value *TypedExnLoc = CGF.Builder.CreateBitCast(ExnLoc, Ty); + + // FIXME: this isn't quite right! If there's a final unelided call + // to a copy constructor, then according to [except.terminate]p1 we + // must call std::terminate() if that constructor throws, because + // technically that copy occurs after the exception expression is + // evaluated but before the exception is caught. But the best way + // to handle that is to teach EmitAggExpr to do the final copy + // differently if it can't be elided. + CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false); + + CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), + ShouldFreeVar); + + // Pop the cleanup block if it's still the top of the cleanup stack. + // Otherwise, temporaries have been created and our cleanup will get + // properly removed in time. + // TODO: this is not very resilient. + if (CGF.getInvokeDest() == Cleanup) + CGF.setInvokeDest(SavedInvokeDest); } // CopyObject - Utility to copy an object. Calls copy constructor as necessary. @@ -270,7 +259,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Now allocate the exception object. const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8; + uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity(); llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this); llvm::Value *ExceptionPtr = @@ -278,17 +267,24 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - llvm::Value *ExceptionPtrPtr = - CreateTempAlloca(ExceptionPtr->getType(), "exception.ptr"); - Builder.CreateStore(ExceptionPtr, ExceptionPtrPtr); - - - CopyObject(*this, E->getSubExpr(), ExceptionPtr, ExceptionPtrPtr); + EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType); - llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); + llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(ThrowType, true); + + // The address of the destructor. If the exception type has a + // trivial destructor (or isn't a record), we just pass null. + llvm::Constant *Dtor = 0; + if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (!Record->hasTrivialDestructor()) { + CXXDestructorDecl *DtorD = Record->getDestructor(getContext()); + Dtor = CGM.GetAddrOfCXXDestructor(DtorD, Dtor_Complete); + Dtor = llvm::ConstantExpr::getBitCast(Dtor, Int8PtrTy); + } + } + if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy); if (getInvokeDest()) { llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); @@ -375,7 +371,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { QualType Ty = Proto->getExceptionType(i); QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, true); SelectorArgs.push_back(EHType); } if (Proto->getNumExceptions()) @@ -498,7 +494,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, // are ignored. QualType CaughtType = C->getCaughtType().getNonReferenceType(); llvm::Value *EHTypeInfo - = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType()); + = CGM.GetAddrOfRTTIDescriptor(CaughtType.getUnqualifiedType(), true); SelectorArgs.push_back(EHTypeInfo); } else { // null indicates catch all @@ -649,38 +645,46 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, } CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { - llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont"); - CGF.EmitBranch(Cont1); CGF.setInvokeDest(PreviousInvokeDest); + llvm::BasicBlock *EndOfCleanup = CGF.Builder.GetInsertBlock(); - CGF.EmitBlock(CleanupHandler); - + // Jump to the beginning of the cleanup. + CGF.Builder.SetInsertPoint(CleanupHandler, CleanupHandler->begin()); + + // The libstdc++ personality function. + // TODO: generalize to work with other libraries. llvm::Constant *Personality = CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty (CGF.VMContext), true), "__gxx_personality_v0"); Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty); + + // %exception = call i8* @llvm.eh.exception() + // Magic intrinsic which tells gives us a handle to the caught + // exception. llvm::Value *llvm_eh_exception = CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception); - llvm::Value *llvm_eh_selector = - CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); - llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); - const llvm::IntegerType *Int8Ty; - const llvm::PointerType *PtrToInt8Ty; - Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext); - // C string type. Used in lots of places. - PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); - llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); + + llvm::Constant *Null = llvm::ConstantPointerNull::get(CGF.PtrToInt8Ty); + + // %ignored = call i32 @llvm.eh.selector(i8* %exception, + // i8* @__gxx_personality_v0, + // i8* null) + // Magic intrinsic which tells LLVM that this invoke landing pad is + // just a cleanup block. llvm::Value *Args[] = { Exc, Personality, Null }; + llvm::Value *llvm_eh_selector = + CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector); CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); - CGF.EmitBlock(CleanupEntryBB); - - CGF.EmitBlock(Cont1); + // And then we fall through into the code that the user put there. + // Jump back to the end of the cleanup. + CGF.Builder.SetInsertPoint(EndOfCleanup); + // Rethrow the exception. if (CGF.getInvokeDest()) { llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont, @@ -688,10 +692,15 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { CGF.EmitBlock(Cont); } else CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc); - CGF.Builder.CreateUnreachable(); - CGF.EmitBlock(Cont); + // Resume inserting where we started, but put the new cleanup + // handler in place. + if (PreviousInsertionBlock) + CGF.Builder.SetInsertPoint(PreviousInsertionBlock); + else + CGF.Builder.ClearInsertionPoint(); + if (CGF.Exceptions) CGF.setInvokeDest(CleanupHandler); } @@ -700,12 +709,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { if (TerminateHandler) return TerminateHandler; - llvm::BasicBlock *Cont = 0; - - if (HaveInsertPoint()) { - Cont = createBasicBlock("cont"); - EmitBranch(Cont); - } + // We don't want to change anything at the current location, so + // save it aside and clear the insert point. + llvm::BasicBlock *SavedInsertBlock = Builder.GetInsertBlock(); + llvm::BasicBlock::iterator SavedInsertPoint = Builder.GetInsertPoint(); + Builder.ClearInsertionPoint(); llvm::Constant *Personality = CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty @@ -735,11 +743,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { TerminateCall->setDoesNotThrow(); Builder.CreateUnreachable(); - // Clear the insertion point to indicate we are in unreachable code. - Builder.ClearInsertionPoint(); - - if (Cont) - EmitBlock(Cont); + // Restore the saved insertion state. + Builder.SetInsertPoint(SavedInsertBlock, SavedInsertPoint); return TerminateHandler; } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 0aa4438..9ade916 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -37,6 +37,13 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(const llvm::Type *Ty, return new llvm::AllocaInst(Ty, 0, Name, AllocaInsertPt); } +void CodeGenFunction::InitTempAlloca(llvm::AllocaInst *Var, + llvm::Value *Init) { + llvm::StoreInst *Store = new llvm::StoreInst(Init, Var); + llvm::BasicBlock *Block = AllocaInsertPt->getParent(); + Block->getInstList().insertAfter(&*AllocaInsertPt, Store); +} + llvm::Value *CodeGenFunction::CreateIRTemp(QualType Ty, const llvm::Twine &Name) { llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertType(Ty), Name); @@ -111,6 +118,23 @@ RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, IsInitializer); } +/// EmitAnyExprToMem - Evaluate an expression into a given memory +/// location. +void CodeGenFunction::EmitAnyExprToMem(const Expr *E, + llvm::Value *Location, + bool IsLocationVolatile, + bool IsInit) { + if (E->getType()->isComplexType()) + EmitComplexExprIntoAddr(E, Location, IsLocationVolatile); + else if (hasAggregateLLVMType(E->getType())) + EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit); + else { + RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); + LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType())); + EmitStoreThroughLValue(RV, LV, E->getType()); + } +} + RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, bool IsInitializer) { bool ShouldDestroyTemporaries = false; @@ -150,16 +174,15 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, PopCXXTemporary(); } } else { - const CXXRecordDecl *BaseClassDecl = 0; + const CXXBaseSpecifierArray *BasePath = 0; const CXXRecordDecl *DerivedClassDecl = 0; if (const CastExpr *CE = dyn_cast<CastExpr>(E->IgnoreParenNoopCasts(getContext()))) { if (CE->getCastKind() == CastExpr::CK_DerivedToBase) { E = CE->getSubExpr(); - - BaseClassDecl = - cast<CXXRecordDecl>(CE->getType()->getAs<RecordType>()->getDecl()); + + BasePath = &CE->getBasePath(); DerivedClassDecl = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); } @@ -185,6 +208,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, { DelayedCleanupBlock Scope(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); // Make sure to jump to the exit block. @@ -193,6 +217,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, if (Exceptions) { EHCleanupBlock Cleanup(*this); EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Val.getAggregateAddr()); } } @@ -201,10 +226,10 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, } // Check if need to perform the derived-to-base cast. - if (BaseClassDecl) { + if (BasePath) { llvm::Value *Derived = Val.getAggregateAddr(); llvm::Value *Base = - GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl, + GetAddressOfBaseClass(Derived, DerivedClassDecl, *BasePath, /*NullCheckValue=*/false); return RValue::get(Base); } @@ -240,18 +265,15 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { if (!CatchUndefined) return; - const llvm::IntegerType *Size_tTy + const llvm::Type *Size_tTy = llvm::IntegerType::get(VMContext, LLVMPointerWidth); Address = Builder.CreateBitCast(Address, PtrToInt8Ty); - const llvm::Type *ResType[] = { - Size_tTy - }; - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, ResType, 1); - const llvm::IntegerType *IntTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().IntTy)); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, &Size_tTy, 1); + const llvm::IntegerType *Int1Ty = llvm::IntegerType::get(VMContext, 1); + // In time, people may want to control this and use a 1 here. - llvm::Value *Arg = llvm::ConstantInt::get(IntTy, 0); + llvm::Value *Arg = llvm::ConstantInt::get(Int1Ty, 0); llvm::Value *C = Builder.CreateCall2(F, Address, Arg); llvm::BasicBlock *Cont = createBasicBlock(); llvm::BasicBlock *Check = createBasicBlock(); @@ -457,6 +479,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E)); case Expr::BinaryOperatorClass: return EmitBinaryOperatorLValue(cast<BinaryOperator>(E)); + case Expr::CompoundAssignOperatorClass: + return EmitCompoundAssignOperatorLValue(cast<CompoundAssignOperator>(E)); case Expr::CallExprClass: case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: @@ -606,63 +630,73 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, QualType ExprType) { const CGBitFieldInfo &Info = LV.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = LV.getBitFieldAddr(); - const llvm::Type *EltTy = - cast<llvm::PointerType>(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertType(ExprType); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // In some cases the bitfield may straddle two memory locations. Currently we - // load the entire bitfield, then do the magic to sign-extend it if - // necessary. This results in somewhat more code than necessary for the common - // case (one load), since two shifts accomplish both the masking and sign - // extension. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "tmp"); + // Compute the result as an OR of all of the individual component accesses. + llvm::Value *Res = 0; + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Shift to proper location. - if (StartBit) - Val = Builder.CreateLShr(Val, StartBit, "bf.lo"); + // Get the field pointer. + llvm::Value *Ptr = LV.getBitFieldBaseAddr(); - // Mask off unused bits. - llvm::Constant *LowMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, LowBits)); - Val = Builder.CreateAnd(Val, LowMask, "bf.lo.cleared"); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // Fetch the high bits if necessary. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - LV.isVolatileQualified(), - "tmp"); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Mask off unused bits. - llvm::Constant *HighMask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, HighBits)); - HighVal = Builder.CreateAnd(HighVal, HighMask, "bf.lo.cleared"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + ExprType.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); - // Shift to proper location and or in to bitfield value. - HighVal = Builder.CreateShl(HighVal, LowBits); - Val = Builder.CreateOr(Val, HighVal, "bf.val"); - } + // Perform the load. + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); - // Sign extend if necessary. - if (Info.IsSigned) { - llvm::Value *ExtraBits = llvm::ConstantInt::get(EltTy, - EltTySize - BitfieldSize); - Val = Builder.CreateAShr(Builder.CreateShl(Val, ExtraBits), - ExtraBits, "bf.val.sext"); + // Shift out unused low bits and mask out unused high bits. + llvm::Value *Val = Load; + if (AI.FieldBitStart) + Val = Builder.CreateLShr(Load, AI.FieldBitStart); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth, + AI.TargetBitWidth), + "bf.clear"); + + // Extend or truncate to the target size. + if (AI.AccessWidth < ResSizeInBits) + Val = Builder.CreateZExt(Val, ResLTy); + else if (AI.AccessWidth > ResSizeInBits) + Val = Builder.CreateTrunc(Val, ResLTy); + + // Shift into place, and OR into the result. + if (AI.TargetBitOffset) + Val = Builder.CreateShl(Val, AI.TargetBitOffset); + Res = Res ? Builder.CreateOr(Res, Val) : Val; } - // The bitfield type and the normal type differ when the storage sizes differ - // (currently just _Bool). - Val = Builder.CreateIntCast(Val, ConvertType(ExprType), false, "tmp"); + // If the bit-field is signed, perform the sign-extension. + // + // FIXME: This can easily be folded into the load of the high bits, which + // could also eliminate the mask of high bits in some situations. + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits), + ExtraBits, "bf.val.sext"); + } - return RValue::get(Val); + return RValue::get(Res); } RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, @@ -783,88 +817,103 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, QualType Ty, llvm::Value **Result) { const CGBitFieldInfo &Info = Dst.getBitFieldInfo(); - unsigned StartBit = Info.Start; - unsigned BitfieldSize = Info.Size; - llvm::Value *Ptr = Dst.getBitFieldAddr(); - const llvm::Type *EltTy = - cast<llvm::PointerType>(Ptr->getType())->getElementType(); - unsigned EltTySize = CGM.getTargetData().getTypeSizeInBits(EltTy); + // Get the output type. + const llvm::Type *ResLTy = ConvertTypeForMem(Ty); + unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); - // Get the new value, cast to the appropriate type and masked to exactly the - // size of the bit-field. + // Get the source value, truncated to the width of the bit-field. llvm::Value *SrcVal = Src.getScalarVal(); - llvm::Value *NewVal = Builder.CreateIntCast(SrcVal, EltTy, false, "tmp"); - llvm::Constant *Mask = llvm::ConstantInt::get(VMContext, - llvm::APInt::getLowBitsSet(EltTySize, BitfieldSize)); - NewVal = Builder.CreateAnd(NewVal, Mask, "bf.value"); + + if (Ty->isBooleanType()) + SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false); + + SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits, + Info.getSize()), + "bf.value"); // Return the new value of the bit-field, if requested. if (Result) { // Cast back to the proper type for result. - const llvm::Type *SrcTy = SrcVal->getType(); - llvm::Value *SrcTrunc = Builder.CreateIntCast(NewVal, SrcTy, false, - "bf.reload.val"); + const llvm::Type *SrcTy = Src.getScalarVal()->getType(); + llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false, + "bf.reload.val"); // Sign extend if necessary. - if (Info.IsSigned) { - unsigned SrcTySize = CGM.getTargetData().getTypeSizeInBits(SrcTy); - llvm::Value *ExtraBits = llvm::ConstantInt::get(SrcTy, - SrcTySize - BitfieldSize); - SrcTrunc = Builder.CreateAShr(Builder.CreateShl(SrcTrunc, ExtraBits), - ExtraBits, "bf.reload.sext"); + if (Info.isSigned()) { + unsigned ExtraBits = ResSizeInBits - Info.getSize(); + if (ExtraBits) + ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits), + ExtraBits, "bf.reload.sext"); } - *Result = SrcTrunc; + *Result = ReloadVal; } - // In some cases the bitfield may straddle two memory locations. Emit the low - // part first and check to see if the high needs to be done. - unsigned LowBits = std::min(BitfieldSize, EltTySize - StartBit); - llvm::Value *LowVal = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(), - "bf.prev.low"); - - // Compute the mask for zero-ing the low part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, - ~llvm::APInt::getBitsSet(EltTySize, StartBit, StartBit + LowBits)); + // Iterate over the components, writing each piece to memory. + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); - // Compute the new low part as - // LowVal = (LowVal & InvMask) | (NewVal << StartBit), - // with the shift of NewVal implicitly stripping the high bits. - llvm::Value *NewLowVal = - Builder.CreateShl(NewVal, StartBit, "bf.value.lo"); - LowVal = Builder.CreateAnd(LowVal, InvMask, "bf.prev.lo.cleared"); - LowVal = Builder.CreateOr(LowVal, NewLowVal, "bf.new.lo"); + // Get the field pointer. + llvm::Value *Ptr = Dst.getBitFieldBaseAddr(); - // Write back. - Builder.CreateStore(LowVal, Ptr, Dst.isVolatileQualified()); + // Only offset by the field index if used, so that incoming values are not + // required to be structures. + if (AI.FieldIndex) + Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); - // If the low part doesn't cover the bitfield emit a high part. - if (LowBits < BitfieldSize) { - unsigned HighBits = BitfieldSize - LowBits; - llvm::Value *HighPtr = Builder.CreateGEP(Ptr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(VMContext), 1), "bf.ptr.hi"); - llvm::Value *HighVal = Builder.CreateLoad(HighPtr, - Dst.isVolatileQualified(), - "bf.prev.hi"); - - // Compute the mask for zero-ing the high part of this bitfield. - llvm::Constant *InvMask = - llvm::ConstantInt::get(VMContext, ~llvm::APInt::getLowBitsSet(EltTySize, - HighBits)); + // Offset by the byte offset, if used. + if (AI.FieldByteOffset) { + const llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(VMContext); + Ptr = Builder.CreateBitCast(Ptr, i8PTy); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + } - // Compute the new high part as - // HighVal = (HighVal & InvMask) | (NewVal lshr LowBits), - // where the high bits of NewVal have already been cleared and the - // shift stripping the low bits. - llvm::Value *NewHighVal = - Builder.CreateLShr(NewVal, LowBits, "bf.value.high"); - HighVal = Builder.CreateAnd(HighVal, InvMask, "bf.prev.hi.cleared"); - HighVal = Builder.CreateOr(HighVal, NewHighVal, "bf.new.hi"); + // Cast to the access type. + const llvm::Type *PTy = llvm::Type::getIntNPtrTy(VMContext, AI.AccessWidth, + Ty.getAddressSpace()); + Ptr = Builder.CreateBitCast(Ptr, PTy); + + // Extract the piece of the bit-field value to write in this access, limited + // to the values that are part of this access. + llvm::Value *Val = SrcVal; + if (AI.TargetBitOffset) + Val = Builder.CreateLShr(Val, AI.TargetBitOffset); + Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits, + AI.TargetBitWidth)); + + // Extend or truncate to the access size. + const llvm::Type *AccessLTy = + llvm::Type::getIntNTy(VMContext, AI.AccessWidth); + if (ResSizeInBits < AI.AccessWidth) + Val = Builder.CreateZExt(Val, AccessLTy); + else if (ResSizeInBits > AI.AccessWidth) + Val = Builder.CreateTrunc(Val, AccessLTy); + + // Shift into the position in memory. + if (AI.FieldBitStart) + Val = Builder.CreateShl(Val, AI.FieldBitStart); + + // If necessary, load and OR in bits that are outside of the bit-field. + if (AI.TargetBitWidth != AI.AccessWidth) { + llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Load->setAlignment(AI.AccessAlignment); + + // Compute the mask for zeroing the bits that are part of the bit-field. + llvm::APInt InvMask = + ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart, + AI.FieldBitStart + AI.TargetBitWidth); + + // Apply the mask and OR in to the value to write. + Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val); + } - // Write back. - Builder.CreateStore(HighVal, HighPtr, Dst.isVolatileQualified()); + // Write the value. + llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr, + Dst.isVolatileQualified()); + if (AI.AccessAlignment) + Store->setAlignment(AI.AccessAlignment); } } @@ -1084,6 +1133,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>(); llvm::Value *V = LocalDeclMap[VD]; + if (!V && getContext().getLangOptions().CPlusPlus && + VD->isStaticLocal()) + V = CGM.getStaticLocalDeclAddress(VD); assert(V && "DeclRefExpr not entered in LocalDeclMap?"); Qualifiers Quals = MakeQualifiers(E->getType()); @@ -1474,19 +1526,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue, const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(Field->getParent()); const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - // FIXME: CodeGenTypes should expose a method to get the appropriate type for - // FieldTy (the appropriate type is ABI-dependent). - const llvm::Type *FieldTy = - CGM.getTypes().ConvertTypeForMem(Field->getType()); - const llvm::PointerType *BaseTy = - cast<llvm::PointerType>(BaseValue->getType()); - unsigned AS = BaseTy->getAddressSpace(); - BaseValue = Builder.CreateBitCast(BaseValue, - llvm::PointerType::get(FieldTy, AS)); - llvm::Value *V = Builder.CreateConstGEP1_32(BaseValue, Info.FieldNo); - - return LValue::MakeBitfield(V, Info, + return LValue::MakeBitfield(BaseValue, Info, Field->getType().getCVRQualifiers()|CVRQualifiers); } @@ -1548,12 +1588,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ const Expr* InitExpr = E->getInitializer(); LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); - if (E->getType()->isComplexType()) - EmitComplexExprIntoAddr(InitExpr, DeclPtr, false); - else if (hasAggregateLLVMType(E->getType())) - EmitAnyExpr(InitExpr, DeclPtr, false); - else - EmitStoreThroughLValue(EmitAnyExpr(InitExpr), Result, E->getType()); + EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false); return Result; } @@ -1647,27 +1682,19 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { E->getSubExpr()->getType()->getAs<RecordType>(); CXXRecordDecl *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl()); - - const RecordType *BaseClassTy = E->getType()->getAs<RecordType>(); - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl()); LValue LV = EmitLValue(E->getSubExpr()); // Perform the derived-to-base conversion llvm::Value *Base = GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl, - BaseClassDecl, /*NullCheckValue=*/false); + E->getBasePath(), /*NullCheckValue=*/false); return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); } case CastExpr::CK_ToUnion: return EmitAggExprToLValue(E); case CastExpr::CK_BaseToDerived: { - const RecordType *BaseClassTy = - E->getSubExpr()->getType()->getAs<RecordType>(); - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(BaseClassTy->getDecl()); - const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>(); CXXRecordDecl *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl()); @@ -1676,8 +1703,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the base-to-derived conversion llvm::Value *Derived = - GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl, - DerivedClassDecl, /*NullCheckValue=*/false); + GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, + E->getBasePath(),/*NullCheckValue=*/false); return LValue::MakeAddr(Derived, MakeQualifiers(E->getType())); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 4d5160f..d1b0dff 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -263,7 +263,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) { if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); else @@ -321,6 +321,11 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { (void) MPT; assert(MPT->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); + + // The creation of member function pointers has no side effects; if + // there is no destination pointer, we have nothing to do. + if (!DestPtr) + return; const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr()); const CXXMethodDecl *MD = @@ -329,17 +334,23 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { const llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); llvm::Value *FuncPtr; if (MD->isVirtual()) { - int64_t Index = CGF.CGM.getVTables().getMethodVtableIndex(MD); + int64_t Index = CGF.CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGF.CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - FuncPtr = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + FuncPtr = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *Ty = @@ -738,6 +749,14 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { + if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty()) + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 1fd1da8..b57cdc9 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -205,20 +205,20 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); EmitBlock(FnVirtual); - const llvm::Type *VtableTy = + const llvm::Type *VTableTy = FTy->getPointerTo()->getPointerTo(); - llvm::Value *Vtable = Builder.CreateBitCast(This, VtableTy->getPointerTo()); - Vtable = Builder.CreateLoad(Vtable); + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); + VTable = Builder.CreateLoad(VTable); - Vtable = Builder.CreateBitCast(Vtable, Int8PtrTy); - llvm::Value *VtableOffset = + VTable = Builder.CreateBitCast(VTable, Int8PtrTy); + llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - Vtable = Builder.CreateGEP(Vtable, VtableOffset, "fn"); - Vtable = Builder.CreateBitCast(Vtable, VtableTy); + VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); + VTable = Builder.CreateBitCast(VTable, VTableTy); - llvm::Value *VirtualFn = Builder.CreateLoad(Vtable, "virtualfn"); + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); EmitBranch(FnEnd); EmitBlock(FnNonVirtual); @@ -316,17 +316,22 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(Dest, BasePtr); + Builder.CreateBitCast(Dest, BasePtr); EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, E->arg_begin(), E->arg_end()); } - else + else { + CXXCtorType Type = + (E->getConstructionKind() == CXXConstructExpr::CK_Complete) + ? Ctor_Complete : Ctor_Base; + bool ForVirtualBase = + E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; + // Call the constructor. - EmitCXXConstructorCall(CD, - E->isBaseInitialization()? Ctor_Base : Ctor_Complete, - Dest, + EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest, E->arg_begin(), E->arg_end()); + } } static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { @@ -460,18 +465,20 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *NewPtr, llvm::Value *NumElements) { if (E->isArray()) { - if (CXXConstructorDecl *Ctor = E->getConstructor()) - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - return; + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + if (!Ctor->getParent()->hasTrivialConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + return; + } } QualType AllocType = E->getAllocatedType(); if (CXXConstructorDecl *Ctor = E->getConstructor()) { - CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, + NewPtr, E->constructor_arg_begin(), E->constructor_arg_end()); return; @@ -760,7 +767,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { // The dtor took care of deleting the object. ShouldCallDelete = false; } else - EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + Ptr); } } } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 172a77d..2595ff0 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -27,359 +27,387 @@ using namespace clang; using namespace CodeGen; -namespace { +//===----------------------------------------------------------------------===// +// ConstStructBuilder +//===----------------------------------------------------------------------===// + +namespace { class ConstStructBuilder { CodeGenModule &CGM; CodeGenFunction *CGF; bool Packed; - unsigned NextFieldOffsetInBytes; - unsigned LLVMStructAlignment; - std::vector<llvm::Constant *> Elements; - +public: + static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, + InitListExpr *ILE); + +private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), LLVMStructAlignment(1) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - uint64_t FieldOffsetInBytes = FieldOffset / 8; + llvm::Constant *InitExpr); - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes - && "Field offset mismatch!"); + bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitExpr); - // Emit the field. - llvm::Constant *C = CGM.EmitConstantExpr(InitExpr, Field->getType(), CGF); - if (!C) - return false; + void AppendPadding(uint64_t NumBytes); - unsigned FieldAlignment = getAlignment(C); + void AppendTailPadding(uint64_t RecordSize); - // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + void ConvertStructToPacked(); + + bool Build(InitListExpr *ILE); - if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { - assert(!Packed && "Alignment is wrong even with a packed struct!"); + unsigned getAlignment(const llvm::Constant *C) const { + if (Packed) return 1; + return CGM.getTargetData().getABITypeAlignment(C->getType()); + } - // Convert the struct to a packed struct. - ConvertStructToPacked(); - - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + uint64_t getSizeInBytes(const llvm::Constant *C) const { + return CGM.getTargetData().getTypeAllocSize(C->getType()); + } +}; - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { - // We need to append padding. - AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); +bool ConstStructBuilder:: +AppendField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + uint64_t FieldOffsetInBytes = FieldOffset / 8; - assert(NextFieldOffsetInBytes == FieldOffsetInBytes && - "Did not add enough padding!"); + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + && "Field offset mismatch!"); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; - } + // Emit the field. + if (!InitCst) + return false; - // Add the field. - Elements.push_back(C); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C); - - if (Packed) - assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); - else - LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); + unsigned FieldAlignment = getAlignment(InitCst); - return true; - } + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); - bool AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, - const Expr *InitExpr) { - llvm::ConstantInt *CI = - cast_or_null<llvm::ConstantInt>(CGM.EmitConstantExpr(InitExpr, - Field->getType(), - CGF)); - // FIXME: Can this ever happen? - if (!CI) - return false; - - if (FieldOffset > NextFieldOffsetInBytes * 8) { - // We need to add padding. - uint64_t NumBytes = - llvm::RoundUpToAlignment(FieldOffset - - NextFieldOffsetInBytes * 8, 8) / 8; + if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + assert(!Packed && "Alignment is wrong even with a packed struct!"); - AppendPadding(NumBytes); - } + // Convert the struct to a packed struct. + ConvertStructToPacked(); + + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // We need to append padding. + AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); - llvm::APInt FieldValue = CI->getValue(); + assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + "Did not add enough padding!"); - // Promote the size of FieldValue if necessary - // FIXME: This should never occur, but currently it can because initializer - // constants are cast to bool, and because clang is not enforcing bitfield - // width limits. - if (FieldSize > FieldValue.getBitWidth()) - FieldValue.zext(FieldSize); + AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + } - // Truncate the size of FieldValue to the bit field size. - if (FieldSize < FieldValue.getBitWidth()) - FieldValue.trunc(FieldSize); + // Add the field. + Elements.push_back(InitCst); + NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + + getSizeInBytes(InitCst); + + if (Packed) + assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + else + LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); - if (FieldOffset < NextFieldOffsetInBytes * 8) { - // Either part of the field or the entire field can go into the previous - // byte. - assert(!Elements.empty() && "Elements can't be empty!"); + return true; +} - unsigned BitsInPreviousByte = - NextFieldOffsetInBytes * 8 - FieldOffset; +bool ConstStructBuilder:: + AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, + llvm::Constant *InitCst) { + llvm::ConstantInt *CI = cast_or_null<llvm::ConstantInt>(InitCst); + // FIXME: Can this ever happen? + if (!CI) + return false; - bool FitsCompletelyInPreviousByte = - BitsInPreviousByte >= FieldValue.getBitWidth(); + if (FieldOffset > NextFieldOffsetInBytes * 8) { + // We need to add padding. + uint64_t NumBytes = + llvm::RoundUpToAlignment(FieldOffset - + NextFieldOffsetInBytes * 8, 8) / 8; - llvm::APInt Tmp = FieldValue; + AppendPadding(NumBytes); + } - if (!FitsCompletelyInPreviousByte) { - unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); - if (CGM.getTargetData().isBigEndian()) { - Tmp = Tmp.lshr(NewFieldWidth); - Tmp.trunc(BitsInPreviousByte); + llvm::APInt FieldValue = CI->getValue(); - // We want the remaining high bits. - FieldValue.trunc(NewFieldWidth); - } else { - Tmp.trunc(BitsInPreviousByte); + // Promote the size of FieldValue if necessary + // FIXME: This should never occur, but currently it can because initializer + // constants are cast to bool, and because clang is not enforcing bitfield + // width limits. + if (FieldSize > FieldValue.getBitWidth()) + FieldValue.zext(FieldSize); - // We want the remaining low bits. - FieldValue = FieldValue.lshr(BitsInPreviousByte); - FieldValue.trunc(NewFieldWidth); - } - } + // Truncate the size of FieldValue to the bit field size. + if (FieldSize < FieldValue.getBitWidth()) + FieldValue.trunc(FieldSize); - Tmp.zext(8); - if (CGM.getTargetData().isBigEndian()) { - if (FitsCompletelyInPreviousByte) - Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); - } else { - Tmp = Tmp.shl(8 - BitsInPreviousByte); - } + if (FieldOffset < NextFieldOffsetInBytes * 8) { + // Either part of the field or the entire field can go into the previous + // byte. + assert(!Elements.empty() && "Elements can't be empty!"); - // Or in the bits that go into the previous byte. - if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) - Tmp |= Val->getValue(); - else - assert(isa<llvm::UndefValue>(Elements.back())); + unsigned BitsInPreviousByte = + NextFieldOffsetInBytes * 8 - FieldOffset; - Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); + bool FitsCompletelyInPreviousByte = + BitsInPreviousByte >= FieldValue.getBitWidth(); - if (FitsCompletelyInPreviousByte) - return true; - } + llvm::APInt Tmp = FieldValue; - while (FieldValue.getBitWidth() > 8) { - llvm::APInt Tmp; + if (!FitsCompletelyInPreviousByte) { + unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; if (CGM.getTargetData().isBigEndian()) { - // We want the high bits. - Tmp = FieldValue; - Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); - Tmp.trunc(8); + Tmp = Tmp.lshr(NewFieldWidth); + Tmp.trunc(BitsInPreviousByte); + + // We want the remaining high bits. + FieldValue.trunc(NewFieldWidth); } else { - // We want the low bits. - Tmp = FieldValue; - Tmp.trunc(8); + Tmp.trunc(BitsInPreviousByte); - FieldValue = FieldValue.lshr(8); + // We want the remaining low bits. + FieldValue = FieldValue.lshr(BitsInPreviousByte); + FieldValue.trunc(NewFieldWidth); } - - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); - NextFieldOffsetInBytes++; - - FieldValue.trunc(FieldValue.getBitWidth() - 8); } - assert(FieldValue.getBitWidth() > 0 && - "Should have at least one bit left!"); - assert(FieldValue.getBitWidth() <= 8 && - "Should not have more than a byte left!"); + Tmp.zext(8); + if (CGM.getTargetData().isBigEndian()) { + if (FitsCompletelyInPreviousByte) + Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); + } else { + Tmp = Tmp.shl(8 - BitsInPreviousByte); + } - if (FieldValue.getBitWidth() < 8) { - if (CGM.getTargetData().isBigEndian()) { - unsigned BitWidth = FieldValue.getBitWidth(); + // Or in the bits that go into the previous byte. + if (llvm::ConstantInt *Val = dyn_cast<llvm::ConstantInt>(Elements.back())) + Tmp |= Val->getValue(); + else + assert(isa<llvm::UndefValue>(Elements.back())); - FieldValue.zext(8); - FieldValue = FieldValue << (8 - BitWidth); - } else - FieldValue.zext(8); - } + Elements.back() = llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp); - // Append the last element. - Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), - FieldValue)); - NextFieldOffsetInBytes++; - return true; + if (FitsCompletelyInPreviousByte) + return true; } - void AppendPadding(uint64_t NumBytes) { - if (!NumBytes) - return; + while (FieldValue.getBitWidth() > 8) { + llvm::APInt Tmp; + + if (CGM.getTargetData().isBigEndian()) { + // We want the high bits. + Tmp = FieldValue; + Tmp = Tmp.lshr(Tmp.getBitWidth() - 8); + Tmp.trunc(8); + } else { + // We want the low bits. + Tmp = FieldValue; + Tmp.trunc(8); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + FieldValue = FieldValue.lshr(8); + } - llvm::Constant *C = llvm::UndefValue::get(Ty); - Elements.push_back(C); - assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); + NextFieldOffsetInBytes++; - NextFieldOffsetInBytes += getSizeInBytes(C); + FieldValue.trunc(FieldValue.getBitWidth() - 8); } - void AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); + assert(FieldValue.getBitWidth() > 0 && + "Should have at least one bit left!"); + assert(FieldValue.getBitWidth() <= 8 && + "Should not have more than a byte left!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + if (FieldValue.getBitWidth() < 8) { + if (CGM.getTargetData().isBigEndian()) { + unsigned BitWidth = FieldValue.getBitWidth(); - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; - AppendPadding(NumPadBytes); + FieldValue.zext(8); + FieldValue = FieldValue << (8 - BitWidth); + } else + FieldValue.zext(8); } - void ConvertStructToPacked() { - std::vector<llvm::Constant *> PackedElements; - uint64_t ElementOffsetInBytes = 0; + // Append the last element. + Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), + FieldValue)); + NextFieldOffsetInBytes++; + return true; +} - for (unsigned i = 0, e = Elements.size(); i != e; ++i) { - llvm::Constant *C = Elements[i]; +void ConstStructBuilder::AppendPadding(uint64_t NumBytes) { + if (!NumBytes) + return; - unsigned ElementAlign = - CGM.getTargetData().getABITypeAlignment(C->getType()); - uint64_t AlignedElementOffsetInBytes = - llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { - // We need some padding. - uint64_t NumBytes = - AlignedElementOffsetInBytes - ElementOffsetInBytes; + llvm::Constant *C = llvm::UndefValue::get(Ty); + Elements.push_back(C); + assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); - const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + NextFieldOffsetInBytes += getSizeInBytes(C); +} - llvm::Constant *Padding = llvm::UndefValue::get(Ty); - PackedElements.push_back(Padding); - ElementOffsetInBytes += getSizeInBytes(Padding); - } +void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) { + assert(RecordSize % 8 == 0 && "Invalid record size!"); - PackedElements.push_back(C); - ElementOffsetInBytes += getSizeInBytes(C); - } + uint64_t RecordSizeInBytes = RecordSize / 8; + assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - assert(ElementOffsetInBytes == NextFieldOffsetInBytes && - "Packing the struct changed its size!"); + unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + AppendPadding(NumPadBytes); +} - Elements = PackedElements; - LLVMStructAlignment = 1; - Packed = true; - } - - bool Build(InitListExpr *ILE) { - RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - - unsigned FieldNo = 0; - unsigned ElementNo = 0; - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); - ElementNo < ILE->getNumInits() && Field != FieldEnd; - ++Field, ++FieldNo) { - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) - continue; - - if (Field->isBitField()) { - if (!Field->getIdentifier()) - continue; - - if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } else { - if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), - ILE->getInit(ElementNo))) - return false; - } +void ConstStructBuilder::ConvertStructToPacked() { + std::vector<llvm::Constant *> PackedElements; + uint64_t ElementOffsetInBytes = 0; - ElementNo++; - } + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + llvm::Constant *C = Elements[i]; - uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + unsigned ElementAlign = + CGM.getTargetData().getABITypeAlignment(C->getType()); + uint64_t AlignedElementOffsetInBytes = + llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); - if (NextFieldOffsetInBytes > LayoutSizeInBytes) { - // If the struct is bigger than the size of the record type, - // we must have a flexible array member at the end. - assert(RD->hasFlexibleArrayMember() && - "Must have flexible array member if struct is bigger than type!"); - - // No tail padding is necessary. - return true; - } + if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + // We need some padding. + uint64_t NumBytes = + AlignedElementOffsetInBytes - ElementOffsetInBytes; - uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, - LLVMStructAlignment); + const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + if (NumBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumBytes); - // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInBytes <= LayoutSizeInBytes && - LLVMSizeInBytes > LayoutSizeInBytes) { - assert(!Packed && "Size mismatch!"); - - ConvertStructToPacked(); - assert(NextFieldOffsetInBytes == LayoutSizeInBytes && - "Converting to packed did not help!"); + llvm::Constant *Padding = llvm::UndefValue::get(Ty); + PackedElements.push_back(Padding); + ElementOffsetInBytes += getSizeInBytes(Padding); } - // Append tail padding if necessary. - AppendTailPadding(Layout.getSize()); - - assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && - "Tail padding mismatch!"); - - return true; + PackedElements.push_back(C); + ElementOffsetInBytes += getSizeInBytes(C); } - unsigned getAlignment(const llvm::Constant *C) const { - if (Packed) - return 1; + assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + "Packing the struct changed its size!"); - return CGM.getTargetData().getABITypeAlignment(C->getType()); + Elements = PackedElements; + LLVMStructAlignment = 1; + Packed = true; +} + +bool ConstStructBuilder::Build(InitListExpr *ILE) { + RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + + unsigned FieldNo = 0; + unsigned ElementNo = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + + // If this is a union, skip all the fields that aren't being initialized. + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + continue; + + // Don't emit anonymous bitfields, they just affect layout. + if (Field->isBitField() && !Field->getIdentifier()) + continue; + + // Get the initializer. A struct can include fields without initializers, + // we just use explicit null values for them. + llvm::Constant *EltInit; + if (ElementNo < ILE->getNumInits()) + EltInit = CGM.EmitConstantExpr(ILE->getInit(ElementNo++), + Field->getType(), CGF); + else + EltInit = CGM.EmitNullConstant(Field->getType()); + + if (!Field->isBitField()) { + // Handle non-bitfield members. + if (!AppendField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } else { + // Otherwise we have a bitfield. + if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo), EltInit)) + return false; + } } - uint64_t getSizeInBytes(const llvm::Constant *C) const { - return CGM.getTargetData().getTypeAllocSize(C->getType()); + uint64_t LayoutSizeInBytes = Layout.getSize() / 8; + + if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + // If the struct is bigger than the size of the record type, + // we must have a flexible array member at the end. + assert(RD->hasFlexibleArrayMember() && + "Must have flexible array member if struct is bigger than type!"); + + // No tail padding is necessary. + return true; } -public: - static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, - InitListExpr *ILE) { - ConstStructBuilder Builder(CGM, CGF); + uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, + LLVMStructAlignment); - if (!Builder.Build(ILE)) - return 0; + // Check if we need to convert the struct to a packed struct. + if (NextFieldOffsetInBytes <= LayoutSizeInBytes && + LLVMSizeInBytes > LayoutSizeInBytes) { + assert(!Packed && "Size mismatch!"); + + ConvertStructToPacked(); + assert(NextFieldOffsetInBytes <= LayoutSizeInBytes && + "Converting to packed did not help!"); + } - llvm::Constant *Result = - llvm::ConstantStruct::get(CGM.getLLVMContext(), - Builder.Elements, Builder.Packed); + // Append tail padding if necessary. + AppendTailPadding(Layout.getSize()); - assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, - Builder.getAlignment(Result)) == - Builder.getSizeInBytes(Result) && "Size mismatch!"); + assert(Layout.getSize() / 8 == NextFieldOffsetInBytes && + "Tail padding mismatch!"); - return Result; - } -}; + return true; +} + +llvm::Constant *ConstStructBuilder:: + BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, InitListExpr *ILE) { + ConstStructBuilder Builder(CGM, CGF); + + if (!Builder.Build(ILE)) + return 0; + + llvm::Constant *Result = + llvm::ConstantStruct::get(CGM.getLLVMContext(), + Builder.Elements, Builder.Packed); + + assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, + Builder.getAlignment(Result)) == + Builder.getSizeInBytes(Result) && "Size mismatch!"); + + return Result; +} + +//===----------------------------------------------------------------------===// +// ConstExprEmitter +//===----------------------------------------------------------------------===// + class ConstExprEmitter : public StmtVisitor<ConstExprEmitter, llvm::Constant*> { CodeGenModule &CGM; @@ -418,13 +446,18 @@ public: // Get the function pointer (or index if this is a virtual function). if (MD->isVirtual()) { - uint64_t Index = CGM.getVTables().getMethodVtableIndex(MD); + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGM.getContext().Target.getPointerWidth(0) / 8; + // Itanium C++ ABI 2.3: // For a non-virtual function, this field is a simple function pointer. // For a virtual function, it is 1 plus the virtual table offset // (in bytes) of the function, represented as a ptrdiff_t. - Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1); + Values[0] = llvm::ConstantInt::get(PtrDiffTy, + (Index * PointerWidthInBytes) + 1); } else { const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *Ty = @@ -528,8 +561,6 @@ public: const MemberPointerType *DestTy = E->getType()->getAs<MemberPointerType>(); - const CXXRecordDecl *BaseClass = - cast<CXXRecordDecl>(cast<RecordType>(SrcTy->getClass())->getDecl()); const CXXRecordDecl *DerivedClass = cast<CXXRecordDecl>(cast<RecordType>(DestTy->getClass())->getDecl()); @@ -543,7 +574,7 @@ public: // Check if we need to update the adjustment. if (llvm::Constant *Offset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, BaseClass)) { + CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) { llvm::Constant *Values[2]; Values[0] = CS->getOperand(0); @@ -587,17 +618,15 @@ public: } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { - std::vector<llvm::Constant*> Elts; - const llvm::ArrayType *AType = - cast<llvm::ArrayType>(ConvertType(ILE->getType())); unsigned NumInitElements = ILE->getNumInits(); - // FIXME: Check for wide strings - // FIXME: Check for NumInitElements exactly equal to 1?? - if (NumInitElements > 0 && + if (NumInitElements == 1 && (isa<StringLiteral>(ILE->getInit(0)) || - isa<ObjCEncodeExpr>(ILE->getInit(0))) && - ILE->getType()->getArrayElementTypeNoTypeQual()->isCharType()) + isa<ObjCEncodeExpr>(ILE->getInit(0)))) return Visit(ILE->getInit(0)); + + std::vector<llvm::Constant*> Elts; + const llvm::ArrayType *AType = + cast<llvm::ArrayType>(ConvertType(ILE->getType())); const llvm::Type *ElemTy = AType->getElementType(); unsigned NumElements = AType->getNumElements(); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index d1c0f8d..9849688 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -133,6 +133,7 @@ public: CGF.getContext().typesAreCompatible( E->getArgType1(), E->getArgType2())); } + Value *VisitOffsetOfExpr(const OffsetOfExpr *E); Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); @@ -242,7 +243,7 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); - + // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); @@ -314,6 +315,10 @@ public: } BinOpInfo EmitBinOps(const BinaryOperator *E); + LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*F)(const BinOpInfo &), + Value *&BitFieldResult); + Value *EmitCompoundAssign(const CompoundAssignOperator *E, Value *(ScalarExprEmitter::*F)(const BinOpInfo &)); @@ -818,16 +823,12 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return Visit(const_cast<Expr*>(E)); case CastExpr::CK_BaseToDerived: { - const CXXRecordDecl *BaseClassDecl = - E->getType()->getCXXRecordDeclForPointerType(); const CXXRecordDecl *DerivedClassDecl = DestTy->getCXXRecordDeclForPointerType(); - Value *Src = Visit(const_cast<Expr*>(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl, - NullCheckValue); + return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_UncheckedDerivedToBase: case CastExpr::CK_DerivedToBase: { @@ -836,15 +837,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CXXRecordDecl *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl()); - const RecordType *BaseClassTy = - DestTy->getAs<PointerType>()->getPointeeType()->getAs<RecordType>(); - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseClassTy->getDecl()); - - Value *Src = Visit(const_cast<Expr*>(E)); - - bool NullCheckValue = ShouldNullCheckClassCastValue(CE); - return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl, - NullCheckValue); + return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl, + CE->getBasePath(), + ShouldNullCheckClassCastValue(CE)); } case CastExpr::CK_Dynamic: { Value *V = Visit(const_cast<Expr*>(E)); @@ -894,7 +889,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { std::swap(DerivedDecl, BaseDecl); if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, BaseDecl)) { + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + CE->getBasePath())) { if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) Src = Builder.CreateSub(Src, Adj, "adj"); else @@ -1035,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } +Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) { + Expr::EvalResult Result; + if(E->Evaluate(Result, CGF.getContext())) + return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + + // FIXME: Cannot support code generation for non-constant offsetof. + unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error, + "cannot compile non-constant __builtin_offsetof"); + CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()), + DiagID) + << E->getSourceRange(); + + return llvm::Constant::getNullValue(ConvertType(E->getType())); +} + /// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * @@ -1103,22 +1114,24 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { return Result; } -Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, - Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { - bool Ignore = TestAndClearIgnoreResultAssign(); +LValue ScalarExprEmitter::EmitCompoundAssignLValue( + const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &), + Value *&BitFieldResult) { QualType LHSTy = E->getLHS()->getType(); - + BitFieldResult = 0; BinOpInfo OpInfo; - + if (E->getComputationResultType()->isAnyComplexType()) { // This needs to go through the complex expression emitter, but it's a tad // complicated to do that... I'm leaving it out for now. (Note that we do // actually need the imaginary part of the RHS for multiplication and // division.) CGF.ErrorUnsupported(E, "complex compound assignment"); - return llvm::UndefValue::get(CGF.ConvertType(E->getType())); + llvm::UndefValue::get(CGF.ConvertType(E->getType())); + return LValue(); } - + // Emit the RHS first. __block variables need to have the rhs evaluated // first, plus this should improve codegen a little. OpInfo.RHS = Visit(E->getRHS()); @@ -1129,13 +1142,13 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, OpInfo.LHS = EmitLoadOfLValue(LHSLV, LHSTy); OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, E->getComputationLHSType()); - + // Expand the binary operator. Value *Result = (this->*Func)(OpInfo); - + // Convert the result back to the LHS type. Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy); - + // Store the result value into the LHS lvalue. Bit-fields are handled // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the @@ -1144,11 +1157,23 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, if (!LHSLV.isVolatileQualified()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy, &Result); - return Result; + BitFieldResult = Result; + return LHSLV; } else CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy); } else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy); + return LHSLV; +} + +Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, + Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) { + bool Ignore = TestAndClearIgnoreResultAssign(); + Value *BitFieldResult; + LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult); + if (BitFieldResult) + return BitFieldResult; + if (Ignore) return 0; return EmitLoadOfLValue(LHSLV, E->getType()); @@ -1914,3 +1939,53 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { return LV; } + +LValue CodeGenFunction::EmitCompoundAssignOperatorLValue( + const CompoundAssignOperator *E) { + ScalarExprEmitter Scalar(*this); + Value *BitFieldResult = 0; + switch (E->getOpcode()) { +#define COMPOUND_OP(Op) \ + case BinaryOperator::Op##Assign: \ + return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \ + BitFieldResult) + COMPOUND_OP(Mul); + COMPOUND_OP(Div); + COMPOUND_OP(Rem); + COMPOUND_OP(Add); + COMPOUND_OP(Sub); + COMPOUND_OP(Shl); + COMPOUND_OP(Shr); + COMPOUND_OP(And); + COMPOUND_OP(Xor); + COMPOUND_OP(Or); +#undef COMPOUND_OP + + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::LAnd: + case BinaryOperator::LOr: + case BinaryOperator::Assign: + case BinaryOperator::Comma: + assert(false && "Not valid compound assignment operators"); + break; + } + + llvm_unreachable("Unhandled compound assignment operator"); +} diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 206d438..3359250 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -53,31 +53,36 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { // arguments in generic code. CGObjCRuntime &Runtime = CGM.getObjCRuntime(); - const Expr *ReceiverExpr = E->getReceiver(); bool isSuperMessage = false; bool isClassMessage = false; + ObjCInterfaceDecl *OID = 0; // Find the receiver - llvm::Value *Receiver; - if (!ReceiverExpr) { - const ObjCInterfaceDecl *OID = E->getClassInfo().Decl; - - // Very special case, super send in class method. The receiver is - // self (the class object) and the send uses super semantics. - if (!OID) { - assert(E->getClassName()->isStr("super") && - "Unexpected missing class interface in message send."); - isSuperMessage = true; - Receiver = LoadObjCSelf(); - } else { - Receiver = Runtime.GetClass(Builder, OID); - } - + llvm::Value *Receiver = 0; + switch (E->getReceiverKind()) { + case ObjCMessageExpr::Instance: + Receiver = EmitScalarExpr(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: { + const ObjCInterfaceType *IFace + = E->getClassReceiver()->getAs<ObjCInterfaceType>(); + OID = IFace->getDecl(); + assert(IFace && "Invalid Objective-C class message send"); + Receiver = Runtime.GetClass(Builder, OID); isClassMessage = true; - } else if (isa<ObjCSuperExpr>(E->getReceiver())) { + break; + } + + case ObjCMessageExpr::SuperInstance: + Receiver = LoadObjCSelf(); isSuperMessage = true; + break; + + case ObjCMessageExpr::SuperClass: Receiver = LoadObjCSelf(); - } else { - Receiver = EmitScalarExpr(E->getReceiver()); + isSuperMessage = true; + isClassMessage = true; + break; } CallArgList Args; @@ -98,7 +103,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) { } return Runtime.GenerateMessageSend(*this, E->getType(), E->getSelector(), - Receiver, isClassMessage, Args, + Receiver, Args, OID, E->getMethodDecl()); } @@ -148,19 +153,21 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); const ObjCPropertyDecl *PD = PID->getPropertyDecl(); + bool IsAtomic = + !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); // FIXME: This is rather murky, we create this here since they will not have // been created by Sema for us. OMD->createImplicitParams(getContext(), IMP->getClassInterface()); StartObjCMethod(OMD, IMP->getClassInterface()); - + // Determine if we should use an objc_getProperty call for // this. Non-atomic properties are directly evaluated. // atomic 'copy' and 'retain' properties are also directly // evaluated in gc-only mode. if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly && - !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) && + IsAtomic && (PD->getSetterKind() == ObjCPropertyDecl::Copy || PD->getSetterKind() == ObjCPropertyDecl::Retain)) { llvm::Value *GetPropertyFn = @@ -208,7 +215,44 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); } else if (hasAggregateLLVMType(Ivar->getType())) { - EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + bool IsStrong = false; + if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(Ivar->getType()))) + && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect + && CGM.getObjCRuntime().GetCopyStructFunction()) { + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + // objc_copyStruct (ReturnValue, &structIvar, + // sizeof (Type of Ivar), isAtomic, false); + CallArgList Args; + RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *isAtomic = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsAtomic ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(isAtomic), + getContext().BoolTy)); + llvm::Value *hasStrong = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), + IsStrong ? 1 : 0); + Args.push_back(std::make_pair(RValue::get(hasStrong), + getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); + } + else + EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); } else { CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); @@ -289,6 +333,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), SetPropertyFn, ReturnValueSlot(), Args); + } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) && + !Ivar->getType()->isAnyComplexType() && + IndirectObjCSetterArg(*CurFnInfo) + && CGM.getObjCRuntime().GetCopyStructFunction()) { + // objc_copyStruct (&structIvar, &Arg, + // sizeof (struct something), true, false); + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + CallArgList Args; + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); + RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; + llvm::Value *ArgAsPtrTy = + Builder.CreateBitCast(Arg, + Types.ConvertType(getContext().VoidPtrTy)); + RV = RValue::get(ArgAsPtrTy); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *True = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); + Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + llvm::Value *False = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); + Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -304,7 +383,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, if (getContext().getCanonicalType(Ivar->getType()) != getContext().getCanonicalType(ArgDecl->getType())) { ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, - false); + CXXBaseSpecifierArray(), false); BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, Ivar->getType(), Loc); EmitStmt(&Assign); @@ -318,6 +397,83 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FinishFunction(); } +void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, + bool ctor) { + llvm::SmallVector<CXXBaseOrMemberInitializer *, 8> IvarInitializers; + MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface()); + StartObjCMethod(MD, IMP->getClassInterface()); + for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), + E = IMP->init_end(); B != E; ++B) { + CXXBaseOrMemberInitializer *Member = (*B); + IvarInitializers.push_back(Member); + } + if (ctor) { + for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) { + CXXBaseOrMemberInitializer *IvarInit = IvarInitializers[I]; + FieldDecl *Field = IvarInit->getMember(); + QualType FieldType = Field->getType(); + ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + EmitAggExpr(IvarInit->getInit(), LV.getAddress(), + LV.isVolatileQualified(), false, true); + } + // constructor returns 'self'. + CodeGenTypes &Types = CGM.getTypes(); + QualType IdTy(CGM.getContext().getObjCIdType()); + llvm::Value *SelfAsId = + Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); + EmitReturnOfRValue(RValue::get(SelfAsId), IdTy); + } + else { + // dtor + for (size_t i = IvarInitializers.size(); i > 0; --i) { + FieldDecl *Field = IvarInitializers[i - 1]->getMember(); + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(FieldType); + + ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), + LoadObjCSelf(), Ivar, 0); + const RecordType *RT = FieldType->getAs<RecordType>(); + CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (Array) { + const llvm::Type *BasePtr = ConvertType(FieldType); + BasePtr = llvm::PointerType::getUnqual(BasePtr); + llvm::Value *BaseAddrPtr = + Builder.CreateBitCast(LV.getAddress(), BasePtr); + EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()), + Array, BaseAddrPtr); + } + else + EmitCXXDestructorCall(FieldClassDecl->getDestructor(CGM.getContext()), + Dtor_Complete, /*ForVirtualBase=*/false, + LV.getAddress()); + } + } + FinishFunction(); +} + +bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) { + CGFunctionInfo::const_arg_iterator it = FI.arg_begin(); + it++; it++; + const ABIArgInfo &AI = it->info; + // FIXME. Is this sufficient check? + return (AI.getKind() == ABIArgInfo::Indirect); +} + +bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) { + if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + return false; + if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>()) + return FDTTy->getDecl()->hasObjectMember(); + return false; +} + llvm::Value *CodeGenFunction::LoadObjCSelf() { const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); // See if we need to lazily forward self inside a block literal. @@ -360,7 +516,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, EmitScalarExpr(E->getBase()), - false, CallArgList()); + CallArgList()); } else { const ObjCImplicitSetterGetterRefExpr *KE = cast<ObjCImplicitSetterGetterRefExpr>(Exp); @@ -376,7 +532,7 @@ RValue CodeGenFunction::EmitObjCPropertyGet(const Expr *Exp) { return CGM.getObjCRuntime(). GenerateMessageSend(*this, Exp->getType(), S, Receiver, - KE->getInterfaceDecl() != 0, CallArgList()); + CallArgList(), KE->getInterfaceDecl()); } } @@ -413,7 +569,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, EmitScalarExpr(E->getBase()), - false, Args); + Args); } else if (const ObjCImplicitSetterGetterRefExpr *E = dyn_cast<ObjCImplicitSetterGetterRefExpr>(Exp)) { Selector S = E->getSetterMethod()->getSelector(); @@ -430,7 +586,7 @@ void CodeGenFunction::EmitObjCPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, E->getType())); CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().VoidTy, S, Receiver, - E->getInterfaceDecl() != 0, Args); + Args, E->getInterfaceDecl()); } else assert (0 && "bad expression node in EmitObjCPropertySet"); } @@ -498,7 +654,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); llvm::Value *LimitPtr = CreateMemTemp(getContext().UnsignedLongTy, "limit.ptr"); @@ -623,7 +779,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CGM.getObjCRuntime().GenerateMessageSend(*this, getContext().UnsignedLongTy, FastEnumSel, - Collection, false, Args); + Collection, Args); Builder.CreateStore(CountRV.getScalarVal(), LimitPtr); Limit = Builder.CreateLoad(LimitPtr); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index d445200..3c51b7e 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -26,6 +26,7 @@ #include "llvm/Intrinsics.h" #include "llvm/Module.h" +#include "llvm/LLVMContext.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Compiler.h" @@ -81,6 +82,8 @@ private: llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; llvm::LLVMContext &VMContext; + /// Metadata kind used to tie method lookups to message sends. + unsigned msgSendMDKind; private: llvm::Constant *GenerateIvarList( const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames, @@ -112,7 +115,8 @@ private: llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties); + llvm::Constant *Properties, + bool isMeta=false); llvm::Constant *GenerateProtocolMethodList( const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames, const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes); @@ -141,8 +145,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, @@ -170,6 +174,7 @@ public: virtual llvm::Function *ModuleInitFunction(); virtual llvm::Function *GetPropertyGetFunction(); virtual llvm::Function *GetPropertySetFunction(); + virtual llvm::Function *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -221,10 +226,6 @@ void CGObjCGNU::EmitClassRef(const std::string &className) { llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } -static std::string SymbolNameForClass(const std::string &ClassName) { - return "_OBJC_CLASS_" + ClassName; -} - static std::string SymbolNameForMethod(const std::string &ClassName, const std::string &CategoryName, const std::string &MethodName, bool isClassMethod) { @@ -238,6 +239,9 @@ static std::string SymbolNameForMethod(const std::string &ClassName, const CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) { + + msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); + IntTy = cast<llvm::IntegerType>( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); LongTy = cast<llvm::IntegerType>( @@ -452,12 +456,15 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } - llvm::Value *cmd = GetSelector(CGF.Builder, Sel); + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *cmd = GetSelector(Builder, Sel); + CallArgList ActualArgs; ActualArgs.push_back( - std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), + std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)), ASTIdTy)); ActualArgs.push_back(std::make_pair(RValue::get(cmd), CGF.getContext().getObjCSelType())); @@ -481,7 +488,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( IdTy, Params, true), "objc_get_class"); } - ReceiverClass = CGF.Builder.CreateCall(classLookupFunction, + ReceiverClass = Builder.CreateCall(classLookupFunction, MakeConstantString(Class->getNameAsString())); } else { // Set up global aliases for the metaclass or class pointer if they do not @@ -506,36 +513,64 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } } // Cast the pointer to a simplified version of the class structure - ReceiverClass = CGF.Builder.CreateBitCast(ReceiverClass, + ReceiverClass = Builder.CreateBitCast(ReceiverClass, llvm::PointerType::getUnqual( llvm::StructType::get(VMContext, IdTy, IdTy, NULL))); // Get the superclass pointer - ReceiverClass = CGF.Builder.CreateStructGEP(ReceiverClass, 1); + ReceiverClass = Builder.CreateStructGEP(ReceiverClass, 1); // Load the superclass pointer - ReceiverClass = CGF.Builder.CreateLoad(ReceiverClass); + ReceiverClass = Builder.CreateLoad(ReceiverClass); // Construct the structure used to look up the IMP llvm::StructType *ObjCSuperTy = llvm::StructType::get(VMContext, Receiver->getType(), IdTy, NULL); - llvm::Value *ObjCSuper = CGF.Builder.CreateAlloca(ObjCSuperTy); + llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy); - CGF.Builder.CreateStore(Receiver, CGF.Builder.CreateStructGEP(ObjCSuper, 0)); - CGF.Builder.CreateStore(ReceiverClass, - CGF.Builder.CreateStructGEP(ObjCSuper, 1)); + Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); + Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); // Get the IMP std::vector<const llvm::Type*> Params; Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy)); Params.push_back(SelectorTy); + + llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; + llvm::Value *imp; + + if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { + // The lookup function returns a slot, which can be safely cached. + llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, + IntTy, llvm::PointerType::getUnqual(impType), NULL); + + llvm::Constant *lookupFunction = + CGM.CreateRuntimeFunction(llvm::FunctionType::get( + llvm::PointerType::getUnqual(SlotTy), Params, true), + "objc_slot_lookup_super"); + + llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs, + lookupArgs+2); + slot->setOnlyReadsMemory(); + + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + } else { llvm::Constant *lookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::PointerType::getUnqual(impType), Params, true), "objc_msg_lookup_super"); + imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2); + } - llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; - llvm::Value *imp = CGF.Builder.CreateCall(lookupFunction, lookupArgs, - lookupArgs+2); - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + return msgRet; } /// Generate code for a message send expression. @@ -544,9 +579,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { + // Strip out message sends to retain / release in GC mode if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { if (Sel == RetainSel || Sel == AutoreleaseSel) { return RValue::get(Receiver); @@ -555,7 +591,39 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, return RValue::get(0); } } + CGBuilderTy &Builder = CGF.Builder; + + // If the return type is something that goes in an integer register, the + // runtime will handle 0 returns. For other cases, we fill in the 0 value + // ourselves. + // + // The language spec says the result of this kind of message send is + // undefined, but lots of people seem to have forgotten to read that + // paragraph and insist on sending messages to nil that have structure + // returns. With GCC, this generates a random return value (whatever happens + // to be on the stack / in those registers at the time) on most platforms, + // and generates a SegV on SPARC. With LLVM it corrupts the stack. + bool isPointerSizedReturn = false; + if (ResultType->isAnyPointerType() || ResultType->isIntegralType() || + ResultType->isVoidType()) + isPointerSizedReturn = true; + + llvm::BasicBlock *startBB = 0; + llvm::BasicBlock *messageBB = 0; + llvm::BasicBlock *contiueBB = 0; + + if (!isPointerSizedReturn) { + startBB = Builder.GetInsertBlock(); + messageBB = CGF.createBasicBlock("msgSend"); + contiueBB = CGF.createBasicBlock("continue"); + + llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, + llvm::Constant::getNullValue(Receiver->getType())); + Builder.CreateCondBr(isNil, contiueBB, messageBB); + CGF.EmitBlock(messageBB); + } + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) @@ -577,6 +645,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + + llvm::Value *imp; // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. @@ -611,9 +687,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, LookupFn->setDoesNotCapture(1); } - llvm::Value *slot = + llvm::CallInst *slot = Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self); + slot->setOnlyReadsMemory(); + slot->setMetadata(msgSendMDKind, node); + imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + // The lookup function may have changed the receiver, so make sure we use // the new one. ActualArgs[0] = @@ -628,9 +708,46 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, "objc_msg_lookup"); imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); + cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node); } - - return CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs); + llvm::Instruction *call; + RValue msgRet = CGF.EmitCall(FnInfo, imp, ReturnValueSlot(), ActualArgs, + 0, &call); + call->setMetadata(msgSendMDKind, node); + + if (!isPointerSizedReturn) { + CGF.EmitBlock(contiueBB); + if (msgRet.isScalar()) { + llvm::Value *v = msgRet.getScalarVal(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + phi->addIncoming(v, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); + msgRet = RValue::get(phi); + } else if (msgRet.isAggregate()) { + llvm::Value *v = msgRet.getAggregateAddr(); + llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType()); + llvm::AllocaInst *NullVal = + CGF.CreateTempAlloca(RetTy->getElementType(), "null"); + CGF.InitTempAlloca(NullVal, + llvm::Constant::getNullValue(RetTy->getElementType())); + phi->addIncoming(v, messageBB); + phi->addIncoming(NullVal, startBB); + msgRet = RValue::getAggregate(phi); + } else /* isComplex() */ { + std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal(); + llvm::PHINode *phi = Builder.CreatePHI(v.first->getType()); + phi->addIncoming(v.first, messageBB); + phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), + startBB); + llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType()); + phi2->addIncoming(v.second, messageBB); + phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), + startBB); + msgRet = RValue::getComplex(phi, phi2); + } + } + return msgRet; } /// Generates a MethodList. Used in construction of a objc_class and @@ -749,7 +866,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( llvm::Constant *Methods, llvm::Constant *Protocols, llvm::Constant *IvarOffsets, - llvm::Constant *Properties) { + llvm::Constant *Properties, + bool isMeta) { // Set up the class structure // Note: Several of these are char*s when they should be ids. This is // because the runtime performs this translation on load. @@ -799,8 +917,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. - return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name), - llvm::GlobalValue::ExternalLinkage); + return MakeGlobal(ClassTy, Elements, (isMeta ? "_OBJC_METACLASS_": + "_OBJC_CLASS_") + std::string(Name), llvm::GlobalValue::ExternalLinkage); } llvm::Constant *CGObjCGNU::GenerateProtocolMethodList( @@ -1289,16 +1407,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { instanceSize = 0 - (instanceSize - superInstanceSize); } - for (ObjCInterfaceDecl::ivar_iterator iter = ClassDecl->ivar_begin(), - endIter = ClassDecl->ivar_end() ; iter != endIter ; iter++) { + + // Collect declared and synthesized ivars. + llvm::SmallVector<ObjCIvarDecl*, 16> OIvars; + CGM.getContext().ShallowCollectObjCIvars(ClassDecl, OIvars); + + for (unsigned i = 0, e = OIvars.size(); i != e; ++i) { + ObjCIvarDecl *IVD = OIvars[i]; // Store the name - IvarNames.push_back(MakeConstantString((*iter)->getNameAsString())); + IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); // Get the type encoding for this ivar std::string TypeStr; - Context.getObjCEncodingForType((*iter)->getType(), TypeStr); + Context.getObjCEncodingForType(IVD->getType(), TypeStr); IvarTypes.push_back(MakeConstantString(TypeStr)); // Get the offset - uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter); + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { Offset = BaseOffset - superInstanceSize; @@ -1309,7 +1432,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { false, llvm::GlobalValue::ExternalLinkage, llvm::ConstantInt::get(IntTy, BaseOffset), "__objc_ivar_offset_value_" + ClassName +"." + - (*iter)->getNameAsString())); + IVD->getNameAsString())); } llvm::Constant *IvarOffsetArrayInit = llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy, @@ -1411,7 +1534,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { //Generate metaclass for class methods llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList( - empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr); + empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true); // Generate the class structure llvm::Constant *ClassStruct = @@ -1658,10 +1781,9 @@ llvm::Function *CGObjCGNU::GetPropertyGetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(BoolTy); - // void objc_getProperty (id, SEL, ptrdiff_t, bool) + // void objc_getProperty (id, SEL, int, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Params, false); return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, @@ -1674,18 +1796,22 @@ llvm::Function *CGObjCGNU::GetPropertySetFunction() { CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Params.push_back(IdTy); Params.push_back(SelectorTy); - // FIXME: Using LongTy for ptrdiff_t is probably broken on Win64 - Params.push_back(LongTy); + Params.push_back(IntTy); Params.push_back(IdTy); Params.push_back(BoolTy); Params.push_back(BoolTy); - // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) + // void objc_setProperty (id, SEL, int, id, bool, bool) const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, "objc_setProperty")); } +// FIXME. Implement this. +llvm::Function *CGObjCGNU::GetCopyStructFunction() { + return 0; +} + llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -1764,7 +1890,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::Value *RethrowPtr = CGF.CreateTempAlloca(Exc->getType(), "_rethrow"); llvm::SmallVector<llvm::Value*, 8> ESelArgs; - llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers; + llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers; ESelArgs.push_back(Exc); ESelArgs.push_back(Personality); @@ -1772,12 +1898,13 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, bool HasCatchAll = false; // Only @try blocks are allowed @catch blocks, but both can have @finally if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast<ObjCAtTryStmt>(S).getCatchStmts()) { + if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) { + const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S); CGF.setInvokeDest(CatchInCatch); - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); @@ -1816,7 +1943,7 @@ void CGObjCGNU::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ESelArgs.begin(), ESelArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -2046,7 +2173,14 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( // when linked against code which isn't (most of the time). llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); if (!IvarOffsetPointer) { - uint64_t Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + uint64_t Offset; + if (ObjCImplementationDecl *OID = + CGM.getContext().getObjCImplementation( + const_cast<ObjCInterfaceDecl *>(ID))) + Offset = ComputeIvarBaseOffset(CGM, OID, Ivar); + else + Offset = ComputeIvarBaseOffset(CGM, ID, Ivar); + llvm::ConstantInt *OffsetGuess = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Offset, "ivar"); // Don't emit the guess in non-PIC code because the linker will not be able diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index ac8fa05..77eabbf 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -124,9 +124,19 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // layout object. However, this is blocked on other cleanups to the // Objective-C code, so for now we just live with allocating a bunch of these // objects. - unsigned FieldNo = 0; // This value is unused. + + // We always construct a single, possibly unaligned, access for this case. + CGBitFieldInfo::AccessInfo AI; + AI.FieldIndex = 0; + AI.FieldByteOffset = 0; + AI.FieldBitStart = BitOffset; + AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy); + AI.AccessAlignment = 0; + AI.TargetBitOffset = 0; + AI.TargetBitWidth = BitFieldSize; + CGBitFieldInfo *Info = - new (CGF.CGM.getContext()) CGBitFieldInfo(FieldNo, BitOffset, BitFieldSize, + new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI, IvarTy->isSignedIntegerType()); // FIXME: We need to set a very conservative alignment on this, or make sure @@ -329,6 +339,24 @@ public: return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } + + llvm::Constant *getCopyStructFn() { + CodeGen::CodeGenTypes &Types = CGM.getTypes(); + ASTContext &Ctx = CGM.getContext(); + // void objc_copyStruct (void *, const void *, size_t, bool, bool) + llvm::SmallVector<CanQualType,5> Params; + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.VoidPtrTy); + Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.BoolTy); + Params.push_back(Ctx.BoolTy); + const llvm::FunctionType *FTy = + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + FunctionType::ExtInfo()), + false); + return CGM.CreateRuntimeFunction(FTy, "objc_copyStruct"); + } + llvm::Constant *getEnumerationMutationFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); @@ -954,6 +982,10 @@ protected: const ObjCMethodDecl *OMD, const ObjCCommonTypesHelper &ObjCTypes); + /// EmitImageInfo - Emit the image info marker used to encode some module + /// level information. + void EmitImageInfo(); + public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } @@ -980,9 +1012,6 @@ public: class CGObjCMac : public CGObjCCommonMac { private: ObjCTypesHelper ObjCTypes; - /// EmitImageInfo - Emit the image info marker used to encode some module - /// level information. - void EmitImageInfo(); /// EmitModuleInfo - Another marker encoding module level /// information. @@ -1100,8 +1129,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1134,6 +1163,7 @@ public: virtual llvm::Constant *GetPropertyGetFunction(); virtual llvm::Constant *GetPropertySetFunction(); + virtual llvm::Constant *GetCopyStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, @@ -1327,8 +1357,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); virtual CodeGen::RValue @@ -1366,6 +1396,11 @@ public: virtual llvm::Constant *GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } + + virtual llvm::Constant *GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); + } + virtual llvm::Constant *EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -1459,9 +1494,20 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl }; */ +/// or Generate a constant NSString object. +/* + struct __builtin_NSString { + const int *isa; // point to __NSConstantStringClassReference + const char *str; + unsigned int length; + }; +*/ + llvm::Constant *CGObjCCommonMac::GenerateConstantString( const StringLiteral *SL) { - return CGM.GetAddrOfConstantCFString(SL); + return (CGM.getLangOptions().NoConstantCFStrings == 0 ? + CGM.GetAddrOfConstantCFString(SL) : + CGM.GetAddrOfConstantNSString(SL)); } /// Generates a message send where the super is the receiver. This is @@ -1531,8 +1577,8 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -1696,7 +1742,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { Init, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -1718,7 +1763,6 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { 0, "\01L_OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - Entry->setAlignment(4); // FIXME: Is this necessary? Why only for protocol? Entry->setAlignment(4); } @@ -2039,6 +2083,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { Interface->protocol_begin(), Interface->protocol_end()); unsigned Flags = eClassFlags_Factory; + if (ID->getNumIvarInitializers()) + Flags |= eClassFlags_HasCXXStructors; unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize() / 8; @@ -2430,6 +2476,10 @@ llvm::Constant *CGObjCMac::GetPropertySetFunction() { return ObjCTypes.getSetPropertyFn(); } +llvm::Constant *CGObjCMac::GetCopyStructFunction() { + return ObjCTypes.getCopyStructFn(); +} + llvm::Constant *CGObjCMac::EnumerationMutationFunction() { return ObjCTypes.getEnumerationMutationFn(); } @@ -2597,8 +2647,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), CallTryExitPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); - } else if (const ObjCAtCatchStmt* CatchStmt = - cast<ObjCAtTryStmt>(S).getCatchStmts()) { + } else if (cast<ObjCAtTryStmt>(S).getNumCatchStmts()) { + const ObjCAtTryStmt* AtTryStmt = cast<ObjCAtTryStmt>(&S); + // Enter a new exception try block (in case a @catch block throws // an exception). CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData); @@ -2617,10 +2668,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // matched and avoid generating code for falling off the end if // so. bool AllMatched = false; - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { + for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I); llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch"); - const ParmVarDecl *CatchParam = CatchStmt->getCatchParamDecl(); + const VarDecl *CatchParam = CatchStmt->getCatchParamDecl(); const ObjCObjectPointerType *OPT = 0; // catch(...) always matches. @@ -2911,18 +2963,17 @@ llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, /// unsigned flags; /// }; enum ImageInfoFlags { - eImageInfo_FixAndContinue = (1 << 0), // FIXME: Not sure what - // this implies. + eImageInfo_FixAndContinue = (1 << 0), eImageInfo_GarbageCollected = (1 << 1), eImageInfo_GCOnly = (1 << 2), eImageInfo_OptimizedByDyld = (1 << 3), // FIXME: When is this set. - // A flag indicating that the module has no instances of an - // @synthesize of a superclass variable. <rdar://problem/6803242> + // A flag indicating that the module has no instances of a @synthesize of a + // superclass variable. <rdar://problem/6803242> eImageInfo_CorrectedSynthesize = (1 << 4) }; -void CGObjCMac::EmitImageInfo() { +void CGObjCCommonMac::EmitImageInfo() { unsigned version = 0; // Version is unused? unsigned flags = 0; @@ -3132,19 +3183,10 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, FieldDecl *Field = RecFields[i]; uint64_t FieldOffset; if (RD) { - const CGRecordLayout &RL = - CGM.getTypes().getCGRecordLayout(Field->getParent()); - if (Field->isBitField()) { - const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); - - const llvm::Type *Ty = - CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); - uint64_t TypeSize = - CGM.getTypes().getTargetData().getTypeAllocSize(Ty); - FieldOffset = Info.FieldNo * TypeSize; - } else - FieldOffset = - Layout->getElementOffset(RL.getLLVMFieldNo(Field)); + // Note that 'i' here is actually the field index inside RD of Field, + // although this dependency is hidden. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + FieldOffset = RL.getFieldOffset(i) / 8; } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)); @@ -3536,7 +3578,7 @@ void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) - OS << '(' << CID->getNameAsString() << ')'; + OS << '(' << CID << ')'; OS << ' ' << D->getSelector().getAsString() << ']'; } @@ -3574,14 +3616,14 @@ void CGObjCMac::FinishModule() { Asm += '\n'; llvm::raw_svector_ostream OS(Asm); - for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(), - e = LazySymbols.end(); I != e; ++I) - OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(), e = DefinedSymbols.end(); I != e; ++I) OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n" << "\t.globl .objc_class_name_" << (*I)->getName() << "\n"; - + for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(), + e = LazySymbols.end(); I != e; ++I) + OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; + CGM.getModule().setModuleInlineAsm(OS.str()); } } @@ -3627,7 +3669,8 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // id self; // Class cls; // } - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_objc_super")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4088,7 +4131,8 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // }; // First the clang type for struct _message_ref_t - RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, + RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, + Ctx.getTranslationUnitDecl(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, @@ -4162,7 +4206,7 @@ void CGObjCNonFragileABIMac::AddModuleClassList(const llvm::GlobalValue::InternalLinkage, Init, SymbolName); - GV->setAlignment(8); + GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(SectionName); CGM.AddUsedGlobal(GV); } @@ -4203,28 +4247,7 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { "\01L_OBJC_LABEL_NONLAZY_CATEGORY_$", "__DATA, __objc_nlcatlist, regular, no_dead_strip"); - // static int L_OBJC_IMAGE_INFO[2] = { 0, flags }; - // FIXME. flags can be 0 | 1 | 2 | 6. For now just use 0 - std::vector<llvm::Constant*> Values(2); - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, 0); - unsigned int flags = 0; - // FIXME: Fix and continue? - if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) - flags |= eImageInfo_GarbageCollected; - if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) - flags |= eImageInfo_GCOnly; - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); - llvm::Constant* Init = llvm::ConstantArray::get( - llvm::ArrayType::get(ObjCTypes.IntTy, 2), - Values); - llvm::GlobalVariable *IMGV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::InternalLinkage, - Init, - "\01L_OBJC_IMAGE_INFO"); - IMGV->setSection("__DATA, __objc_imageinfo, regular, no_dead_strip"); - IMGV->setConstant(true); - CGM.AddUsedGlobal(IMGV); + EmitImageInfo(); } /// LegacyDispatchedSelector - Returns true if SEL is not in the list of @@ -4233,9 +4256,19 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() { /// message dispatch call for all the rest. /// bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { - if (CGM.getCodeGenOpts().ObjCLegacyDispatch) + switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { + default: + assert(0 && "Invalid dispatch method!"); + case CodeGenOptions::Legacy: return true; + case CodeGenOptions::NonLegacy: + return false; + case CodeGenOptions::Mixed: + break; + } + // If so, see whether this selector is in the white-list of things which must + // use the new dispatch convention. We lazily build a dense set for this. if (NonLegacyDispatchMethods.empty()) { NonLegacyDispatchMethods.insert(GetNullarySelector("alloc")); NonLegacyDispatchMethods.insert(GetNullarySelector("class")); @@ -4265,6 +4298,7 @@ bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) { NonLegacyDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); } + return (NonLegacyDispatchMethods.count(Sel) == 0); } @@ -4369,7 +4403,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); CLASS_RO_GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassRonfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); CLASS_RO_GV->setSection("__DATA, __objc_const"); return CLASS_RO_GV; @@ -4405,7 +4439,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( GV->setInitializer(Init); GV->setSection("__DATA, __objc_data"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ClassnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy)); if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return GV; @@ -4467,6 +4501,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { CGM.getDeclVisibilityMode(ID->getClassInterface()) == LangOptions::Hidden; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (!ID->getClassInterface()->getSuperClass()) { // class is root flags |= CLS_ROOT; @@ -4501,6 +4537,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { flags = CLS; if (classIsHidden) flags |= OBJC2_CLS_HIDDEN; + if (ID->getNumIvarInitializers()) + flags |= eClassFlags_ABI2_HasCXXStructors; if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface())) flags |= CLS_EXCEPTION; @@ -4655,7 +4693,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Init, ExtCatName); GCATV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.CategorynfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy)); GCATV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); @@ -4715,7 +4753,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitMethodList(llvm::Twine Name, Init, Name); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection(Section); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, @@ -4750,7 +4788,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, Offset)); IvarOffsetGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.LongTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy)); // FIXME: This matches gcc, but shouldn't the visibility be set on the use as // well (i.e., in ObjCIvarOffsetVariable). @@ -4837,7 +4875,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( Init, Prefix + OID->getName()); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GV); @@ -4956,7 +4994,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Init, "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABITy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); } Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -4969,7 +5007,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Entry, "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); + CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); @@ -5025,7 +5063,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(llvm::Twine Name, Name); GV->setSection("__DATA, __objc_const"); GV->setAlignment( - CGM.getTargetData().getPrefTypeAlignment(Init->getType())); + CGM.getTargetData().getABITypeAlignment(Init->getType())); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); @@ -5184,8 +5222,8 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { return LegacyDispatchedSelector(Sel) ? EmitLegacyMessageSend(CGF, ResultType, EmitSelector(CGF.Builder, Sel), @@ -5222,7 +5260,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_REFERENCES_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5245,7 +5283,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -5271,7 +5309,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, MetaClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getPrefTypeAlignment( + CGM.getTargetData().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); @@ -5532,45 +5570,44 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.push_back(ObjCTypes.getEHPersonalityPtr()); // Construct the lists of (type, catch body) to handle. - llvm::SmallVector<std::pair<const ParmVarDecl*, const Stmt*>, 8> Handlers; + llvm::SmallVector<std::pair<const VarDecl*, const Stmt*>, 8> Handlers; bool HasCatchAll = false; if (isTry) { - if (const ObjCAtCatchStmt* CatchStmt = - cast<ObjCAtTryStmt>(S).getCatchStmts()) { - for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) { - const ParmVarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - - // catch(...) always matches. - if (!CatchDecl) { - // Use i8* null here to signal this is a catch all, not a cleanup. - llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); - SelectorArgs.push_back(Null); - HasCatchAll = true; - break; - } + const ObjCAtTryStmt &AtTry = cast<ObjCAtTryStmt>(S); + for (unsigned I = 0, N = AtTry.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = AtTry.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + Handlers.push_back(std::make_pair(CatchDecl, CatchStmt->getCatchBody())); - if (CatchDecl->getType()->isObjCIdType() || - CatchDecl->getType()->isObjCQualifiedIdType()) { - llvm::Value *IDEHType = - CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); - if (!IDEHType) - IDEHType = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, "OBJC_EHTYPE_id"); - SelectorArgs.push_back(IDEHType); - } else { - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *PT = - CatchDecl->getType()->getAs<ObjCObjectPointerType>(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = PT->getInterfaceType(); - assert(IT && "Invalid @catch type."); - llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); - SelectorArgs.push_back(EHType); - } + // catch(...) always matches. + if (!CatchDecl) { + // Use i8* null here to signal this is a catch all, not a cleanup. + llvm::Value *Null = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + SelectorArgs.push_back(Null); + HasCatchAll = true; + break; + } + + if (CatchDecl->getType()->isObjCIdType() || + CatchDecl->getType()->isObjCQualifiedIdType()) { + llvm::Value *IDEHType = + CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, "OBJC_EHTYPE_id"); + SelectorArgs.push_back(IDEHType); + } else { + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *PT = + CatchDecl->getType()->getAs<ObjCObjectPointerType>(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + llvm::Value *EHType = GetInterfaceEHType(IT->getDecl(), false); + SelectorArgs.push_back(EHType); } } } @@ -5589,7 +5626,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, SelectorArgs.begin(), SelectorArgs.end(), "selector"); for (unsigned i = 0, e = Handlers.size(); i != e; ++i) { - const ParmVarDecl *CatchParam = Handlers[i].first; + const VarDecl *CatchParam = Handlers[i].first; const Stmt *CatchBody = Handlers[i].second; llvm::BasicBlock *Next = 0; @@ -5612,14 +5649,9 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, if (CatchBody) { llvm::BasicBlock *MatchEnd = CGF.createBasicBlock("match.end"); - llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); // Cleanups must call objc_end_catch. - // - // FIXME: It seems incorrect for objc_begin_catch to be inside this - // context, but this matches gcc. CGF.PushCleanupBlock(MatchEnd); - CGF.setInvokeDest(MatchHandler); llvm::Value *ExcObject = CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), Exc); @@ -5636,25 +5668,37 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateStore(ExcObject, CGF.GetAddrOfLocalVar(CatchParam)); } + // Exceptions inside the catch block must be rethrown. We set a special + // purpose invoke destination for this which just collects the thrown + // exception and overwrites the object in RethrowPtr, branches through the + // match.end to make sure we call objc_end_catch, before branching to the + // rethrow handler. + llvm::BasicBlock *MatchHandler = CGF.createBasicBlock("match.handler"); + CGF.setInvokeDest(MatchHandler); CGF.ObjCEHValueStack.push_back(ExcObject); CGF.EmitStmt(CatchBody); CGF.ObjCEHValueStack.pop_back(); + CGF.setInvokeDest(0); CGF.EmitBranchThroughCleanup(FinallyEnd); - CGF.EmitBlock(MatchHandler); - - llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); - // We are required to emit this call to satisfy LLVM, even - // though we don't use the result. - llvm::SmallVector<llvm::Value*, 8> Args; - Args.push_back(Exc); - Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); - CGF.Builder.CreateStore(Exc, RethrowPtr); - CGF.EmitBranchThroughCleanup(FinallyRethrow); + // Don't emit the extra match handler if there we no unprotected calls in + // the catch block. + if (MatchHandler->use_empty()) { + delete MatchHandler; + } else { + CGF.EmitBlock(MatchHandler); + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); + CGF.Builder.CreateStore(Exc, RethrowPtr); + CGF.EmitBranchThroughCleanup(FinallyRethrow); + } CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock(); @@ -5666,8 +5710,7 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.createBasicBlock("match.end.handler"); llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); CGF.Builder.CreateInvoke(ObjCTypes.getObjCEndCatchFn(), - Cont, MatchEndHandler, - Args.begin(), Args.begin()); + Cont, MatchEndHandler); CGF.EmitBlock(Cont); if (Info.SwitchBlock) @@ -5676,15 +5719,14 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(Info.EndBlock); CGF.EmitBlock(MatchEndHandler); - Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(ObjCTypes.getEHPersonalityPtr()); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + CGF.Builder.CreateCall3(llvm_eh_selector, + Exc, ObjCTypes.getEHPersonalityPtr(), + llvm::ConstantInt::get( + llvm::Type::getInt32Ty(VMContext), 0), + "unused_eh_selector"); CGF.Builder.CreateStore(Exc, RethrowPtr); CGF.EmitBranchThroughCleanup(FinallyRethrow); @@ -5723,9 +5765,19 @@ CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Branch around the rethrow code. CGF.EmitBranch(FinallyEnd); + // Generate the rethrow code, taking care to use an invoke if we are in a + // nested exception scope. CGF.EmitBlock(FinallyRethrow); - CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), - CGF.Builder.CreateLoad(RethrowPtr)); + if (PrevLandingPad) { + llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont"); + CGF.Builder.CreateInvoke(ObjCTypes.getUnwindResumeOrRethrowFn(), + Cont, PrevLandingPad, + CGF.Builder.CreateLoad(RethrowPtr)); + CGF.EmitBlock(Cont); + } else { + CGF.Builder.CreateCall(ObjCTypes.getUnwindResumeOrRethrowFn(), + CGF.Builder.CreateLoad(RethrowPtr)); + } CGF.Builder.CreateUnreachable(); CGF.EmitBlock(FinallyEnd); @@ -5816,7 +5868,8 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, if (CGM.getLangOptions().getVisibilityMode() == LangOptions::Hidden) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - Entry->setAlignment(8); + Entry->setAlignment(CGM.getTargetData().getABITypeAlignment( + ObjCTypes.EHTypeTy)); if (ForDefinition) { Entry->setSection("__DATA,__objc_const"); diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index e478394..654ad0a 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -122,8 +122,8 @@ public: QualType ResultType, Selector Sel, llvm::Value *Receiver, - bool IsClassMessage, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class = 0, const ObjCMethodDecl *Method = 0) = 0; /// Generate an Objective-C message send operation to the super @@ -167,6 +167,9 @@ public: /// Return the runtime function for setting properties. virtual llvm::Constant *GetPropertySetFunction() = 0; + // API for atomic copying of qualified aggregates in setter/getter. + virtual llvm::Constant *GetCopyStructFunction() = 0; + /// GetClass - Return a reference to the class for the given /// interface decl. virtual llvm::Value *GetClass(CGBuilderTy &Builder, diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 1caec97..aec1c45 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -31,8 +31,8 @@ class RTTIBuilder { /// descriptor of the given type. llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); - /// BuildVtablePointer - Build the vtable pointer for the given type. - void BuildVtablePointer(const Type *Ty); + /// BuildVTablePointer - Build the vtable pointer for the given type. + void BuildVTablePointer(const Type *Ty); /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single /// inheritance, according to the Itanium C++ ABI, 2.9.5p6b. @@ -148,6 +148,9 @@ public: }; /// BuildTypeInfo - Build the RTTI type info struct for the given type. + /// + /// \param Force - true to force the creation of this RTTI value + /// \param ForEH - true if this is for exception handling llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); }; } @@ -242,9 +245,10 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { } /// ShouldUseExternalRTTIDescriptor - Returns whether the type information for -/// the given type exists somewhere else, and that we should not emit the typ +/// the given type exists somewhere else, and that we should not emit the type /// information in this translation unit. -bool ShouldUseExternalRTTIDescriptor(QualType Ty) { +static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, + QualType Ty) { // Type info for builtin types is defined in the standard library. if (const BuiltinType *BuiltinTy = dyn_cast<BuiltinType>(Ty)) return TypeInfoIsInStandardLibrary(BuiltinTy); @@ -254,6 +258,9 @@ bool ShouldUseExternalRTTIDescriptor(QualType Ty) { if (const PointerType *PointerTy = dyn_cast<PointerType>(Ty)) return TypeInfoIsInStandardLibrary(PointerTy); + // If RTTI is disabled, don't consider key functions. + if (!Context.getLangOptions().RTTI) return false; + if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); if (!RD->hasDefinition()) @@ -337,7 +344,7 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty) { if (const RecordType *Record = dyn_cast<RecordType>(Ty)) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); if (RD->isDynamicClass()) - return CodeGenModule::getVtableLinkage(RD); + return CodeGenModule::getVTableLinkage(RD); } return llvm::GlobalValue::WeakODRLinkage; @@ -375,8 +382,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { return true; } -void RTTIBuilder::BuildVtablePointer(const Type *Ty) { - const char *VtableName; +void RTTIBuilder::BuildVTablePointer(const Type *Ty) { + const char *VTableName; switch (Ty->getTypeClass()) { default: assert(0 && "Unhandled type!"); @@ -386,24 +393,24 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Vector: case Type::ExtVector: // abi::__fundamental_type_info. - VtableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; + VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; break; case Type::ConstantArray: case Type::IncompleteArray: // abi::__array_type_info. - VtableName = "_ZTVN10__cxxabiv117__array_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; break; case Type::FunctionNoProto: case Type::FunctionProto: // abi::__function_type_info. - VtableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; break; case Type::Enum: // abi::__enum_type_info. - VtableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; + VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; break; case Type::Record: { @@ -412,13 +419,13 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { if (!RD->hasDefinition() || !RD->getNumBases()) { // abi::__class_type_info. - VtableName = "_ZTVN10__cxxabiv117__class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv117__class_type_infoE"; } else if (CanUseSingleInheritance(RD)) { // abi::__si_class_type_info. - VtableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; } else { // abi::__vmi_class_type_info. - VtableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; } break; @@ -426,30 +433,31 @@ void RTTIBuilder::BuildVtablePointer(const Type *Ty) { case Type::Pointer: // abi::__pointer_type_info. - VtableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; + VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; break; case Type::MemberPointer: // abi::__pointer_to_member_type_info. - VtableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; + VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; break; } - llvm::Constant *Vtable = - CGM.getModule().getOrInsertGlobal(VtableName, Int8PtrTy); + llvm::Constant *VTable = + CGM.getModule().getOrInsertGlobal(VTableName, Int8PtrTy); const llvm::Type *PtrDiffTy = CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); // The vtable address point is 2. llvm::Constant *Two = llvm::ConstantInt::get(PtrDiffTy, 2); - Vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, &Two, 1); - Vtable = llvm::ConstantExpr::getBitCast(Vtable, Int8PtrTy); + VTable = llvm::ConstantExpr::getInBoundsGetElementPtr(VTable, &Two, 1); + VTable = llvm::ConstantExpr::getBitCast(VTable, Int8PtrTy); - Fields.push_back(Vtable); + Fields.push_back(VTable); } -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, + bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); @@ -463,13 +471,13 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); // Check if there is already an external RTTI descriptor for this type. - if (!Force && ShouldUseExternalRTTIDescriptor(Ty)) + if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty)) return GetAddrOfExternalRTTIDescriptor(Ty); llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); // Add the vtable pointer. - BuildVtablePointer(cast<Type>(Ty)); + BuildVTablePointer(cast<Type>(Ty)); // And the name. Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage)); @@ -782,42 +790,17 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) { Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0))); } -llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty) { - if (!getContext().getLangOptions().RTTI) { +llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, + bool ForEH) { + // Return a bogus pointer if RTTI is disabled, unless it's for EH. + // FIXME: should we even be calling this method if RTTI is disabled + // and it's not for EH? + if (!ForEH && !getContext().getLangOptions().RTTI) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); return llvm::Constant::getNullValue(Int8PtrTy); } - - return RTTIBuilder(*this).BuildTypeInfo(Ty); -} -// Try to find the magic class __cxxabiv1::__fundamental_type_info. If -// exists and has a destructor, we will emit the typeinfo for the fundamental -// types. This is the same behaviour as GCC. -static CXXRecordDecl *FindMagicClass(ASTContext &AC) { - const IdentifierInfo &NamespaceII = AC.Idents.get("__cxxabiv1"); - DeclarationName NamespaceDN = AC.DeclarationNames.getIdentifier(&NamespaceII); - TranslationUnitDecl *TUD = AC.getTranslationUnitDecl(); - DeclContext::lookup_result NamespaceLookup = TUD->lookup(NamespaceDN); - if (NamespaceLookup.first == NamespaceLookup.second) - return NULL; - const NamespaceDecl *Namespace = - dyn_cast<NamespaceDecl>(*NamespaceLookup.first); - if (!Namespace) - return NULL; - - const IdentifierInfo &ClassII = AC.Idents.get("__fundamental_type_info"); - DeclarationName ClassDN = AC.DeclarationNames.getIdentifier(&ClassII); - DeclContext::lookup_const_result ClassLookup = Namespace->lookup(ClassDN); - if (ClassLookup.first == ClassLookup.second) - return NULL; - CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(*ClassLookup.first); - - if (Class->hasDefinition() && Class->isDynamicClass() && - Class->getDestructor(AC)) - return Class; - - return NULL; + return RTTIBuilder(*this).BuildTypeInfo(Ty); } void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { @@ -829,12 +812,6 @@ void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) { } void CodeGenModule::EmitFundamentalRTTIDescriptors() { - CXXRecordDecl *RD = FindMagicClass(getContext()); - if (!RD) - return; - - getVTables().GenerateClassData(getVtableLinkage(RD), RD); - QualType FundamentalTypes[] = { Context.VoidTy, Context.Char32Ty, Context.Char16Ty, Context.UnsignedLongLongTy, Context.LongLongTy, Context.WCharTy, diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index fd1775e..9f966fb 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -13,22 +13,137 @@ #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" namespace llvm { + class raw_ostream; class Type; } namespace clang { namespace CodeGen { +/// \brief Helper object for describing how to generate the code for access to a +/// bit-field. +/// +/// This structure is intended to describe the "policy" of how the bit-field +/// should be accessed, which may be target, language, or ABI dependent. class CGBitFieldInfo { public: - CGBitFieldInfo(unsigned FieldNo, unsigned Start, unsigned Size, - bool IsSigned) - : FieldNo(FieldNo), Start(Start), Size(Size), IsSigned(IsSigned) {} + /// Descriptor for a single component of a bit-field access. The entire + /// bit-field is constituted of a bitwise OR of all of the individual + /// components. + /// + /// Each component describes an accessed value, which is how the component + /// should be transferred to/from memory, and a target placement, which is how + /// that component fits into the constituted bit-field. The pseudo-IR for a + /// load is: + /// + /// %0 = gep %base, 0, FieldIndex + /// %1 = gep (i8*) %0, FieldByteOffset + /// %2 = (i(AccessWidth) *) %1 + /// %3 = load %2, align AccessAlignment + /// %4 = shr %3, FieldBitStart + /// + /// and the composed bit-field is formed as the boolean OR of all accesses, + /// masked to TargetBitWidth bits and shifted to TargetBitOffset. + struct AccessInfo { + /// Offset of the field to load in the LLVM structure, if any. + unsigned FieldIndex; + + /// Byte offset from the field address, if any. This should generally be + /// unused as the cleanest IR comes from having a well-constructed LLVM type + /// with proper GEP instructions, but sometimes its use is required, for + /// example if an access is intended to straddle an LLVM field boundary. + unsigned FieldByteOffset; + + /// Bit offset in the accessed value to use. The width is implied by \see + /// TargetBitWidth. + unsigned FieldBitStart; + + /// Bit width of the memory access to perform. + unsigned AccessWidth; + + /// The alignment of the memory access, or 0 if the default alignment should + /// be used. + // + // FIXME: Remove use of 0 to encode default, instead have IRgen do the right + // thing when it generates the code, if avoiding align directives is + // desired. + unsigned AccessAlignment; + + /// Offset for the target value. + unsigned TargetBitOffset; + + /// Number of bits in the access that are destined for the bit-field. + unsigned TargetBitWidth; + }; - unsigned FieldNo; - unsigned Start; +private: + /// The components to use to access the bit-field. We may need up to three + /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte + /// accesses). + // + // FIXME: De-hardcode this, just allocate following the struct. + AccessInfo Components[3]; + + /// The total size of the bit-field, in bits. unsigned Size; + + /// The number of access components to use. + unsigned NumComponents; + + /// Whether the bit-field is signed. bool IsSigned : 1; + +public: + CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components, + bool IsSigned) : Size(Size), NumComponents(NumComponents), + IsSigned(IsSigned) { + assert(NumComponents <= 3 && "invalid number of components!"); + for (unsigned i = 0; i != NumComponents; ++i) + Components[i] = _Components[i]; + + // Check some invariants. + unsigned AccessedSize = 0; + for (unsigned i = 0, e = getNumComponents(); i != e; ++i) { + const AccessInfo &AI = getComponent(i); + AccessedSize += AI.TargetBitWidth; + + // We shouldn't try to load 0 bits. + assert(AI.TargetBitWidth > 0); + + // We can't load more bits than we accessed. + assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth); + + // We shouldn't put any bits outside the result size. + assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size); + } + + // Check that the total number of target bits matches the total bit-field + // size. + assert(AccessedSize == Size && "Total size does not match accessed size!"); + } + +public: + /// \brief Check whether this bit-field access is (i.e., should be sign + /// extended on loads). + bool isSigned() const { return IsSigned; } + + /// \brief Get the size of the bit-field, in bits. + unsigned getSize() const { return Size; } + + /// @name Component Access + /// @{ + + unsigned getNumComponents() const { return NumComponents; } + + const AccessInfo &getComponent(unsigned Index) const { + assert(Index < getNumComponents() && "Invalid access!"); + return Components[Index]; + } + + /// @} + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; /// CGRecordLayout - This class handles struct and union layout info while @@ -71,15 +186,15 @@ public: return ContainsPointerToDataMember; } - /// \brief Return the BitFieldInfo that corresponds to the field FD. + /// \brief Return llvm::StructType element number that corresponds to the + /// field FD. unsigned getLLVMFieldNo(const FieldDecl *FD) const { assert(!FD->isBitField() && "Invalid call for bit-field decl!"); assert(FieldInfo.count(FD) && "Invalid field for record!"); return FieldInfo.lookup(FD); } - /// \brief Return llvm::StructType element number that corresponds to the - /// field FD. + /// \brief Return the BitFieldInfo that corresponds to the field FD. const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const { assert(FD->isBitField() && "Invalid call for non bit-field decl!"); llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator @@ -87,6 +202,9 @@ public: assert(it != BitFields.end() && "Unable to find bitfield info"); return it->second; } + + void print(llvm::raw_ostream &OS) const; + void dump() const; }; } // end namespace CodeGen diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 4b9ec66..6302cf8 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -18,8 +18,10 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "CodeGenTypes.h" -#include "llvm/Type.h" #include "llvm/DerivedTypes.h" +#include "llvm/Type.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" using namespace clang; using namespace CodeGen; @@ -67,6 +69,11 @@ private: /// NextFieldOffsetInBytes - Holds the next field offset in bytes. uint64_t NextFieldOffsetInBytes; + /// LayoutUnionField - Will layout a field in an union and return the type + /// that the field will have. + const llvm::Type *LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout); + /// LayoutUnion - Will layout a union RecordDecl. void LayoutUnion(const RecordDecl *D); @@ -87,10 +94,6 @@ private: /// AppendField - Appends a field with the given offset and type. void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total struct - /// size matches the alignment of the passed in type. - void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); - /// AppendPadding - Appends enough padding bytes so that the total /// struct size is a multiple of the field alignment. void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); @@ -103,7 +106,6 @@ private: void AppendTailPadding(uint64_t RecordSize); unsigned getTypeAlignment(const llvm::Type *Ty) const; - uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; /// CheckForPointerToDataMember - Check if the given type contains a pointer /// to data member. @@ -145,6 +147,104 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutFields(D); } +static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, + const FieldDecl *FD, + uint64_t FieldOffset, + uint64_t FieldSize) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); + uint64_t ContainingTypeSizeInBits = RL.getSize(); + unsigned ContainingTypeAlign = RL.getAlignment(); + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType()); + uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty); + uint64_t TypeSizeInBits = TypeSizeInBytes * 8; + + bool IsSigned = FD->getType()->isSignedIntegerType(); + + if (FieldSize > TypeSizeInBits) { + // We have a wide bit-field. The extra bits are only used for padding, so + // if we have a bitfield of type T, with size N: + // + // T t : N; + // + // We can just assume that it's: + // + // T t : sizeof(T); + // + FieldSize = TypeSizeInBits; + } + + // Compute the access components. The policy we use is to start by attempting + // to access using the width of the bit-field type itself and to always access + // at aligned indices of that type. If such an access would fail because it + // extends past the bound of the type, then we reduce size to the next smaller + // power of two and retry. The current algorithm assumes pow2 sized types, + // although this is easy to fix. + // + // FIXME: This algorithm is wrong on big-endian systems, I think. + assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!"); + CGBitFieldInfo::AccessInfo Components[3]; + unsigned NumComponents = 0; + unsigned AccessedTargetBits = 0; // The tumber of target bits accessed. + unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt. + + // Round down from the field offset to find the first access position that is + // at an aligned offset of the initial access type. + uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth); + + // Adjust initial access size to fit within record. + while (AccessWidth > 8 && + AccessStart + AccessWidth > ContainingTypeSizeInBits) { + AccessWidth >>= 1; + AccessStart = FieldOffset - (FieldOffset % AccessWidth); + } + + while (AccessedTargetBits < FieldSize) { + // Check that we can access using a type of this size, without reading off + // the end of the structure. This can occur with packed structures and + // -fno-bitfield-type-align, for example. + if (AccessStart + AccessWidth > ContainingTypeSizeInBits) { + // If so, reduce access size to the next smaller power-of-two and retry. + AccessWidth >>= 1; + assert(AccessWidth >= 8 && "Cannot access under byte size!"); + continue; + } + + // Otherwise, add an access component. + + // First, compute the bits inside this access which are part of the + // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the + // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits + // in the target that we are reading. + assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!"); + assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!"); + uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset); + uint64_t AccessBitsInFieldSize = + std::min(AccessWidth + AccessStart, + FieldOffset + FieldSize) - AccessBitsInFieldStart; + + assert(NumComponents < 3 && "Unexpected number of components!"); + CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++]; + AI.FieldIndex = 0; + // FIXME: We still follow the old access pattern of only using the field + // byte offset. We should switch this once we fix the struct layout to be + // pretty. + AI.FieldByteOffset = AccessStart / 8; + AI.FieldBitStart = AccessBitsInFieldStart - AccessStart; + AI.AccessWidth = AccessWidth; + AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8; + AI.TargetBitOffset = AccessedTargetBits; + AI.TargetBitWidth = AccessBitsInFieldSize; + + AccessStart += AccessWidth; + AccessedTargetBits += AI.TargetBitWidth; + } + + assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!"); + return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned); +} + void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, uint64_t FieldOffset) { uint64_t FieldSize = @@ -175,14 +275,9 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, assert(NumBytesToAppend && "No bytes to append!"); } - const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); - uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8; - - bool IsSigned = D->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - D, CGBitFieldInfo(FieldOffset / TypeSizeInBits, - FieldOffset % TypeSizeInBits, - FieldSize, IsSigned))); + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize))); AppendBytes(NumBytesToAppend); @@ -254,6 +349,35 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, return true; } +const llvm::Type * +CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, + const ASTRecordLayout &Layout) { + if (Field->isBitField()) { + uint64_t FieldSize = + Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + // Ignore zero sized bit fields. + if (FieldSize == 0) + return 0; + + const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext()); + unsigned NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize, 8) / 8; + + if (NumBytesToAppend > 1) + FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend); + + // Add the bit field info. + LLVMBitFields.push_back( + LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize))); + return FieldTy; + } + + // This is a regular union field. + LLVMFields.push_back(LLVMFieldInfo(Field, 0)); + return Types.ConvertTypeForMemRecursive(Field->getType()); +} + void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!"); @@ -270,28 +394,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { assert(Layout.getFieldOffset(FieldNo) == 0 && "Union field offset did not start at the beginning of record!"); + const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout); - if (Field->isBitField()) { - uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); - - // Ignore zero sized bit fields. - if (FieldSize == 0) - continue; - - // Add the bit field info. - bool IsSigned = Field->getType()->isSignedIntegerType(); - LLVMBitFields.push_back(LLVMBitFieldInfo( - *Field, CGBitFieldInfo(0, 0, FieldSize, - IsSigned))); - } else { - LLVMFields.push_back(LLVMFieldInfo(*Field, 0)); - } + if (!FieldTy) + continue; HasOnlyZeroSizedBitFields = false; - const llvm::Type *FieldTy = - Types.ConvertTypeForMemRecursive(Field->getType()); unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy); @@ -334,7 +443,7 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD, llvm::Type::getInt8PtrTy(Types.getLLVMContext()); assert(NextFieldOffsetInBytes == 0 && - "Vtable pointer must come first!"); + "VTable pointer must come first!"); AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); } } @@ -388,7 +497,7 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, getTypeAlignment(FieldTy)); - uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy); + uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy); FieldTypes.push_back(FieldTy); @@ -396,12 +505,6 @@ void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, BitsAvailableInLastField = 0; } -void -CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, - const llvm::Type *FieldTy) { - AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy)); -} - void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment) { assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && @@ -439,10 +542,6 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { return Types.getTargetData().getABITypeAlignment(Ty); } -uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { - return Types.getTargetData().getTypeAllocSize(Ty); -} - void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { // This record already contains a member pointer. if (ContainsPointerToDataMember) @@ -481,9 +580,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(), Builder.FieldTypes, Builder.Packed); - assert(getContext().getASTRecordLayout(D).getSize() / 8 == - getTargetData().getTypeAllocSize(Ty) && - "Type size mismatch!"); CGRecordLayout *RL = new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); @@ -496,5 +592,121 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) RL->BitFields.insert(Builder.LLVMBitFields[i]); + // Dump the layout, if requested. + if (getContext().getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping IRgen Record Layout\n"; + llvm::errs() << "Record: "; + D->dump(); + llvm::errs() << "\nLayout: "; + RL->dump(); + } + +#ifndef NDEBUG + // Verify that the computed LLVM struct size matches the AST layout size. + uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize(); + assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && + "Type size mismatch!"); + + // Verify that the LLVM and AST field offsets agree. + const llvm::StructType *ST = + dyn_cast<llvm::StructType>(RL->getLLVMType()); + const llvm::StructLayout *SL = getTargetData().getStructLayout(ST); + + const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); + RecordDecl::field_iterator it = D->field_begin(); + for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { + const FieldDecl *FD = *it; + + // For non-bit-fields, just check that the LLVM struct offset matches the + // AST offset. + if (!FD->isBitField()) { + unsigned FieldNo = RL->getLLVMFieldNo(FD); + assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && + "Invalid field offset!"); + continue; + } + + // Ignore unnamed bit-fields. + if (!FD->getDeclName()) + continue; + + const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); + for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { + const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); + + // Verify that every component access is within the structure. + uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex); + uint64_t AccessBitOffset = FieldOffset + AI.FieldByteOffset * 8; + assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits && + "Invalid bit-field access (out of range)!"); + } + } +#endif + return RL; } + +void CGRecordLayout::print(llvm::raw_ostream &OS) const { + OS << "<CGRecordLayout\n"; + OS << " LLVMType:" << *LLVMType << "\n"; + OS << " ContainsPointerToDataMember:" << ContainsPointerToDataMember << "\n"; + OS << " BitFields:[\n"; + + // Print bit-field infos in declaration order. + std::vector<std::pair<unsigned, const CGBitFieldInfo*> > BFIs; + for (llvm::DenseMap<const FieldDecl*, CGBitFieldInfo>::const_iterator + it = BitFields.begin(), ie = BitFields.end(); + it != ie; ++it) { + const RecordDecl *RD = it->first->getParent(); + unsigned Index = 0; + for (RecordDecl::field_iterator + it2 = RD->field_begin(); *it2 != it->first; ++it2) + ++Index; + BFIs.push_back(std::make_pair(Index, &it->second)); + } + llvm::array_pod_sort(BFIs.begin(), BFIs.end()); + for (unsigned i = 0, e = BFIs.size(); i != e; ++i) { + OS.indent(4); + BFIs[i].second->print(OS); + OS << "\n"; + } + + OS << "]>\n"; +} + +void CGRecordLayout::dump() const { + print(llvm::errs()); +} + +void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { + OS << "<CGBitFieldInfo"; + OS << " Size:" << Size; + OS << " IsSigned:" << IsSigned << "\n"; + + OS.indent(4 + strlen("<CGBitFieldInfo")); + OS << " NumComponents:" << getNumComponents(); + OS << " Components: ["; + if (getNumComponents()) { + OS << "\n"; + for (unsigned i = 0, e = getNumComponents(); i != e; ++i) { + const AccessInfo &AI = getComponent(i); + OS.indent(8); + OS << "<AccessInfo" + << " FieldIndex:" << AI.FieldIndex + << " FieldByteOffset:" << AI.FieldByteOffset + << " FieldBitStart:" << AI.FieldBitStart + << " AccessWidth:" << AI.AccessWidth << "\n"; + OS.indent(8 + strlen("<AccessInfo")); + OS << " AccessAlignment:" << AI.AccessAlignment + << " TargetBitOffset:" << AI.TargetBitOffset + << " TargetBitWidth:" << AI.TargetBitWidth + << ">\n"; + } + OS.indent(4); + } + OS << "]>"; +} + +void CGBitFieldInfo::dump() const { + print(llvm::errs()); +} diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index ae2f791..a914c80d 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -160,7 +160,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EmitStmt(*I); if (DI) { - DI->setLocation(S.getLBracLoc()); + DI->setLocation(S.getRBracLoc()); DI->EmitRegionEnd(CurFn, Builder); } @@ -205,6 +205,8 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { } void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); + // Fall out of the current block (if necessary). EmitBranch(BB); @@ -225,7 +227,12 @@ void CodeGenFunction::EmitBlock(llvm::BasicBlock *BB, bool IsFinished) { } } - CurFn->getBasicBlockList().push_back(BB); + // Place the block after the current block, if possible, or else at + // the end of the function. + if (CurBB && CurBB->getParent()) + CurFn->getBasicBlockList().insertAfter(CurBB, BB); + else + CurFn->getBasicBlockList().push_back(BB); Builder.SetInsertPoint(BB); } @@ -974,19 +981,18 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { unsigned InputNo; for (InputNo = 0; InputNo != S.getNumInputs(); ++InputNo) { TargetInfo::ConstraintInfo &Input = InputConstraintInfos[InputNo]; - if (Input.hasTiedOperand() && - Input.getTiedOperand() == i) + if (Input.hasTiedOperand() && Input.getTiedOperand() == i) break; } assert(InputNo != S.getNumInputs() && "Didn't find matching input!"); QualType InputTy = S.getInputExpr(InputNo)->getType(); - QualType OutputTy = OutExpr->getType(); + QualType OutputType = OutExpr->getType(); uint64_t InputSize = getContext().getTypeSize(InputTy); - if (getContext().getTypeSize(OutputTy) < InputSize) { - // Form the asm to return the value as a larger integer type. - ResultRegTypes.back() = llvm::IntegerType::get(VMContext, (unsigned)InputSize); + if (getContext().getTypeSize(OutputType) < InputSize) { + // Form the asm to return the value as a larger integer or fp type. + ResultRegTypes.back() = ConvertType(InputTy); } } } else { @@ -1036,17 +1042,20 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // that is usually cheaper, but LLVM IR should really get an anyext someday. if (Info.hasTiedOperand()) { unsigned Output = Info.getTiedOperand(); - QualType OutputTy = S.getOutputExpr(Output)->getType(); + QualType OutputType = S.getOutputExpr(Output)->getType(); QualType InputTy = InputExpr->getType(); - if (getContext().getTypeSize(OutputTy) > + if (getContext().getTypeSize(OutputType) > getContext().getTypeSize(InputTy)) { // Use ptrtoint as appropriate so that we can do our extension. if (isa<llvm::PointerType>(Arg->getType())) Arg = Builder.CreatePtrToInt(Arg, - llvm::IntegerType::get(VMContext, LLVMPointerWidth)); - unsigned OutputSize = (unsigned)getContext().getTypeSize(OutputTy); - Arg = Builder.CreateZExt(Arg, llvm::IntegerType::get(VMContext, OutputSize)); + llvm::IntegerType::get(VMContext, LLVMPointerWidth)); + const llvm::Type *OutputTy = ConvertType(OutputType); + if (isa<llvm::IntegerType>(OutputTy)) + Arg = Builder.CreateZExt(Arg, OutputTy); + else + Arg = Builder.CreateFPExt(Arg, OutputTy); } } @@ -1102,6 +1111,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::CallInst *Result = Builder.CreateCall(IA, Args.begin(), Args.end()); Result->addAttribute(~0, llvm::Attribute::NoUnwind); + // Slap the source location of the inline asm into a !srcloc metadata on the + // call. + unsigned LocID = S.getAsmString()->getLocStart().getRawEncoding(); + llvm::Value *LocIDC = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), LocID); + Result->setMetadata("srcloc", llvm::MDNode::get(VMContext, &LocIDC, 1)); // Extract all of the register value results from the asm. std::vector<llvm::Value*> RegResults; @@ -1121,14 +1136,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { const llvm::Type *TruncTy = ResultTruncRegTypes[i]; - // Truncate the integer result to the right size, note that - // ResultTruncRegTypes can be a pointer. - uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); - Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, (unsigned)ResSize)); - - if (Tmp->getType() != TruncTy) { - assert(isa<llvm::PointerType>(TruncTy)); + + // Truncate the integer result to the right size, note that TruncTy can be + // a pointer. + if (TruncTy->isFloatingPointTy()) + Tmp = Builder.CreateFPTrunc(Tmp, TruncTy); + else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) { + uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); + Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)ResSize)); Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); + } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) { + uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType()); + Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(VMContext, + (unsigned)TmpSize)); + Tmp = Builder.CreateTrunc(Tmp, TruncTy); + } else if (TruncTy->isIntegerTy()) { + Tmp = Builder.CreateTrunc(Tmp, TruncTy); } } diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index 6d38ab9..a8f0467 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, "Pushed the same temporary twice; AST is likely wrong"); llvm::BasicBlock *DtorBlock = createBasicBlock("temp.dtor"); - llvm::Value *CondPtr = 0; + llvm::AllocaInst *CondPtr = 0; // Check if temporaries need to be conditional. If so, we'll create a // condition boolean, initialize it to 0 and @@ -32,10 +32,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, // Initialize it to false. This initialization takes place right after // the alloca insert point. - llvm::StoreInst *SI = - new llvm::StoreInst(llvm::ConstantInt::getFalse(VMContext), CondPtr); - llvm::BasicBlock *Block = AllocaInsertPt->getParent(); - Block->getInstList().insertAfter((llvm::Instruction *)AllocaInsertPt, SI); + InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); // Now set it to true. Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); @@ -64,7 +61,8 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary, } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, + Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. @@ -107,7 +105,7 @@ void CodeGenFunction::PopCXXTemporary() { } EmitCXXDestructorCall(Info.Temporary->getDestructor(), - Dtor_Complete, Info.ThisPtr); + Dtor_Complete, /*ForVirtualBase=*/false, Info.ThisPtr); if (CondEnd) { // Reset the condition. to false. diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 91d9f76..15e5648 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -43,7 +43,7 @@ class VTTBuilder { /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived /// class. - llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of /// all subobjects of the most derived class. @@ -116,8 +116,7 @@ public: } /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. - const llvm::DenseMap<const CXXRecordDecl *, uint64_t> & - getSubVTTIndicies() const { + const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const { return SubVTTIndicies; } @@ -179,13 +178,14 @@ void VTTBuilder::AddVTablePointer(BaseSubobject Base, llvm::Constant *VTable, // The vtable is a construction vtable, look in the construction vtable // address points. AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint != 0 && "Did not find ctor vtable address point!"); } else { // Just get the address point for the regular vtable. AddressPoint = CGM.getVTables().getAddressPoint(Base, VTableClass); + assert(AddressPoint != 0 && "Did not find vtable address point!"); } if (!AddressPoint) AddressPoint = 0; - assert(AddressPoint != 0 && "Did not find an address point!"); llvm::Value *Idxs[] = { llvm::ConstantInt::get(llvm::Type::getInt64Ty(CGM.getLLVMContext()), 0), @@ -340,7 +340,7 @@ void VTTBuilder::LayoutVTT(BaseSubobject Base, bool BaseIsVirtual) { if (!IsPrimaryVTT) { // Remember the sub-VTT index. - SubVTTIndicies[RD] = VTTComponents.size(); + SubVTTIndicies[Base] = VTTComponents.size(); } AddressPointsMapTy AddressPoints; @@ -434,25 +434,25 @@ bool CodeGenVTables::needsVTTParameter(GlobalDecl GD) { } uint64_t CodeGenVTables::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { - ClassPairTy ClassPair(RD, Base); + BaseSubobject Base) { + BaseSubobjectPairTy ClassSubobjectPair(RD, Base); - SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassPair); + SubVTTIndiciesMapTy::iterator I = SubVTTIndicies.find(ClassSubobjectPair); if (I != SubVTTIndicies.end()) return I->second; VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/false); - for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::const_iterator I = + for (llvm::DenseMap<BaseSubobject, uint64_t>::const_iterator I = Builder.getSubVTTIndicies().begin(), E = Builder.getSubVTTIndicies().end(); I != E; ++I) { // Insert all indices. - ClassPairTy ClassPair(RD, I->first); + BaseSubobjectPairTy ClassSubobjectPair(RD, I->first); - SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + SubVTTIndicies.insert(std::make_pair(ClassSubobjectPair, I->second)); } - I = SubVTTIndicies.find(ClassPair); + I = SubVTTIndicies.find(ClassSubobjectPair); assert(I != SubVTTIndicies.end() && "Did not find index!"); return I->second; diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVTables.cpp index fc6d1a8..159753a 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -1,4 +1,4 @@ -//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===// +//===--- CGVTables.cpp - Emit LLVM Code for C++ vtables -------------------===// // // The LLVM Compiler Infrastructure // @@ -573,8 +573,8 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) { } } -/// VtableComponent - Represents a single component in a vtable. -class VtableComponent { +/// VTableComponent - Represents a single component in a vtable. +class VTableComponent { public: enum Kind { CK_VCallOffset, @@ -595,49 +595,49 @@ public: CK_UnusedFunctionPointer }; - static VtableComponent MakeVCallOffset(int64_t Offset) { - return VtableComponent(CK_VCallOffset, Offset); + static VTableComponent MakeVCallOffset(int64_t Offset) { + return VTableComponent(CK_VCallOffset, Offset); } - static VtableComponent MakeVBaseOffset(int64_t Offset) { - return VtableComponent(CK_VBaseOffset, Offset); + static VTableComponent MakeVBaseOffset(int64_t Offset) { + return VTableComponent(CK_VBaseOffset, Offset); } - static VtableComponent MakeOffsetToTop(int64_t Offset) { - return VtableComponent(CK_OffsetToTop, Offset); + static VTableComponent MakeOffsetToTop(int64_t Offset) { + return VTableComponent(CK_OffsetToTop, Offset); } - static VtableComponent MakeRTTI(const CXXRecordDecl *RD) { - return VtableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); + static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); } - static VtableComponent MakeFunction(const CXXMethodDecl *MD) { + static VTableComponent MakeFunction(const CXXMethodDecl *MD) { assert(!isa<CXXDestructorDecl>(MD) && "Don't use MakeFunction with destructors!"); - return VtableComponent(CK_FunctionPointer, + return VTableComponent(CK_FunctionPointer, reinterpret_cast<uintptr_t>(MD)); } - static VtableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_CompleteDtorPointer, + static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_CompleteDtorPointer, reinterpret_cast<uintptr_t>(DD)); } - static VtableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { - return VtableComponent(CK_DeletingDtorPointer, + static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_DeletingDtorPointer, reinterpret_cast<uintptr_t>(DD)); } - static VtableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { assert(!isa<CXXDestructorDecl>(MD) && "Don't use MakeUnusedFunction with destructors!"); - return VtableComponent(CK_UnusedFunctionPointer, + return VTableComponent(CK_UnusedFunctionPointer, reinterpret_cast<uintptr_t>(MD)); } - static VtableComponent getFromOpaqueInteger(uint64_t I) { - return VtableComponent(I); + static VTableComponent getFromOpaqueInteger(uint64_t I) { + return VTableComponent(I); } /// getKind - Get the kind of this vtable component. @@ -689,7 +689,7 @@ public: } private: - VtableComponent(Kind ComponentKind, int64_t Offset) { + VTableComponent(Kind ComponentKind, int64_t Offset) { assert((ComponentKind == CK_VCallOffset || ComponentKind == CK_VBaseOffset || ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); @@ -698,7 +698,7 @@ private: Value = ((Offset << 3) | ComponentKind); } - VtableComponent(Kind ComponentKind, uintptr_t Ptr) { + VTableComponent(Kind ComponentKind, uintptr_t Ptr) { assert((ComponentKind == CK_RTTI || ComponentKind == CK_FunctionPointer || ComponentKind == CK_CompleteDtorPointer || @@ -729,7 +729,7 @@ private: return static_cast<uintptr_t>(Value & ~7ULL); } - explicit VtableComponent(uint64_t Value) + explicit VTableComponent(uint64_t Value) : Value(Value) { } /// The kind is stored in the lower 3 bits of the value. For offsets, we @@ -855,8 +855,8 @@ private: ASTContext &Context; /// Components - vcall and vbase offset components - typedef llvm::SmallVector<VtableComponent, 64> VtableComponentVectorTy; - VtableComponentVectorTy Components; + typedef llvm::SmallVector<VTableComponent, 64> VTableComponentVectorTy; + VTableComponentVectorTy Components; /// VisitedVirtualBases - Visited virtual bases. llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; @@ -902,7 +902,7 @@ public: } /// Methods for iterating over the components. - typedef VtableComponentVectorTy::const_reverse_iterator const_iterator; + typedef VTableComponentVectorTy::const_reverse_iterator const_iterator; const_iterator components_begin() const { return Components.rbegin(); } const_iterator components_end() const { return Components.rend(); } @@ -982,30 +982,17 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); // Handle the primary base first. - if (PrimaryBase) { - uint64_t PrimaryBaseOffset; - + // We only want to add vcall offsets if the base is non-virtual; a virtual + // primary base will have its vcall and vbase offsets emitted already. + if (PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) { // Get the base offset of the primary base. - if (Layout.getPrimaryBaseWasVirtual()) { - assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && - "Primary vbase should have a zero offset!"); - - const ASTRecordLayout &MostDerivedClassLayout = - Context.getASTRecordLayout(MostDerivedClass); - - PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); - } else { - assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && - "Primary base should have a zero offset!"); + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); - PrimaryBaseOffset = Base.getBaseOffset(); - } - - AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + AddVCallOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), VBaseOffset); } - + // Add the vcall offsets. for (CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { @@ -1034,7 +1021,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; } - Components.push_back(VtableComponent::MakeVCallOffset(Offset)); + Components.push_back(VTableComponent::MakeVCallOffset(Offset)); } // And iterate over all non-virtual bases (ignoring the primary base). @@ -1082,7 +1069,7 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); - Components.push_back(VtableComponent::MakeVBaseOffset(Offset)); + Components.push_back(VTableComponent::MakeVBaseOffset(Offset)); } // Check the base class looking for more vbase offsets. @@ -1090,8 +1077,8 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, } } -/// VtableBuilder - Class for building vtable layout information. -class VtableBuilder { +/// VTableBuilder - Class for building vtable layout information. +class VTableBuilder { public: /// PrimaryBasesSetVectorTy - A set vector of direct and indirect /// primary bases. @@ -1140,7 +1127,7 @@ private: VBaseOffsetOffsetsMapTy VBaseOffsetOffsets; /// Components - The components of the vtable being built. - llvm::SmallVector<VtableComponent, 64> Components; + llvm::SmallVector<VTableComponent, 64> Components; /// AddressPoints - Address points for the vtable being built. AddressPointsMapTy AddressPoints; @@ -1155,17 +1142,17 @@ private: /// method. const uint64_t BaseOffsetInLayoutClass; - /// VtableIndex - The index in the vtable that this method has. + /// VTableIndex - The index in the vtable that this method has. /// (For destructors, this is the index of the complete destructor). - const uint64_t VtableIndex; + const uint64_t VTableIndex; MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, - uint64_t VtableIndex) + uint64_t VTableIndex) : BaseOffset(BaseOffset), BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), - VtableIndex(VtableIndex) { } + VTableIndex(VTableIndex) { } - MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VtableIndex(0) { } + MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { } }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -1174,11 +1161,11 @@ private: /// currently building. MethodInfoMapTy MethodInfoMap; - typedef llvm::DenseMap<uint64_t, ThunkInfo> VtableThunksMapTy; + typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy; /// VTableThunks - The thunks by vtable index in the vtable currently being /// built. - VtableThunksMapTy VTableThunks; + VTableThunksMapTy VTableThunks; typedef llvm::SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; @@ -1253,22 +1240,29 @@ private: uint64_t FirstBaseOffsetInLayoutClass, PrimaryBasesSetVectorTy &PrimaryBases); - // LayoutVtable - Layout the vtable for the given base class, including its + // LayoutVTable - Layout the vtable for the given base class, including its // secondary vtables and any vtables for virtual bases. - void LayoutVtable(); + void LayoutVTable(); - /// LayoutPrimaryAndSecondaryVtables - Layout the primary vtable for the + /// LayoutPrimaryAndSecondaryVTables - Layout the primary vtable for the /// given base subobject, as well as all its secondary vtables. - void LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param BaseIsVirtualInLayoutClass - Whether the base subobject is virtual + /// in the layout class. + void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, uint64_t OffsetInLayoutClass); - /// LayoutSecondaryVtables - Layout the secondary vtables for the given base + /// LayoutSecondaryVTables - Layout the secondary vtables for the given base /// subobject. /// /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base /// or a direct or indirect base of a virtual base. - void LayoutSecondaryVtables(BaseSubobject Base, bool BaseIsMorallyVirtual, + void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, uint64_t OffsetInLayoutClass); /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this @@ -1277,19 +1271,19 @@ private: uint64_t OffsetInLayoutClass, VisitedVirtualBasesSetTy &VBases); - /// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the + /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the /// given base (excluding any primary bases). - void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, + void LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases); - /// isBuildingConstructionVtable - Return whether this vtable builder is + /// isBuildingConstructionVTable - Return whether this vtable builder is /// building a construction vtable. - bool isBuildingConstructorVtable() const { + bool isBuildingConstructorVTable() const { return MostDerivedClass != LayoutClass; } public: - VtableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, + VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) : VTables(VTables), MostDerivedClass(MostDerivedClass), @@ -1298,7 +1292,7 @@ public: LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) { - LayoutVtable(); + LayoutVTable(); } ThunksMapTy::const_iterator thunks_begin() const { @@ -1335,11 +1329,11 @@ public: return AddressPoints.end(); } - VtableThunksMapTy::const_iterator vtable_thunks_begin() const { + VTableThunksMapTy::const_iterator vtable_thunks_begin() const { return VTableThunks.begin(); } - VtableThunksMapTy::const_iterator vtable_thunks_end() const { + VTableThunksMapTy::const_iterator vtable_thunks_end() const { return VTableThunks.end(); } @@ -1347,8 +1341,8 @@ public: void dumpLayout(llvm::raw_ostream&); }; -void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { - assert(!isBuildingConstructorVtable() && +void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { + assert(!isBuildingConstructorVTable() && "Can't add thunks for construction vtable"); llvm::SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD]; @@ -1361,27 +1355,26 @@ void VtableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) { ThunksVector.push_back(Thunk); } -/// OverridesMethodInBases - Checks whether whether this virtual member -/// function overrides a member function in any of the given bases. -/// Returns the overridden member function, or null if none was found. -static const CXXMethodDecl * -OverridesMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { +typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy; + +/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all +/// the overridden methods that the function decl overrides. +static void +ComputeAllOverriddenMethods(const CXXMethodDecl *MD, + OverriddenMethodsSetTy& OverriddenMethods) { + assert(MD->isVirtual() && "Method is not virtual!"); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - assert(OverriddenMD->isCanonicalDecl() && - "Should have the canonical decl of the overridden RD!"); - if (Bases.count(OverriddenRD)) - return OverriddenMD; + OverriddenMethods.insert(OverriddenMD); + + ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods); } - - return 0; } -void VtableBuilder::ComputeThisAdjustments() { +void VTableBuilder::ComputeThisAdjustments() { // Now go through the method info map and see if any of the methods need // 'this' pointer adjustments. for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), @@ -1390,9 +1383,9 @@ void VtableBuilder::ComputeThisAdjustments() { const MethodInfo &MethodInfo = I->second; // Ignore adjustments for unused function pointers. - uint64_t VtableIndex = MethodInfo.VtableIndex; - if (Components[VtableIndex].getKind() == - VtableComponent::CK_UnusedFunctionPointer) + uint64_t VTableIndex = MethodInfo.VTableIndex; + if (Components[VTableIndex].getKind() == + VTableComponent::CK_UnusedFunctionPointer) continue; // Get the final overrider for this method. @@ -1407,7 +1400,7 @@ void VtableBuilder::ComputeThisAdjustments() { // While the thunk itself might be needed by vtables in subclasses or // in construction vtables, there doesn't seem to be a reason for using // the thunk in this vtable. Still, we do so to match gcc. - if (VTableThunks.lookup(VtableIndex).Return.isEmpty()) + if (VTableThunks.lookup(VTableIndex).Return.isEmpty()) continue; } @@ -1418,38 +1411,38 @@ void VtableBuilder::ComputeThisAdjustments() { continue; // Add it. - VTableThunks[VtableIndex].This = ThisAdjustment; + VTableThunks[VTableIndex].This = ThisAdjustment; if (isa<CXXDestructorDecl>(MD)) { // Add an adjustment for the deleting destructor as well. - VTableThunks[VtableIndex + 1].This = ThisAdjustment; + VTableThunks[VTableIndex + 1].This = ThisAdjustment; } } /// Clear the method info map. MethodInfoMap.clear(); - if (isBuildingConstructorVtable()) { + if (isBuildingConstructorVTable()) { // We don't need to store thunk information for construction vtables. return; } - for (VtableThunksMapTy::const_iterator I = VTableThunks.begin(), + for (VTableThunksMapTy::const_iterator I = VTableThunks.begin(), E = VTableThunks.end(); I != E; ++I) { - const VtableComponent &Component = Components[I->first]; + const VTableComponent &Component = Components[I->first]; const ThunkInfo &Thunk = I->second; const CXXMethodDecl *MD; switch (Component.getKind()) { default: llvm_unreachable("Unexpected vtable component kind!"); - case VtableComponent::CK_FunctionPointer: + case VTableComponent::CK_FunctionPointer: MD = Component.getFunctionDecl(); break; - case VtableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_CompleteDtorPointer: MD = Component.getDestructorDecl(); break; - case VtableComponent::CK_DeletingDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: // We've already added the thunk when we saw the complete dtor pointer. continue; } @@ -1459,7 +1452,7 @@ void VtableBuilder::ComputeThisAdjustments() { } } -ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { +ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { @@ -1474,11 +1467,6 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, Offset.VirtualBase); } - - // FIXME: Once the assert in getVirtualBaseOffsetOffset is back again, - // we can get rid of this assert. - assert(Adjustment.VBaseOffsetOffset != 0 && - "Invalid vbase offset offset!"); } Adjustment.NonVirtual = Offset.NonVirtualOffset; @@ -1488,7 +1476,7 @@ ReturnAdjustment VtableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { } BaseOffset -VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, +VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, BaseSubobject Derived) const { const CXXRecordDecl *BaseRD = Base.getBase(); const CXXRecordDecl *DerivedRD = Derived.getBase(); @@ -1540,7 +1528,7 @@ VtableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, } ThisAdjustment -VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, +VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, uint64_t BaseOffsetInLayoutClass, FinalOverriders::OverriderInfo Overrider) { // Ignore adjustments for pure virtual member functions. @@ -1587,22 +1575,22 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, } void -VtableBuilder::AddMethod(const CXXMethodDecl *MD, +VTableBuilder::AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { assert(ReturnAdjustment.isEmpty() && "Destructor can't have return adjustment!"); // Add both the complete destructor and the deleting destructor. - Components.push_back(VtableComponent::MakeCompleteDtor(DD)); - Components.push_back(VtableComponent::MakeDeletingDtor(DD)); + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) VTableThunks[Components.size()].Return = ReturnAdjustment; // Add the function. - Components.push_back(VtableComponent::MakeFunction(MD)); + Components.push_back(VTableComponent::MakeFunction(MD)); } } @@ -1616,19 +1604,16 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD, /// struct C : B { virtual void f(); } /// /// OverridesIndirectMethodInBase will return true if given C::f as the method -/// and { A } as the set of bases. +/// and { A } as the set of bases. static bool OverridesIndirectMethodInBases(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + if (Bases.count(MD->getParent())) + return true; + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; - const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); - assert(OverriddenMD->isCanonicalDecl() && - "Should have the canonical decl of the overridden RD!"); - - if (Bases.count(OverriddenRD)) - return true; // Check "indirect overriders". if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) @@ -1639,7 +1624,7 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD, } bool -VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, +VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, uint64_t BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, uint64_t FirstBaseOffsetInLayoutClass) const { @@ -1657,7 +1642,7 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, if (Overrider->getParent() == FirstBaseInPrimaryBaseChain) return true; - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain; PrimaryBases.insert(RD); @@ -1705,15 +1690,18 @@ VtableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, /// from the nearest base. Returns null if no method was found. static const CXXMethodDecl * FindNearestOverriddenMethod(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetVectorTy &Bases) { + VTableBuilder::PrimaryBasesSetVectorTy &Bases) { + OverriddenMethodsSetTy OverriddenMethods; + ComputeAllOverriddenMethods(MD, OverriddenMethods); + for (int I = Bases.size(), E = 0; I != E; --I) { const CXXRecordDecl *PrimaryBase = Bases[I - 1]; // Now check the overriden methods. - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); I != E; ++I) { + for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(), + E = OverriddenMethods.end(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; - + // We found our overridden method. if (OverriddenMD->getParent() == PrimaryBase) return OverriddenMD; @@ -1724,7 +1712,7 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD, } void -VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, +VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, uint64_t FirstBaseOffsetInLayoutClass, PrimaryBasesSetVectorTy &PrimaryBases) { @@ -1792,7 +1780,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, - OverriddenMethodInfo.VtableIndex); + OverriddenMethodInfo.VTableIndex); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); @@ -1804,7 +1792,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, // or indirect base class of a virtual base class, we need to emit a // thunk if we ever have a class hierarchy where the base class is not // a primary base in the complete object. - if (!isBuildingConstructorVtable() && OverriddenMD != MD) { + if (!isBuildingConstructorVTable() && OverriddenMD != MD) { // Compute the this adjustment. ThisAdjustment ThisAdjustment = ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass, @@ -1835,7 +1823,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, if (!IsOverriderUsed(OverriderMD, BaseOffsetInLayoutClass, FirstBaseInPrimaryBaseChain, FirstBaseOffsetInLayoutClass)) { - Components.push_back(VtableComponent::MakeUnusedFunction(OverriderMD)); + Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD)); continue; } @@ -1850,8 +1838,9 @@ VtableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, } } -void VtableBuilder::LayoutVtable() { - LayoutPrimaryAndSecondaryVtables(BaseSubobject(MostDerivedClass, 0), +void VTableBuilder::LayoutVTable() { + LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0), + /*BaseIsMorallyVirtual=*/false, MostDerivedClassIsVirtual, MostDerivedClassOffset); @@ -1862,22 +1851,24 @@ void VtableBuilder::LayoutVtable() { VBases); VBases.clear(); - LayoutVtablesForVirtualBases(MostDerivedClass, VBases); + LayoutVTablesForVirtualBases(MostDerivedClass, VBases); } void -VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, - bool BaseIsVirtual, +VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, + bool BaseIsMorallyVirtual, + bool BaseIsVirtualInLayoutClass, uint64_t OffsetInLayoutClass) { assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); // Add vcall and vbase offsets for this vtable. VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, LayoutClass, &Overriders, - Base, BaseIsVirtual, OffsetInLayoutClass); + Base, BaseIsVirtualInLayoutClass, + OffsetInLayoutClass); Components.append(Builder.components_begin(), Builder.components_end()); // Check if we need to add these vcall offsets. - if (BaseIsVirtual && !Builder.getVCallOffsets().empty()) { + if (BaseIsVirtualInLayoutClass && !Builder.getVCallOffsets().empty()) { VCallOffsetMap &VCallOffsets = VCallOffsetsForVBases[Base.getBase()]; if (VCallOffsets.empty()) @@ -1893,10 +1884,10 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, // FIXME: We should not use / 8 here. int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - MostDerivedClassOffset) / 8; - Components.push_back(VtableComponent::MakeOffsetToTop(OffsetToTop)); + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); // Next, add the RTTI. - Components.push_back(VtableComponent::MakeRTTI(MostDerivedClass)); + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); uint64_t AddressPoint = Components.size(); @@ -1936,15 +1927,11 @@ VtableBuilder::LayoutPrimaryAndSecondaryVtables(BaseSubobject Base, RD = PrimaryBase; } - bool BaseIsMorallyVirtual = BaseIsVirtual; - if (isBuildingConstructorVtable() && Base.getBase() == MostDerivedClass) - BaseIsMorallyVirtual = false; - // Layout secondary vtables. - LayoutSecondaryVtables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); + LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass); } -void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, +void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, uint64_t OffsetInLayoutClass) { // Itanium C++ ABI 2.5.2: @@ -1969,7 +1956,7 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, if (!BaseDecl->isDynamicClass()) continue; - if (isBuildingConstructorVtable()) { + if (isBuildingConstructorVTable()) { // Itanium C++ ABI 2.6.4: // Some of the base class subobjects may not need construction virtual // tables, which will therefore not be present in the construction @@ -1988,20 +1975,21 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base, // Don't emit a secondary vtable for a primary base. We might however want // to emit secondary vtables for other bases of this base. if (BaseDecl == PrimaryBase) { - LayoutSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), + LayoutSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), BaseIsMorallyVirtual, BaseOffsetInLayoutClass); continue; } // Layout the primary vtable (and any secondary vtables) for this base. - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/false, + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, + /*BaseIsVirtualInLayoutClass=*/false, BaseOffsetInLayoutClass); } } void -VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, +VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, uint64_t OffsetInLayoutClass, VisitedVirtualBasesSetTy &VBases) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -2013,7 +2001,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, if (Layout.getPrimaryBaseWasVirtual()) { bool IsPrimaryVirtualBase = true; - if (isBuildingConstructorVtable()) { + if (isBuildingConstructorVTable()) { // Check if the base is actually a primary base in the class we use for // layout. const ASTRecordLayout &LayoutClassLayout = @@ -2059,7 +2047,7 @@ VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, } void -VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, +VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { // Itanium C++ ABI 2.5.2: // Then come the virtual base virtual tables, also in inheritance graph @@ -2084,22 +2072,23 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD, uint64_t BaseOffsetInLayoutClass = LayoutClassLayout.getVBaseClassOffset(BaseDecl); - LayoutPrimaryAndSecondaryVtables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsVirtual=*/true, + LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsMorallyVirtual=*/true, + /*BaseIsVirtualInLayoutClass=*/true, BaseOffsetInLayoutClass); } // We only need to check the base for virtual base vtables if it actually // has virtual bases. if (BaseDecl->getNumVBases()) - LayoutVtablesForVirtualBases(BaseDecl, VBases); + LayoutVTablesForVirtualBases(BaseDecl, VBases); } } /// dumpLayout - Dump the vtable layout. -void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { +void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { - if (isBuildingConstructorVtable()) { + if (isBuildingConstructorVTable()) { Out << "Construction vtable for ('"; Out << MostDerivedClass->getQualifiedNameAsString() << "', "; // FIXME: Don't use / 8 . @@ -2129,28 +2118,28 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << llvm::format("%4d | ", I); - const VtableComponent &Component = Components[I]; + const VTableComponent &Component = Components[I]; // Dump the component. switch (Component.getKind()) { - case VtableComponent::CK_VCallOffset: + case VTableComponent::CK_VCallOffset: Out << "vcall_offset (" << Component.getVCallOffset() << ")"; break; - case VtableComponent::CK_VBaseOffset: + case VTableComponent::CK_VBaseOffset: Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; break; - case VtableComponent::CK_OffsetToTop: + case VTableComponent::CK_OffsetToTop: Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; break; - case VtableComponent::CK_RTTI: + case VTableComponent::CK_RTTI: Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI"; break; - case VtableComponent::CK_FunctionPointer: { + case VTableComponent::CK_FunctionPointer: { const CXXMethodDecl *MD = Component.getFunctionDecl(); std::string Str = @@ -2192,10 +2181,10 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { break; } - case VtableComponent::CK_CompleteDtorPointer: - case VtableComponent::CK_DeletingDtorPointer: { + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { bool IsComplete = - Component.getKind() == VtableComponent::CK_CompleteDtorPointer; + Component.getKind() == VTableComponent::CK_CompleteDtorPointer; const CXXDestructorDecl *DD = Component.getDestructorDecl(); @@ -2227,7 +2216,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { break; } - case VtableComponent::CK_UnusedFunctionPointer: { + case VTableComponent::CK_UnusedFunctionPointer: { const CXXMethodDecl *MD = Component.getUnusedFunctionDecl(); std::string Str = @@ -2279,7 +2268,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << '\n'; - if (isBuildingConstructorVtable()) + if (isBuildingConstructorVTable()) return; if (MostDerivedClass->getNumVBases()) { @@ -2373,7 +2362,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { } -void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { +void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { // Itanium C++ ABI 2.5.2: // The order of the virtual function pointers in a virtual table is the @@ -2400,7 +2389,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Collect all the primary bases, so we can check whether methods override // a method from the base. - VtableBuilder::PrimaryBasesSetVectorTy PrimaryBases; + VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases; for (ASTRecordLayout::primary_base_info_iterator I = Layout.primary_base_begin(), E = Layout.primary_base_end(); I != E; ++I) @@ -2418,7 +2407,7 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Check if this method overrides a method in the primary base. if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInBases(MD, PrimaryBases)) { + FindNearestOverriddenMethod(MD, PrimaryBases)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, @@ -2430,12 +2419,12 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { cast<CXXDestructorDecl>(OverriddenMD); // Add both the complete and deleting entries. - MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); } else { - MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD); + MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); } // We don't need to add an entry for this method. @@ -2452,13 +2441,13 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { } // Add the complete dtor. - MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; // Add the deleting dtor. - MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; } else { // Add the entry. - MethodVtableIndices[MD] = CurrentIndex++; + MethodVTableIndices[MD] = CurrentIndex++; } } @@ -2468,11 +2457,11 @@ void CodeGenVTables::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // its entries come after the declared virtual function pointers. // Add the complete dtor. - MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = CurrentIndex++; // Add the deleting dtor. - MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = + MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] = CurrentIndex++; } @@ -2485,24 +2474,24 @@ uint64_t CodeGenVTables::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) if (I != NumVirtualFunctionPointers.end()) return I->second; - ComputeMethodVtableIndices(RD); + ComputeMethodVTableIndices(RD); I = NumVirtualFunctionPointers.find(RD); assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!"); return I->second; } -uint64_t CodeGenVTables::getMethodVtableIndex(GlobalDecl GD) { - MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD); - if (I != MethodVtableIndices.end()) +uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) { + MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD); + if (I != MethodVTableIndices.end()) return I->second; const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent(); - ComputeMethodVtableIndices(RD); + ComputeMethodVTableIndices(RD); - I = MethodVtableIndices.find(GD); - assert(I != MethodVtableIndices.end() && "Did not find index!"); + I = MethodVTableIndices.find(GD); + assert(I != MethodVTableIndices.end() && "Did not find index!"); return I->second; } @@ -2530,13 +2519,6 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, } I = VirtualBaseClassOffsetOffsets.find(ClassPair); - - // FIXME: The assertion below assertion currently fails with the old vtable - /// layout code if there is a non-virtual thunk adjustment in a vtable. - // Once the new layout is in place, this return should be removed. - if (I == VirtualBaseClassOffsetOffsets.end()) - return 0; - assert(I != VirtualBaseClassOffsetOffsets.end() && "Did not find index!"); return I->second; @@ -2544,6 +2526,9 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, uint64_t CodeGenVTables::getAddressPoint(BaseSubobject Base, const CXXRecordDecl *RD) { + assert(AddressPoints.count(std::make_pair(RD, Base)) && + "Did not find address point!"); + uint64_t AddressPoint = AddressPoints.lookup(std::make_pair(RD, Base)); assert(AddressPoint && "Address point must not be zero!"); @@ -2562,7 +2547,7 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, else getMangleContext().mangleThunk(MD, Thunk, Name); - const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD); return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); } @@ -2745,7 +2730,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) // There's already a declaration with the same name, check if it has the same // type or if we need to replace it. if (cast<llvm::GlobalValue>(Entry)->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVtable(MD)) { + CGM.getTypes().GetFunctionTypeForVTable(MD)) { llvm::GlobalValue *OldThunkFn = cast<llvm::GlobalValue>(Entry); // If the types mismatch then we have to rewrite the definition. @@ -2804,7 +2789,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { if (LayoutData) return; - VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); // Add the VTable layout. uint64_t NumVTableComponents = Builder.getNumVTableComponents(); @@ -2833,7 +2818,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { std::sort(VTableThunks.begin(), VTableThunks.end()); // Add the address points. - for (VtableBuilder::AddressPointsMapTy::const_iterator I = + for (VTableBuilder::AddressPointsMapTy::const_iterator I = Builder.address_points_begin(), E = Builder.address_points_end(); I != E; ++I) { @@ -2858,7 +2843,7 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase))) return; - for (VtableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = + for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = Builder.getVBaseOffsetOffsets().begin(), E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) { // Insert all types. @@ -2888,43 +2873,43 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, llvm::Constant* PureVirtualFn = 0; for (unsigned I = 0; I != NumComponents; ++I) { - VtableComponent Component = - VtableComponent::getFromOpaqueInteger(Components[I]); + VTableComponent Component = + VTableComponent::getFromOpaqueInteger(Components[I]); llvm::Constant *Init = 0; switch (Component.getKind()) { - case VtableComponent::CK_VCallOffset: + case VTableComponent::CK_VCallOffset: Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; - case VtableComponent::CK_VBaseOffset: + case VTableComponent::CK_VBaseOffset: Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; - case VtableComponent::CK_OffsetToTop: + case VTableComponent::CK_OffsetToTop: Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; - case VtableComponent::CK_RTTI: + case VTableComponent::CK_RTTI: Init = llvm::ConstantExpr::getBitCast(RTTI, Int8PtrTy); break; - case VtableComponent::CK_FunctionPointer: - case VtableComponent::CK_CompleteDtorPointer: - case VtableComponent::CK_DeletingDtorPointer: { + case VTableComponent::CK_FunctionPointer: + case VTableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: { GlobalDecl GD; // Get the right global decl. switch (Component.getKind()) { default: llvm_unreachable("Unexpected vtable component kind"); - case VtableComponent::CK_FunctionPointer: + case VTableComponent::CK_FunctionPointer: GD = Component.getFunctionDecl(); break; - case VtableComponent::CK_CompleteDtorPointer: + case VTableComponent::CK_CompleteDtorPointer: GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Complete); break; - case VtableComponent::CK_DeletingDtorPointer: + case VTableComponent::CK_DeletingDtorPointer: GD = GlobalDecl(Component.getDestructorDecl(), Dtor_Deleting); break; } @@ -2953,7 +2938,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, NextVTableThunkIndex++; } else { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD); Init = CGM.GetAddrOfFunction(GD, Ty); } @@ -2963,7 +2948,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, break; } - case VtableComponent::CK_UnusedFunctionPointer: + case VTableComponent::CK_UnusedFunctionPointer: Init = llvm::ConstantExpr::getNullValue(Int8PtrTy); break; }; @@ -3020,7 +3005,7 @@ GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVtable(RD, OutName); + CGM.getMangleContext().mangleCXXVTable(RD, OutName); llvm::StringRef Name = OutName.str(); ComputeVTableRelatedInformation(RD); @@ -3038,8 +3023,8 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVtableLayouts) { - VtableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + if (CGM.getLangOptions().DumpVTableLayouts) { + VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); Builder.dumpLayout(llvm::errs()); } @@ -3064,11 +3049,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, bool BaseIsVirtual, VTableAddressPointsMapTy& AddressPoints) { - VtableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), + VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); // Dump the vtable layout if necessary. - if (CGM.getLangOptions().DumpVtableLayouts) + if (CGM.getLangOptions().DumpVTableLayouts) Builder.dumpLayout(llvm::errs()); // Add the address points. @@ -3077,7 +3062,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // Get the mangled construction vtable name. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXCtorVtable(RD, Base.getBaseOffset() / 8, + CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, Base.getBase(), OutName); llvm::StringRef Name = OutName.str(); @@ -3111,9 +3096,9 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, void CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { - llvm::GlobalVariable *&VTable = Vtables[RD]; + llvm::GlobalVariable *&VTable = VTables[RD]; if (VTable) { - assert(VTable->getInitializer() && "Vtable doesn't have a definition!"); + assert(VTable->getInitializer() && "VTable doesn't have a definition!"); return; } @@ -3121,6 +3106,18 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, EmitVTableDefinition(VTable, Linkage, RD); GenerateVTT(Linkage, /*GenerateDefinition=*/true, RD); + + // If this is the magic class __cxxabiv1::__fundamental_type_info, + // we will emit the typeinfo for the fundamental types. This is the + // same behaviour as GCC. + const DeclContext *DC = RD->getDeclContext(); + if (RD->getIdentifier() && + RD->getIdentifier()->isStr("__fundamental_type_info") && + isa<NamespaceDecl>(DC) && + cast<NamespaceDecl>(DC)->getIdentifier() && + cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__cxxabiv1") && + DC->getParent()->isTranslationUnit()) + CGM.EmitFundamentalRTTIDescriptors(); } void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { @@ -3160,11 +3157,11 @@ void CodeGenVTables::EmitVTableRelatedData(GlobalDecl GD) { return; } - if (Vtables.count(RD)) + if (VTables.count(RD)) return; if (RDKind == TSK_ImplicitInstantiation) - CGM.DeferredVtables.push_back(RD); + CGM.DeferredVTables.push_back(RD); else - GenerateClassData(CGM.getVtableLinkage(RD), RD); + GenerateClassData(CGM.getVTableLinkage(RD), RD); } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVTables.h index 6073555..6c18ca8 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVTables.h @@ -1,4 +1,4 @@ -//===--- CGVtable.h - Emit LLVM Code for C++ vtables ----------------------===// +//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===// // // The LLVM Compiler Infrastructure // @@ -180,10 +180,10 @@ namespace CodeGen { class CodeGenVTables { CodeGenModule &CGM; - /// MethodVtableIndices - Contains the index (relative to the vtable address + /// MethodVTableIndices - Contains the index (relative to the vtable address /// point) where the function pointer for a virtual function is stored. - typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy; - MethodVtableIndicesTy MethodVtableIndices; + typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; + MethodVTableIndicesTy MethodVTableIndices; typedef std::pair<const CXXRecordDecl *, const CXXRecordDecl *> ClassPairTy; @@ -195,8 +195,8 @@ class CodeGenVTables { VirtualBaseClassOffsetOffsetsMapTy; VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; - /// Vtables - All the vtables which have been defined. - llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> Vtables; + /// VTables - All the vtables which have been defined. + llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables; /// NumVirtualFunctionPointers - Contains the number of virtual function /// pointers in the vtable for a given record decl. @@ -216,8 +216,8 @@ class CodeGenVTables { /// integers are the vtable components. VTableLayoutMapTy VTableLayoutMap; - typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, - BaseSubobject>, uint64_t> AddressPointsMapTy; + typedef std::pair<const CXXRecordDecl *, BaseSubobject> BaseSubobjectPairTy; + typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> AddressPointsMapTy; /// Address points - Address points for all vtables. AddressPointsMapTy AddressPoints; @@ -247,14 +247,12 @@ class CodeGenVTables { return &Components[1]; } - typedef llvm::DenseMap<ClassPairTy, uint64_t> SubVTTIndiciesMapTy; + typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SubVTTIndiciesMapTy; /// SubVTTIndicies - Contains indices into the various sub-VTTs. SubVTTIndiciesMapTy SubVTTIndicies; - - typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, - BaseSubobject>, uint64_t> + typedef llvm::DenseMap<BaseSubobjectPairTy, uint64_t> SecondaryVirtualPointerIndicesMapTy; /// SecondaryVirtualPointerIndices - Contains the secondary virtual pointer @@ -265,7 +263,7 @@ class CodeGenVTables { /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); - void ComputeMethodVtableIndices(const CXXRecordDecl *RD); + void ComputeMethodVTableIndices(const CXXRecordDecl *RD); llvm::GlobalVariable *GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, bool GenerateDefinition, @@ -295,6 +293,15 @@ public: CodeGenVTables(CodeGenModule &CGM) : CGM(CGM) { } + // isKeyFunctionInAnotherTU - True if this record has a key function and it is + // in another translation unit. + static bool isKeyFunctionInAnotherTU(ASTContext &Context, + const CXXRecordDecl *RD) { + assert (RD->isDynamicClass() && "Non dynamic classes have no key."); + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); + return KeyFunction && !KeyFunction->getBody(); + } + /// needsVTTParameter - Return whether the given global decl needs a VTT /// parameter, which it does if it's a base constructor or destructor with /// virtual bases. @@ -302,17 +309,17 @@ public: /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the /// given record decl. - uint64_t getSubVTTIndex(const CXXRecordDecl *RD, const CXXRecordDecl *Base); + uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base); /// getSecondaryVirtualPointerIndex - Return the index in the VTT where the /// virtual pointer for the given subobject is located. uint64_t getSecondaryVirtualPointerIndex(const CXXRecordDecl *RD, BaseSubobject Base); - /// getMethodVtableIndex - Return the index (relative to the vtable address + /// getMethodVTableIndex - Return the index (relative to the vtable address /// point) where the function pointer for the given virtual function is /// stored. - uint64_t getMethodVtableIndex(GlobalDecl GD); + uint64_t getMethodVTableIndex(GlobalDecl GD); /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the /// vtable address point) where the offset of the virtual base that contains diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 91fb714..92ef9dc 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -34,69 +34,64 @@ namespace CodeGen { /// simple LLVM SSA value, a pair of SSA values for complex numbers, or the /// address of an aggregate value in memory. class RValue { - llvm::Value *V1, *V2; - // TODO: Encode this into the low bit of pointer for more efficient - // return-by-value. - enum { Scalar, Complex, Aggregate } Flavor; + enum Flavor { Scalar, Complex, Aggregate }; - bool Volatile:1; -public: + // Stores first value and flavor. + llvm::PointerIntPair<llvm::Value *, 2, Flavor> V1; + // Stores second value and volatility. + llvm::PointerIntPair<llvm::Value *, 1, bool> V2; - bool isScalar() const { return Flavor == Scalar; } - bool isComplex() const { return Flavor == Complex; } - bool isAggregate() const { return Flavor == Aggregate; } +public: + bool isScalar() const { return V1.getInt() == Scalar; } + bool isComplex() const { return V1.getInt() == Complex; } + bool isAggregate() const { return V1.getInt() == Aggregate; } - bool isVolatileQualified() const { return Volatile; } + bool isVolatileQualified() const { return V2.getInt(); } /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); - return V1; + return V1.getPointer(); } /// getComplexVal - Return the real/imag components of this complex value. /// std::pair<llvm::Value *, llvm::Value *> getComplexVal() const { - return std::pair<llvm::Value *, llvm::Value *>(V1, V2); + return std::make_pair(V1.getPointer(), V2.getPointer()); } /// getAggregateAddr() - Return the Value* of the address of the aggregate. llvm::Value *getAggregateAddr() const { assert(isAggregate() && "Not an aggregate!"); - return V1; + return V1.getPointer(); } static RValue get(llvm::Value *V) { RValue ER; - ER.V1 = V; - ER.Flavor = Scalar; - ER.Volatile = false; + ER.V1.setPointer(V); + ER.V1.setInt(Scalar); + ER.V2.setInt(false); return ER; } static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { RValue ER; - ER.V1 = V1; - ER.V2 = V2; - ER.Flavor = Complex; - ER.Volatile = false; + ER.V1.setPointer(V1); + ER.V2.setPointer(V2); + ER.V1.setInt(Complex); + ER.V2.setInt(false); return ER; } static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) { - RValue ER; - ER.V1 = C.first; - ER.V2 = C.second; - ER.Flavor = Complex; - ER.Volatile = false; - return ER; + return getComplex(C.first, C.second); } // FIXME: Aggregate rvalues need to retain information about whether they are // volatile or not. Remove default to find all places that probably get this // wrong. - static RValue getAggregate(llvm::Value *V, bool Vol = false) { + static RValue getAggregate(llvm::Value *V, bool Volatile = false) { RValue ER; - ER.V1 = V; - ER.Flavor = Aggregate; - ER.Volatile = Vol; + ER.V1.setPointer(V); + ER.V1.setInt(Aggregate); + ER.V2.setInt(Volatile); return ER; } }; @@ -220,7 +215,7 @@ public: } // bitfield lvalue - llvm::Value *getBitFieldAddr() const { + llvm::Value *getBitFieldBaseAddr() const { assert(isBitField()); return V; } @@ -269,11 +264,17 @@ public: return R; } - static LValue MakeBitfield(llvm::Value *V, const CGBitFieldInfo &Info, + /// \brief Create a new object to represent a bit-field access. + /// + /// \param BaseValue - The base address of the structure containing the + /// bit-field. + /// \param Info - The information describing how to perform the bit-field + /// access. + static LValue MakeBitfield(llvm::Value *BaseValue, const CGBitFieldInfo &Info, unsigned CVR) { LValue R; R.LVType = BitField; - R.V = V; + R.V = BaseValue; R.BitFieldInfo = &Info; R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); return R; diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index e72a1d9..dfd2a39 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -23,7 +23,7 @@ add_clang_library(clangCodeGen CGRTTI.cpp CGStmt.cpp CGTemporaries.cpp - CGVtable.cpp + CGVTables.cpp CGVTT.cpp CodeGenFunction.cpp CodeGenModule.cpp diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index f38d8a1..d3bf164 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -246,15 +246,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl()); - - Stmt *Body = FD->getBody(); - if (Body) - EmitStmt(Body); - else { - assert(FD->isImplicit() && "non-implicit function def has no body"); - assert(FD->isCopyAssignment() && "implicit function not copy assignment"); - SynthesizeCXXCopyAssignment(Args); - } + assert(FD->getBody()); + EmitStmt(FD->getBody()); } void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { @@ -480,6 +473,14 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, } void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) { + // Ignore empty classes in C++. + if (getContext().getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { + if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty()) + return; + } + } + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); @@ -749,6 +750,11 @@ void CodeGenFunction::EmitCleanupBlock() { return; } + // Scrub debug location info. + for (llvm::BasicBlock::iterator LBI = Info.CleanupBlock->begin(), + LBE = Info.CleanupBlock->end(); LBI != LBE; ++LBI) + Builder.SetInstDebugLocation(LBI); + llvm::BasicBlock *CurBB = Builder.GetInsertBlock(); if (CurBB && !CurBB->getTerminator() && Info.CleanupBlock->getNumUses() == 0) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f21350d..90a3ec4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -32,6 +32,7 @@ namespace llvm { class BasicBlock; class LLVMContext; + class MDNode; class Module; class SwitchInst; class Twine; @@ -148,19 +149,17 @@ public: /// block. class EHCleanupBlock { CodeGenFunction& CGF; - llvm::BasicBlock *Cont; + llvm::BasicBlock *PreviousInsertionBlock; llvm::BasicBlock *CleanupHandler; - llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *PreviousInvokeDest; public: EHCleanupBlock(CodeGenFunction &cgf) - : CGF(cgf), Cont(CGF.createBasicBlock("cont")), - CleanupHandler(CGF.createBasicBlock("ehcleanup")), - CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")), + : CGF(cgf), + PreviousInsertionBlock(CGF.Builder.GetInsertBlock()), + CleanupHandler(CGF.createBasicBlock("ehcleanup", CGF.CurFn)), PreviousInvokeDest(CGF.getInvokeDest()) { - CGF.EmitBranch(Cont); llvm::BasicBlock *TerminateHandler = CGF.getTerminateHandler(); - CGF.Builder.SetInsertPoint(CleanupEntryBB); + CGF.Builder.SetInsertPoint(CleanupHandler); CGF.setInvokeDest(TerminateHandler); } ~EHCleanupBlock(); @@ -186,7 +185,8 @@ public: public: DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), - CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), + CleanupEntryBB(CGF.createBasicBlock("cleanup")), + CleanupExitBB(0), CurInvokeDest(CGF.getInvokeDest()), EHOnly(ehonly) { CGF.Builder.SetInsertPoint(CleanupEntryBB); @@ -474,11 +474,15 @@ public: /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, + ObjCMethodDecl *MD, bool ctor); /// GenerateObjCSetter - Synthesize an Objective-C property setter function /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + bool IndirectObjCSetterArg(const CGFunctionInfo &FI); + bool IvarTypeWithAggrGCObjects(QualType Ty); //===--------------------------------------------------------------------===// // Block Bits @@ -532,14 +536,16 @@ public: /// InitializeVTablePointer - Initialize the vtable pointer of the given /// subobject. /// - /// \param BaseIsMorallyVirtual - Whether the base subobject is a virtual base - /// or a direct or indirect base of a virtual base. - void InitializeVTablePointer(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointer(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass); typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; - void InitializeVTablePointers(BaseSubobject Base, bool BaseIsMorallyVirtual, + void InitializeVTablePointers(BaseSubobject Base, + const CXXRecordDecl *NearestVBase, + uint64_t OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -549,7 +555,6 @@ public: void SynthesizeCXXCopyConstructor(const FunctionArgList &Args); - void SynthesizeCXXCopyAssignment(const FunctionArgList &Args); /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes in @@ -670,6 +675,9 @@ public: llvm::AllocaInst *CreateTempAlloca(const llvm::Type *Ty, const llvm::Twine &Name = "tmp"); + /// InitTempAlloca - Provide an initial value for the given alloca. + void InitTempAlloca(llvm::AllocaInst *Alloca, llvm::Value *Value); + /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary /// value needs to be stored into an alloca (for example, to avoid explicit @@ -704,6 +712,12 @@ public: RValue EmitAnyExprToTemp(const Expr *E, bool IsAggLocVolatile = false, bool IsInitializer = false); + /// EmitsAnyExprToMem - Emits the code necessary to evaluate an + /// arbitrary expression into the given memory location. + void EmitAnyExprToMem(const Expr *E, llvm::Value *Location, + bool IsLocationVolatile = false, + bool IsInitializer = false); + /// EmitAggregateCopy - Emit an aggrate copy. /// /// \param isVolatile - True iff either the source or the destination is @@ -765,22 +779,23 @@ public: } /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a - /// complete class down to one of its virtual bases. - llvm::Value *GetAddressOfBaseOfCompleteClass(llvm::Value *Value, - bool IsVirtual, - const CXXRecordDecl *Derived, - const CXXRecordDecl *Base); - + /// complete class to the given direct base. + llvm::Value * + GetAddressOfDirectBaseInCompleteClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXRecordDecl *Base, + bool BaseIsVirtual); + /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. - llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, + llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); - + llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *DerivedClassDecl, + const CXXRecordDecl *Derived, + const CXXBaseSpecifierArray &BasePath, bool NullCheckValue); llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This, @@ -789,31 +804,17 @@ public: void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassAggrCopyAssignment(llvm::Value *DestValue, - llvm::Value *SrcValue, - const ArrayType *Array, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const ConstantArrayType *Array, + const CXXRecordDecl *ClassDecl); void EmitClassMemberwiseCopy(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); - - void EmitClassCopyAssignment(llvm::Value *DestValue, llvm::Value *SrcValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl, - QualType Ty); + const CXXRecordDecl *ClassDecl); void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, - llvm::Value *This, + bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); @@ -842,7 +843,7 @@ public: llvm::Value *This); void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, - llvm::Value *This); + bool ForVirtualBase, llvm::Value *This); void PushCXXTemporary(const CXXTemporary *Temporary, llvm::Value *Ptr); void PopCXXTemporary(); @@ -1033,6 +1034,7 @@ public: // Note: only availabe for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); + LValue EmitCompoundAssignOperatorLValue(const CompoundAssignOperator *E); // Note: only available for agg return types LValue EmitCallExprLValue(const CallExpr *E); // Note: only available for agg return types @@ -1100,7 +1102,8 @@ public: llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, - const Decl *TargetDecl = 0); + const Decl *TargetDecl = 0, + llvm::Instruction **callOrInvoke = 0); RValue EmitCall(QualType FnType, llvm::Value *Callee, ReturnValueSlot ReturnValue, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index a2ad31e..cc90a28 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -35,6 +35,7 @@ #include "llvm/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Target/TargetData.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace CodeGen; @@ -47,7 +48,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - MangleCtx(C), VTables(*this), Runtime(0), CFConstantStringClassRef(0), + MangleCtx(C, diags), VTables(*this), Runtime(0), + CFConstantStringClassRef(0), + NSConstantStringClassRef(0), VMContext(M.getContext()) { if (!Features.ObjC1) @@ -78,7 +81,6 @@ void CodeGenModule::createObjCRuntime() { } void CodeGenModule::Release() { - EmitFundamentalRTTIDescriptors(); EmitDeferred(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); @@ -313,7 +315,18 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return CodeGenModule::GVA_C99Inline; - + + // If this is a virtual method and its class has a key method in another + // translation unit, we know that this method will be present in that + // translation unit. In this translation unit we will use this method + // only for inlining and analysis. This is the semantics of c99 inline. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isVirtual() && + CodeGenVTables::isKeyFunctionInAnotherTU(Context, RD)) + return CodeGenModule::GVA_C99Inline; + } + return CodeGenModule::GVA_CXXInline; } @@ -491,11 +504,11 @@ void CodeGenModule::EmitDeferred() { // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. - while (!DeferredDeclsToEmit.empty() || !DeferredVtables.empty()) { - if (!DeferredVtables.empty()) { - const CXXRecordDecl *RD = DeferredVtables.back(); - DeferredVtables.pop_back(); - getVTables().GenerateClassData(getVtableLinkage(RD), RD); + while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { + if (!DeferredVTables.empty()) { + const CXXRecordDecl *RD = DeferredVTables.back(); + DeferredVTables.pop_back(); + getVTables().GenerateClassData(getVTableLinkage(RD), RD); continue; } @@ -687,30 +700,30 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Defer code generation when possible if this is a static definition, inline // function etc. These we only want to emit if they are used. - if (MayDeferGeneration(Global)) { - // If the value has already been used, add it directly to the - // DeferredDeclsToEmit list. - MangleBuffer MangledName; - getMangledName(MangledName, GD); - if (GetGlobalValue(MangledName)) - DeferredDeclsToEmit.push_back(GD); - else { - // Otherwise, remember that we saw a deferred decl with this name. The - // first use of the mangled name will cause it to move into - // DeferredDeclsToEmit. - DeferredDecls[MangledName] = GD; - } + if (!MayDeferGeneration(Global)) { + // Emit the definition if it can't be deferred. + EmitGlobalDefinition(GD); return; } - - // Otherwise emit the definition. - EmitGlobalDefinition(GD); + + // If the value has already been used, add it directly to the + // DeferredDeclsToEmit list. + MangleBuffer MangledName; + getMangledName(MangledName, GD); + if (GetGlobalValue(MangledName)) + DeferredDeclsToEmit.push_back(GD); + else { + // Otherwise, remember that we saw a deferred decl with this name. The + // first use of the mangled name will cause it to move into + // DeferredDeclsToEmit. + DeferredDecls[MangledName] = GD; + } } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast<ValueDecl>(GD.getDecl()); - PrettyStackTraceDecl CrashInfo((ValueDecl *)D, D->getLocation(), + PrettyStackTraceDecl CrashInfo(const_cast<ValueDecl *>(D), D->getLocation(), Context.getSourceManager(), "Generating code for declaration"); @@ -718,16 +731,18 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { getVTables().EmitVTableRelatedData(GD); if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D)) - EmitCXXConstructor(CD, GD.getCtorType()); - else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) - EmitCXXDestructor(DD, GD.getDtorType()); - else if (isa<FunctionDecl>(D)) - EmitGlobalFunctionDefinition(GD); - else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) - EmitGlobalVarDefinition(VD); - else { - assert(0 && "Invalid argument to EmitGlobalDefinition()"); - } + return EmitCXXConstructor(CD, GD.getCtorType()); + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) + return EmitCXXDestructor(DD, GD.getDtorType()); + + if (isa<FunctionDecl>(D)) + return EmitGlobalFunctionDefinition(GD); + + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + return EmitGlobalVarDefinition(VD); + + assert(0 && "Invalid argument to EmitGlobalDefinition()"); } /// GetOrCreateLLVMFunction - If the specified mangled name is not in the @@ -764,12 +779,16 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, // type is an incomplete struct). Use a fake type instead, and make // sure not to try to set attributes. bool IsIncompleteFunction = false; - if (!isa<llvm::FunctionType>(Ty)) { - Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - std::vector<const llvm::Type*>(), false); + + const llvm::FunctionType *FTy; + if (isa<llvm::FunctionType>(Ty)) { + FTy = cast<llvm::FunctionType>(Ty); + } else { + FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + std::vector<const llvm::Type*>(), false); IsIncompleteFunction = true; } - llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty), + llvm::Function *F = llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, MangledName, &getModule()); assert(F->getName() == MangledName && "name was uniqued!"); @@ -811,7 +830,14 @@ CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, } } - return F; + // Make sure the result is of the requested type. + if (!IsIncompleteFunction) { + assert(F->getType()->getElementType() == Ty); + return F; + } + + const llvm::Type *PTy = llvm::PointerType::getUnqual(Ty); + return llvm::ConstantExpr::getBitCast(F, PTy); } /// GetAddrOfFunction - Return the address of the given function. If Ty is @@ -959,7 +985,7 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { } llvm::GlobalVariable::LinkageTypes -CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) { +CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { if (RD->isInAnonymousNamespace() || !RD->hasLinkage()) return llvm::GlobalVariable::InternalLinkage; @@ -1204,9 +1230,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end(); UI != E; ) { // TODO: Do invokes ever occur in C code? If so, we should handle them too. - unsigned OpNo = UI.getOperandNo(); - llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*UI++); - if (!CI || OpNo != 0) continue; + llvm::Value::use_iterator I = UI++; // Increment before the CI is erased. + llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*I); + llvm::CallSite CS(CI); + if (!CI || !CS.isCallee(I)) continue; // If the return types don't match exactly, and if the call isn't dead, then // we can't transform this call. @@ -1220,8 +1247,8 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, bool DontTransform = false; for (llvm::Function::arg_iterator AI = NewFn->arg_begin(), E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) { - if (CI->getNumOperands()-1 == ArgNo || - CI->getOperand(ArgNo+1)->getType() != AI->getType()) { + if (CS.arg_size() == ArgNo || + CS.getArgument(ArgNo)->getType() != AI->getType()) { DontTransform = true; break; } @@ -1231,7 +1258,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, // Okay, we can transform this. Create the new call instruction and copy // over the required information. - ArgList.append(CI->op_begin()+1, CI->op_begin()+1+ArgNo); + ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo); llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList.begin(), ArgList.end(), "", CI); ArgList.clear(); @@ -1578,6 +1605,90 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { return GV; } +llvm::Constant * +CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) { + unsigned StringLength = 0; + bool isUTF16 = false; + llvm::StringMapEntry<llvm::Constant*> &Entry = + GetConstantCFStringEntry(CFConstantStringMap, Literal, + getTargetData().isLittleEndian(), + isUTF16, StringLength); + + if (llvm::Constant *C = Entry.getValue()) + return C; + + llvm::Constant *Zero = + llvm::Constant::getNullValue(llvm::Type::getInt32Ty(VMContext)); + llvm::Constant *Zeros[] = { Zero, Zero }; + + // If we don't already have it, get _NSConstantStringClassReference. + if (!NSConstantStringClassRef) { + const llvm::Type *Ty = getTypes().ConvertType(getContext().IntTy); + Ty = llvm::ArrayType::get(Ty, 0); + llvm::Constant *GV = CreateRuntimeVariable(Ty, + Features.ObjCNonFragileABI ? + "OBJC_CLASS_$_NSConstantString" : + "_NSConstantStringClassReference"); + // Decay array -> ptr + NSConstantStringClassRef = + llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + } + + QualType NSTy = getContext().getNSConstantStringType(); + + const llvm::StructType *STy = + cast<llvm::StructType>(getTypes().ConvertType(NSTy)); + + std::vector<llvm::Constant*> Fields(3); + + // Class pointer. + Fields[0] = NSConstantStringClassRef; + + // String pointer. + llvm::Constant *C = llvm::ConstantArray::get(VMContext, Entry.getKey().str()); + + llvm::GlobalValue::LinkageTypes Linkage; + bool isConstant; + if (isUTF16) { + // FIXME: why do utf strings get "_" labels instead of "L" labels? + Linkage = llvm::GlobalValue::InternalLinkage; + // Note: -fwritable-strings doesn't make unicode NSStrings writable, but + // does make plain ascii ones writable. + isConstant = true; + } else { + Linkage = llvm::GlobalValue::PrivateLinkage; + isConstant = !Features.WritableStrings; + } + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, + ".str"); + if (isUTF16) { + CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); + GV->setAlignment(Align.getQuantity()); + } + Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); + + // String length. + const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); + Fields[2] = llvm::ConstantInt::get(Ty, StringLength); + + // The struct. + C = llvm::ConstantStruct::get(STy, Fields); + GV = new llvm::GlobalVariable(getModule(), C->getType(), true, + llvm::GlobalVariable::PrivateLinkage, C, + "_unnamed_nsstring_"); + // FIXME. Fix section. + if (const char *Sect = + Features.ObjCNonFragileABI + ? getContext().Target.getNSStringNonFragileABISection() + : getContext().Target.getNSStringSection()) + GV->setSection(Sect); + Entry.setValue(GV); + + return GV; +} + /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { @@ -1709,6 +1820,39 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } } +/// EmitObjCIvarInitializations - Emit information for ivar initialization +/// for an implementation. +void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { + if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0) + return; + DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D)); + assert(DC && "EmitObjCIvarInitializations - null DeclContext"); + IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + Selector cxxSelector = getContext().Selectors.getSelector(0, &II); + ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().VoidTy, 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(DTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); + + II = &getContext().Idents.get(".cxx_construct"); + cxxSelector = getContext().Selectors.getSelector(0, &II); + // The constructor returns 'self'. + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), + D->getLocation(), + D->getLocation(), cxxSelector, + getContext().getObjCIdType(), 0, + DC, true, false, true, + ObjCMethodDecl::Required); + D->addInstanceMethod(CTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); + + +} + /// EmitNamespace - Emit all declarations in a namespace. void CodeGenModule::EmitNamespace(const NamespaceDecl *ND) { for (RecordDecl::decl_iterator I = ND->decls_begin(), E = ND->decls_end(); @@ -1805,6 +1949,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast<ObjCImplementationDecl>(D); EmitObjCPropertyImplementations(OMD); + EmitObjCIvarInitializations(OMD); Runtime->GenerateClass(OMD); break; } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index e9f78bc..93d8ddf 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -21,7 +21,7 @@ #include "CGBlocks.h" #include "CGCall.h" #include "CGCXX.h" -#include "CGVtable.h" +#include "CGVTables.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -94,7 +94,8 @@ class CodeGenModule : public BlockModule { /// VTables - Holds information about C++ vtables. CodeGenVTables VTables; - + friend class CodeGenVTables; + CGObjCRuntime* Runtime; CGDebugInfo* DebugInfo; @@ -132,6 +133,7 @@ class CodeGenModule : public BlockModule { llvm::StringMap<llvm::Constant*> CFConstantStringMap; llvm::StringMap<llvm::Constant*> ConstantStringMap; + llvm::DenseMap<const Decl*, llvm::Value*> StaticLocalDeclMap; /// CXXGlobalInits - Global variables with initializers that need to run /// before main. @@ -145,6 +147,10 @@ class CodeGenModule : public BlockModule { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// NSConstantStringClassRef - Cached reference to the class for constant + /// strings. This value has type int * but is actually an Obj-C class pointer. + llvm::Constant *NSConstantStringClassRef; + /// Lazily create the Objective-C runtime void createObjCRuntime(); @@ -169,6 +175,14 @@ public: /// been configured. bool hasObjCRuntime() { return !!Runtime; } + llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { + return StaticLocalDeclMap[VD]; + } + void setStaticLocalDeclAddress(const VarDecl *D, + llvm::GlobalVariable *GV) { + StaticLocalDeclMap[D] = GV; + } + CGDebugInfo *getDebugInfo() { return DebugInfo; } ASTContext &getContext() const { return Context; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } @@ -218,7 +232,7 @@ public: /// GetAddrOfRTTIDescriptor - Get the address of the RTTI descriptor /// for the given type. - llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty); + llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); /// GetAddrOfThunk - Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); @@ -227,11 +241,11 @@ public: llvm::Constant *GetWeakRefReference(const ValueDecl *VD); /// GetNonVirtualBaseClassOffset - Returns the offset from a derived class to - /// its base class. Returns null if the offset is 0. + /// a class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl); - + const CXXBaseSpecifierArray &BasePath); + /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of /// a constant is needed consider using GetAddrOfConstantStringLiteral. @@ -240,6 +254,10 @@ public: /// GetAddrOfConstantCFString - Return a pointer to a constant CFString object /// for the given string. llvm::Constant *GetAddrOfConstantCFString(const StringLiteral *Literal); + + /// GetAddrOfConstantNSString - Return a pointer to a constant NSString object + /// for the given string. + llvm::Constant *GetAddrOfConstantNSString(const StringLiteral *Literal); /// GetAddrOfConstantStringFromLiteral - Return a pointer to a constant array /// for the given string literal. @@ -416,16 +434,16 @@ public: llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); - /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, + /// getVTableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes - getVtableLinkage(const CXXRecordDecl *RD); + getVTableLinkage(const CXXRecordDecl *RD); /// GetTargetTypeStoreSize - Return the store size, in character units, of /// the given LLVM type. CharUnits GetTargetTypeStoreSize(const llvm::Type *Ty) const; - std::vector<const CXXRecordDecl*> DeferredVtables; + std::vector<const CXXRecordDecl*> DeferredVTables; private: llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref); @@ -464,6 +482,7 @@ private: void EmitGlobalVarDefinition(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); + void EmitObjCIvarInitializations(ObjCImplementationDecl *D); // C++ related functions. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 9b74106d..10e71e2 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -52,7 +52,6 @@ namespace clang { namespace CodeGen { class CGRecordLayout; - class CodeGenTypes; /// CodeGenTypes - This class organizes the cross-module state that is used /// while lowering AST types to LLVM types. @@ -124,10 +123,10 @@ public: const llvm::FunctionType *GetFunctionType(GlobalDecl GD); - /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable, + /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, /// and/or incomplete argument types, this will return the opaque type. - const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD); + const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 077db7c..8658cfb 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -25,7 +25,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" -#include "CGVtable.h" +#include "CGVTables.h" #define MANGLE_CHECKER 0 @@ -111,6 +111,7 @@ public: private: bool mangleSubstitution(const NamedDecl *ND); bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); bool mangleStandardSubstitution(const NamedDecl *ND); @@ -121,6 +122,7 @@ private: addSubstitution(reinterpret_cast<uintptr_t>(ND)); } void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); @@ -138,6 +140,7 @@ private: unsigned KnownArity); void mangleUnscopedName(const NamedDecl *ND); void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); void mangleSourceName(const IdentifierInfo *II); void mangleLocalName(const NamedDecl *ND); void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, @@ -147,6 +150,7 @@ private: unsigned NumTemplateArgs); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); @@ -172,6 +176,9 @@ private: void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); + void mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); void mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -306,8 +313,6 @@ static bool isStd(const NamespaceDecl *NS) { static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { while (isa<LinkageSpecDecl>(DC)) { - assert(cast<LinkageSpecDecl>(DC)->getLanguage() == - LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!"); DC = DC->getParent(); } @@ -429,6 +434,31 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { addSubstitution(ND); } +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + // FIXME: How to cope with operators here? + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (!Dependent->isIdentifier()) { + // FIXME: We can't possibly know the arity of the operator here! + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle dependent operator name"); + Diags.Report(FullSourceLoc(), DiagID); + return; + } + + mangleSourceName(Dependent->getIdentifier()); + addSubstitution(Template); +} + void CXXNameMangler::mangleNumber(int64_t Number) { // <number> ::= [n] <non-negative decimal integer> if (Number < 0) { @@ -475,11 +505,12 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { if (const TemplateSpecializationType *TST = dyn_cast<TemplateSpecializationType>(QTy)) { if (!mangleSubstitution(QualType(TST, 0))) { - TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); - assert(TD && "FIXME: Support dependent template names"); - mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TST->getArgs(), + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } @@ -741,6 +772,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { addSubstitution(cast<NamedDecl>(DC)); } +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplatePrefix(TD); + + if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) + mangleUnresolvedScope(Qualified->getQualifier()); + + if (OverloadedTemplateStorage *Overloaded + = Template.getAsOverloadedTemplate()) { + mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(), + UnknownArity); + return; + } + + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Unknown template name kind?"); + mangleUnresolvedScope(Dependent->getQualifier()); + mangleUnscopedTemplateName(Template); +} + void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { // <template-prefix> ::= <prefix> <template unqualified-name> // ::= <template-param> @@ -896,7 +950,7 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { assert (CD && "Missing container decl in GetNameForMethod"); OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) - OS << '(' << CID->getNameAsString() << ')'; + OS << '(' << CID << ')'; OS << ' ' << MD->getSelector().getAsString() << ']'; Out << OS.str().size() << OS.str(); @@ -1157,18 +1211,50 @@ void CXXNameMangler::mangleType(const BlockPointerType *T) { mangleType(T->getPointeeType()); } -void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { - TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl(); - assert(TD && "FIXME: Support dependent template names!"); +void CXXNameMangler::mangleType(const InjectedClassNameType *T) { + // Mangle injected class name types as if the user had written the + // specialization out fully. It may not actually be possible to see + // this mangling, though. + mangleType(T->getInjectedSpecializationType()); +} - mangleName(TD, T->getArgs(), T->getNumArgs()); +void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { + mangleName(TD, T->getArgs(), T->getNumArgs()); + } else { + if (mangleSubstitution(QualType(T, 0))) + return; + + mangleTemplatePrefix(T->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + addSubstitution(QualType(T, 0)); + } } void CXXNameMangler::mangleType(const DependentNameType *T) { // Typename types are always nested Out << 'N'; - mangleUnresolvedScope(T->getQualifier()); - mangleSourceName(T->getIdentifier()); + if (T->getIdentifier()) { + mangleUnresolvedScope(T->getQualifier()); + mangleSourceName(T->getIdentifier()); + } else { + const TemplateSpecializationType *TST = T->getTemplateId(); + if (!mangleSubstitution(QualType(TST, 0))) { + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), + TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } + Out << 'E'; } @@ -1279,17 +1365,33 @@ void CXXNameMangler::mangleExpression(const Expr *E) { // ::= L <type <value float> E # floating literal // ::= L <mangled-name> E # external name switch (E->getStmtClass()) { - default: + case Expr::NoStmtClass: +#define EXPR(Type, Base) +#define STMT(Type, Base) \ + case Expr::Type##Class: +#include "clang/AST/StmtNodes.def" llvm_unreachable("unexpected statement kind"); break; + default: { + // As bad as this diagnostic is, it's better than crashing. + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle expression type %0"); + Diags.Report(FullSourceLoc(E->getExprLoc(), + getASTContext().getSourceManager()), + DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + case Expr::CallExprClass: { const CallExpr *CE = cast<CallExpr>(E); Out << "cl"; mangleCalledExpression(CE->getCallee(), CE->getNumArgs()); for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) mangleExpression(CE->getArg(I)); - Out << "E"; + Out << 'E'; break; } @@ -1333,9 +1435,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) { Out << "cv"; mangleType(CE->getType()); - if (N != 1) Out << "_"; + if (N != 1) Out << '_'; for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << "E"; + if (N != 1) Out << 'E'; break; } @@ -1346,21 +1448,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) { Out << "cv"; mangleType(CE->getType()); - if (N != 1) Out << "_"; + if (N != 1) Out << '_'; for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << "E"; + if (N != 1) Out << 'E'; break; } case Expr::SizeOfAlignOfExprClass: { const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E); - if (SAE->isSizeOf()) Out << "s"; - else Out << "a"; + if (SAE->isSizeOf()) Out << 's'; + else Out << 'a'; if (SAE->isArgumentType()) { - Out << "t"; + Out << 't'; mangleType(SAE->getArgumentType()); } else { - Out << "z"; + Out << 'z'; mangleExpression(SAE->getArgumentExpr()); } break; @@ -1474,9 +1576,21 @@ void CXXNameMangler::mangleExpression(const Expr *E) { break; } + case Expr::CXXBindReferenceExprClass: + mangleExpression(cast<CXXBindReferenceExpr>(E)->getSubExpr()); + break; + + case Expr::CXXBindTemporaryExprClass: + mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr()); + break; + + case Expr::CXXExprWithTemporariesClass: + mangleExpression(cast<CXXExprWithTemporaries>(E)->getSubExpr()); + break; + case Expr::FloatingLiteralClass: { const FloatingLiteral *FL = cast<FloatingLiteral>(E); - Out << "L"; + Out << 'L'; mangleType(FL->getType()); // TODO: avoid this copy with careful stream management. @@ -1484,10 +1598,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) { FL->getValue().bitcastToAPInt().toString(Buffer, 16, false); Out.write(Buffer.data(), Buffer.size()); - Out << "E"; + Out << 'E'; break; } + case Expr::CharacterLiteralClass: + Out << 'L'; + mangleType(E->getType()); + Out << cast<CharacterLiteral>(E)->getValue(); + Out << 'E'; + break; + + case Expr::CXXBoolLiteralExprClass: + Out << "Lb"; + Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0'); + Out << 'E'; + break; + case Expr::IntegerLiteralClass: mangleIntegerLiteral(E->getType(), llvm::APSInt(cast<IntegerLiteral>(E)->getValue())); @@ -1535,23 +1662,37 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } } +void CXXNameMangler::mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, + NumTemplateArgs); + + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != NumTemplateArgs; ++i) + mangleTemplateArg(0, TemplateArgs[i]); + Out << 'E'; +} + void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgumentList &AL) { // <template-args> ::= I <template-arg>+ E - Out << "I"; + Out << 'I'; for (unsigned i = 0, e = AL.size(); i != e; ++i) mangleTemplateArg(PL.getParam(i), AL[i]); - Out << "E"; + Out << 'E'; } void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // <template-args> ::= I <template-arg>+ E - Out << "I"; + Out << 'I'; for (unsigned i = 0; i != NumTemplateArgs; ++i) mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); - Out << "E"; + Out << 'E'; } void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, @@ -1569,7 +1710,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, break; case TemplateArgument::Template: assert(A.getAsTemplate().getAsTemplateDecl() && - "FIXME: Support dependent template names"); + "Can't get dependent template names here"); mangleName(A.getAsTemplate().getAsTemplateDecl()); break; case TemplateArgument::Expression: @@ -1581,6 +1722,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); break; case TemplateArgument::Declaration: { + assert(P && "Missing template parameter for declaration argument"); // <expr-primary> ::= L <mangled-name> E # external name // Clang produces AST's where pointer-to-member-function expressions @@ -1646,9 +1788,17 @@ bool CXXNameMangler::mangleSubstitution(QualType T) { return mangleSubstitution(TypePtr); } +bool CXXNameMangler::mangleSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + return mangleSubstitution( + reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { - llvm::DenseMap<uintptr_t, unsigned>::iterator I = - Substitutions.find(Ptr); + llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr); if (I == Substitutions.end()) return false; @@ -1660,9 +1810,8 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { // <seq-id> is encoded in base-36, using digits and upper case letters. char Buffer[10]; - char *BufferPtr = Buffer + 9; + char *BufferPtr = llvm::array_endof(Buffer); - *BufferPtr = 0; if (SeqID == 0) *--BufferPtr = '0'; while (SeqID) { @@ -1674,7 +1823,9 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { SeqID /= 36; } - Out << 'S' << BufferPtr << '_'; + Out << 'S' + << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) + << '_'; } return true; @@ -1824,6 +1975,14 @@ void CXXNameMangler::addSubstitution(QualType T) { addSubstitution(TypePtr); } +void CXXNameMangler::addSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return addSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + void CXXNameMangler::addSubstitution(uintptr_t Ptr) { unsigned SeqID = Substitutions.size(); @@ -1925,7 +2084,7 @@ void MangleContext::mangleGuardVariable(const VarDecl *D, Mangler.mangleName(D); } -void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD, +void MangleContext::mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TV <type> # virtual table CXXNameMangler Mangler(*this, Res); @@ -1941,7 +2100,7 @@ void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD, Mangler.mangleName(RD); } -void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, +void MangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, llvm::SmallVectorImpl<char> &Res) { // <special-name> ::= TC <type> <offset number> _ <base type> @@ -1949,7 +2108,7 @@ void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, Mangler.getStream() << "_ZTC"; Mangler.mangleName(RD); Mangler.getStream() << Offset; - Mangler.getStream() << "_"; + Mangler.getStream() << '_'; Mangler.mangleName(Type); } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 91a5e97..da3626f 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -68,17 +68,21 @@ private: /// calls to the C++ name mangler. class MangleContext { ASTContext &Context; + Diagnostic &Diags; llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; unsigned Discriminator; llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; public: - explicit MangleContext(ASTContext &Context) - : Context(Context) { } + explicit MangleContext(ASTContext &Context, + Diagnostic &Diags) + : Context(Context), Diags(Diags) { } ASTContext &getASTContext() const { return Context; } + Diagnostic &getDiags() const { return Diags; } + uint64_t getAnonymousStructId(const TagDecl *TD) { std::pair<llvm::DenseMap<const TagDecl *, uint64_t>::iterator, bool> Result = @@ -99,9 +103,9 @@ public: const ThisAdjustment &ThisAdjustment, llvm::SmallVectorImpl<char> &); void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &); - void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); + void mangleCXXVTable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &); - void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset, + void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, const CXXRecordDecl *Type, llvm::SmallVectorImpl<char> &); void mangleCXXRTTI(QualType T, llvm::SmallVectorImpl<char> &); diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 59e8e77..e1fdf86 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -43,7 +43,8 @@ void ABIArgInfo::dump() const { getCoerceToType()->print(OS); break; case Indirect: - OS << "Indirect Align=" << getIndirectAlign(); + OS << "Indirect Align=" << getIndirectAlign() + << " Byal=" << getIndirectByVal(); break; case Expand: OS << "Expand"; @@ -270,7 +271,7 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, llvm::LLVMContext &VMContext) const { if (CodeGenFunction::hasAggregateLLVMType(Ty)) return ABIArgInfo::getIndirect(0); - + // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs<EnumType>()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -291,8 +292,10 @@ class X86_32ABIInfo : public ABIInfo { static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); - static unsigned getIndirectArgumentAlignment(QualType Ty, - ASTContext &Context); + /// getIndirectResult - Give a source type \arg Ty, return a suitable result + /// such that the argument will be passed in memory. + ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context, + bool ByVal = true) const; public: ABIArgInfo classifyReturnType(QualType RetTy, @@ -490,14 +493,19 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, } } -unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty, - ASTContext &Context) { - unsigned Align = Context.getTypeAlign(Ty); - if (Align < 128) return 0; - if (const RecordType* RT = Ty->getAs<RecordType>()) - if (typeContainsSSEVector(RT->getDecl(), Context)) - return 16; - return 0; +ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, + ASTContext &Context, + bool ByVal) const { + if (!ByVal) + return ABIArgInfo::getIndirect(0, false); + + // Compute the byval alignment. We trust the back-end to honor the + // minimum ABI alignment for byval, to make cleaner IR. + const unsigned MinABIAlign = 4; + unsigned Align = Context.getTypeAlign(Ty) / 8; + if (Align > MinABIAlign) + return ABIArgInfo::getIndirect(Align); + return ABIArgInfo::getIndirect(0); } ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, @@ -510,11 +518,10 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - + return getIndirectResult(Ty, Context, /*ByVal=*/false); + if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, - Context)); + return getIndirectResult(Ty, Context); } // Ignore empty structs. @@ -529,7 +536,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, canExpandIndirectArgument(Ty, Context)) return ABIArgInfo::getExpand(); - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); + return getIndirectResult(Ty, Context); } else { if (const EnumType *EnumTy = Ty->getAs<EnumType>()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -685,9 +692,12 @@ class X86_64ABIInfo : public ABIInfo { ASTContext &Context) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result + /// such that the argument will be returned in memory. + ABIArgInfo getIndirectReturnResult(QualType Ty, ASTContext &Context) const; + + /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. - ABIArgInfo getIndirectResult(QualType Ty, - ASTContext &Context) const; + ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context) const; ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context, @@ -1060,6 +1070,22 @@ ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, return ABIArgInfo::getCoerce(CoerceTo); } +ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty, + ASTContext &Context) const { + // If this is a scalar LLVM value then assume LLVM will pass it in the right + // place naturally. + if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } + + return ABIArgInfo::getIndirect(0); +} + ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, ASTContext &Context) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right @@ -1073,10 +1099,16 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } - bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - // FIXME: Set alignment correctly. - return ABIArgInfo::getIndirect(0, ByVal); + // Compute the byval alignment. We trust the back-end to honor the + // minimum ABI alignment for byval, to make cleaner IR. + const unsigned MinABIAlign = 8; + unsigned Align = Context.getTypeAlign(Ty) / 8; + if (Align > MinABIAlign) + return ABIArgInfo::getIndirect(Align); + return ABIArgInfo::getIndirect(0); } ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, @@ -1104,7 +1136,7 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via // hidden argument. case Memory: - return getIndirectResult(RetTy, Context); + return getIndirectReturnResult(RetTy, Context); // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. @@ -1126,7 +1158,8 @@ ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, // %st1. case ComplexX87: assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); - ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext), + ResType = llvm::StructType::get(VMContext, + llvm::Type::getX86_FP80Ty(VMContext), llvm::Type::getX86_FP80Ty(VMContext), NULL); break; @@ -1574,7 +1607,7 @@ ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(CGF.getLLVMContext())); + const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); CGBuilderTy &Builder = CGF.Builder; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 921147f..7371a93 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -239,12 +239,8 @@ int Driver::ExecuteCompilation(const Compilation &C) const { // other tools are less common, and they generally have worse diagnostics, // so always print the diagnostic there. const Action &Source = FailingCommand->getSource(); - bool IsFriendlyTool = (isa<PreprocessJobAction>(Source) || - isa<PrecompileJobAction>(Source) || - isa<AnalyzeJobAction>(Source) || - isa<CompileJobAction>(Source)); - if (!IsFriendlyTool || Res != 1) { + if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) { // FIXME: See FIXME above regarding result code interpretation. if (Res < 0) Diag(clang::diag::err_drv_command_signalled) diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 105eab0..1cd8ee1 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -217,6 +217,8 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + std::string Tmp; + // FIXME: Derive these correctly. if (getArchName() == "x86_64") { CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + @@ -225,10 +227,24 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + "/x86_64")); } + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir)); + + Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir; + if (llvm::sys::Path(Tmp).exists()) + CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); + Tmp = getDriver().Dir + "/../lib/gcc"; + if (llvm::sys::Path(Tmp).exists()) + CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); // Intentionally duplicated for (temporary) gcc bug compatibility. CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); + Tmp = getDriver().Dir + "/../lib/" + ToolChainDir; + if (llvm::sys::Path(Tmp).exists()) + CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); + Tmp = getDriver().Dir + "/../lib"; + if (llvm::sys::Path(Tmp).exists()) + CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + "/../../../" + ToolChainDir)); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + @@ -656,6 +672,11 @@ const char *Darwin::GetForcedPicModel() const { return 0; } +bool Darwin::SupportsObjCGC() const { + // Garbage collection is supported everywhere except on iPhone OS. + return !isTargetIPhoneOS(); +} + /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 0d5b2a3..9acc950 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -160,13 +160,20 @@ public: return !isMacosxVersionLT(10, 6); } virtual bool IsObjCNonFragileABIDefault() const { - // Non-fragile ABI default to on for iPhoneOS and x86-64. - return isTargetIPhoneOS() || getTriple().getArch() == llvm::Triple::x86_64; + // Non-fragile ABI is default for everything but i386. + return getTriple().getArch() != llvm::Triple::x86; } virtual bool IsObjCLegacyDispatchDefault() const { // This is only used with the non-fragile ABI. - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); + + // Legacy dispatch is used everywhere except on x86_64. + return getTriple().getArch() != llvm::Triple::x86_64; + } + virtual bool UseObjCMixedDispatch() const { + // This is only used with the non-fragile ABI and non-legacy dispatch. + + // Mixed dispatch is used everywhere except OS X before 10.6. + return !(!isTargetIPhoneOS() && isMacosxVersionLT(10, 6)); } virtual bool IsUnwindTablesDefault() const; virtual unsigned GetDefaultStackProtectorLevel() const { @@ -176,6 +183,8 @@ public: virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; + virtual bool SupportsObjCGC() const; + virtual bool UseDwarfDebugFlags() const; virtual bool UseSjLjExceptions() const; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 2a37991..176d491 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -566,13 +566,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, // If unspecified, choose the default based on the platform. if (FloatABI.empty()) { - switch (getToolChain().getTriple().getOS()) { - default: - // Assume "soft", but warn the user we are guessing. - FloatABI = "soft"; - D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; - break; - } + // Assume "soft", but warn the user we are guessing. + FloatABI = "soft"; + D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; } if (FloatABI == "soft") { @@ -623,6 +619,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CPUName = "core2"; else if (getToolChain().getArchName() == "i386") CPUName = "yonah"; + } else if (getToolChain().getOS().startswith("haiku")) { + if (getToolChain().getArchName() == "x86_64") + CPUName = "x86-64"; + else if (getToolChain().getArchName() == "i386") + CPUName = "i586"; } else { if (getToolChain().getArchName() == "x86_64") CPUName = "x86-64"; @@ -826,7 +827,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-check-dead-stores"); - CmdArgs.push_back("-analyzer-check-security-syntactic"); + // Do not enable the security-syntatic check since it + // it needs to be refined (known issues). + // CmdArgs.push_back("-analyzer-check-security-syntactic"); CmdArgs.push_back("-analyzer-check-objc-mem"); CmdArgs.push_back("-analyzer-eagerly-assume"); CmdArgs.push_back("-analyzer-check-objc-methodsigs"); @@ -1073,6 +1076,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + CmdArgs.push_back("-ferror-limit"); + if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) + CmdArgs.push_back(A->getValue(Args)); + else + CmdArgs.push_back("19"); + + CmdArgs.push_back("-ftemplate-backtrace-limit"); + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) + CmdArgs.push_back(A->getValue(Args)); + else + CmdArgs.push_back("10"); + // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { @@ -1105,10 +1120,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_lax_vector_conversions)) CmdArgs.push_back("-fno-lax-vector-conversions"); + // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only + // takes precedence. + const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only); + if (!GCArg) + GCArg = Args.getLastArg(options::OPT_fobjc_gc); + if (GCArg) { + if (getToolChain().SupportsObjCGC()) { + GCArg->render(Args, CmdArgs); + } else { + // FIXME: We should move this to a hard error. + D.Diag(clang::diag::warn_drv_objc_gc_unsupported) + << GCArg->getAsString(Args); + } + } + Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics); Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); - Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only); - Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); @@ -1150,11 +1178,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks"); } - // -fno-access-control is default (for now). - if (Args.hasFlag(options::OPT_faccess_control, - options::OPT_fno_access_control, + // -faccess-control is default. + if (Args.hasFlag(options::OPT_fno_access_control, + options::OPT_faccess_control, false)) - CmdArgs.push_back("-faccess-control"); + CmdArgs.push_back("-fno-access-control"); // -fexceptions=0 is default. if (needsExceptions(Args, InputType, getToolChain().getTriple())) @@ -1188,6 +1216,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); + // -fgnu-keywords default varies depending on language; only pass if + // specified. + if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, + options::OPT_fno_gnu_keywords)) + A->render(Args, CmdArgs); + // -fnext-runtime is default. if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, getToolChain().getTriple().getOS() == llvm::Triple::Darwin)) @@ -1195,16 +1229,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fobjc-nonfragile-abi=0 is default. if (types::isObjC(InputType)) { + unsigned Version = 1; if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) || - getToolChain().IsObjCNonFragileABIDefault()) { + getToolChain().IsObjCNonFragileABIDefault()) + Version = 2; + if (Arg *A = Args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { + if (llvm::StringRef(A->getValue(Args)) == "1") + Version = 1; + else if (llvm::StringRef(A->getValue(Args)) == "2") + Version = 2; + else + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + } + + if (Version == 2) { CmdArgs.push_back("-fobjc-nonfragile-abi"); - - // -fobjc-legacy-dispatch is only relevant with the nonfragile-abi, and - // defaults to off. - if (Args.hasFlag(options::OPT_fobjc_legacy_dispatch, - options::OPT_fno_objc_legacy_dispatch, - getToolChain().IsObjCLegacyDispatchDefault())) - CmdArgs.push_back("-fobjc-legacy-dispatch"); + + // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and + // legacy is the default. + if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, + options::OPT_fno_objc_legacy_dispatch, + getToolChain().IsObjCLegacyDispatchDefault())) { + if (getToolChain().UseObjCMixedDispatch()) + CmdArgs.push_back("-fobjc-dispatch-method=mixed"); + else + CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); + } } } @@ -1212,12 +1262,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); + // -fconstant-cfstrings is default, and may be subject to argument translation + // on Darwin. + if (!Args.hasFlag(options::OPT_fconstant_cfstrings, + options::OPT_fno_constant_cfstrings) || + !Args.hasFlag(options::OPT_mconstant_cfstrings, + options::OPT_mno_constant_cfstrings)) + CmdArgs.push_back("-fno-constant-cfstrings"); + // -fshort-wchar default varies depending on platform; only // pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) { - if (A->getOption().matches(options::OPT_fshort_wchar)) - CmdArgs.push_back("-fshort-wchar"); - } + if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) + A->render(Args, CmdArgs); // -fno-pascal-strings is default, only pass non-default. If the tool chain // happened to translate to -mpascal-strings, we want to back translate here. @@ -1305,8 +1361,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option + // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); - Args.AddAllArgValues(CmdArgs, options::OPT_mllvm); + for (arg_iterator it = Args.filtered_begin(options::OPT_mllvm), + ie = Args.filtered_end(); it != ie; ++it) { + it->claim(); + + // We translate this by hand to the -cc1 argument, since nightly test uses + // it and developers have been trained to spell it with -mllvm. + if (llvm::StringRef(it->getValue(Args, 0)) == "-disable-llvm-optzns") + CmdArgs.push_back("-disable-llvm-optzns"); + else + it->render(Args, CmdArgs); + } if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. @@ -1363,10 +1431,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Claim some arguments which clang supports automatically. - // -fpch-preprocess is used with gcc to add a special marker in the - // -output to include the PCH file. Clang's PTH solution is - // -completely transparent, so we do not need to deal with it at - // -all. + // -fpch-preprocess is used with gcc to add a special marker in the output to + // include the PCH file. Clang's PTH solution is completely transparent, so we + // do not need to deal with it at all. Args.ClaimAllArgs(options::OPT_fpch_preprocess); // Claim some arguments which clang doesn't support, but we don't diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 7a8f1b7..091fec3 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -42,6 +42,7 @@ namespace tools { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } + virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedAssembler() const { return true; } virtual bool hasIntegratedCPP() const { return true; } @@ -79,6 +80,7 @@ namespace gcc { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } + virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, @@ -91,6 +93,7 @@ namespace gcc { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return false; } + virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, @@ -103,6 +106,7 @@ namespace gcc { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } + virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } virtual void RenderExtraToolArgs(const JobAction &JA, @@ -176,6 +180,7 @@ namespace darwin { virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } + virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } }; diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index ebbd720..7b8ebf9 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -24,7 +24,6 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/CodeGen/ModuleBuilder.h" #include "llvm/Module.h" -#include "llvm/Support/Format.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -165,7 +164,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, case Decl::Namespace: { Out << "[namespace] "; const NamespaceDecl* ND = cast<NamespaceDecl>(DC); - Out << ND->getNameAsString(); + Out << ND; break; } case Decl::Enum: { @@ -174,7 +173,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[enum] "; else Out << "<enum> "; - Out << ED->getNameAsString(); + Out << ED; break; } case Decl::Record: { @@ -183,7 +182,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[struct] "; else Out << "<struct> "; - Out << RD->getNameAsString(); + Out << RD; break; } case Decl::CXXRecord: { @@ -192,7 +191,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[class] "; else Out << "<class> "; - Out << RD->getNameAsString() << " " << DC; + Out << RD << ' ' << DC; break; } case Decl::ObjCMethod: @@ -225,7 +224,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "[function] "; else Out << "<function> "; - Out << FD->getNameAsString(); + Out << FD; // Print the parameters. Out << "("; bool PrintComma = false; @@ -235,7 +234,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << (*I)->getNameAsString(); + Out << *I; } Out << ")"; break; @@ -248,7 +247,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ method) "; else Out << "<c++ method> "; - Out << D->getNameAsString(); + Out << D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -258,7 +257,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << (*I)->getNameAsString(); + Out << *I; } Out << ")"; @@ -278,7 +277,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ ctor) "; else Out << "<c++ ctor> "; - Out << D->getNameAsString(); + Out << D; // Print the parameters. Out << "("; bool PrintComma = false; @@ -288,7 +287,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << ", "; else PrintComma = true; - Out << (*I)->getNameAsString(); + Out << *I; } Out << ")"; @@ -307,7 +306,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ dtor) "; else Out << "<c++ dtor> "; - Out << D->getNameAsString(); + Out << D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -323,7 +322,7 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "(c++ conversion) "; else Out << "<c++ conversion> "; - Out << D->getNameAsString(); + Out << D; // Check the semantic DC. const DeclContext* SemaDC = D->getDeclContext(); const DeclContext* LexicalDC = D->getLexicalDeclContext(); @@ -370,42 +369,42 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::Field: { FieldDecl* FD = cast<FieldDecl>(*I); - Out << "<field> " << FD->getNameAsString() << "\n"; + Out << "<field> " << FD << '\n'; break; } case Decl::Typedef: { TypedefDecl* TD = cast<TypedefDecl>(*I); - Out << "<typedef> " << TD->getNameAsString() << "\n"; + Out << "<typedef> " << TD << '\n'; break; } case Decl::EnumConstant: { EnumConstantDecl* ECD = cast<EnumConstantDecl>(*I); - Out << "<enum constant> " << ECD->getNameAsString() << "\n"; + Out << "<enum constant> " << ECD << '\n'; break; } case Decl::Var: { VarDecl* VD = cast<VarDecl>(*I); - Out << "<var> " << VD->getNameAsString() << "\n"; + Out << "<var> " << VD << '\n'; break; } case Decl::ImplicitParam: { ImplicitParamDecl* IPD = cast<ImplicitParamDecl>(*I); - Out << "<implicit parameter> " << IPD->getNameAsString() << "\n"; + Out << "<implicit parameter> " << IPD << '\n'; break; } case Decl::ParmVar: { ParmVarDecl* PVD = cast<ParmVarDecl>(*I); - Out << "<parameter> " << PVD->getNameAsString() << "\n"; + Out << "<parameter> " << PVD << '\n'; break; } case Decl::ObjCProperty: { ObjCPropertyDecl* OPD = cast<ObjCPropertyDecl>(*I); - Out << "<objc property> " << OPD->getNameAsString() << "\n"; + Out << "<objc property> " << OPD << '\n'; break; } case Decl::FunctionTemplate: { FunctionTemplateDecl* FTD = cast<FunctionTemplateDecl>(*I); - Out << "<function template> " << FTD->getNameAsString() << "\n"; + Out << "<function template> " << FTD << '\n'; break; } case Decl::FileScopeAsm: { @@ -418,16 +417,16 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, } case Decl::NamespaceAlias: { NamespaceAliasDecl* NAD = cast<NamespaceAliasDecl>(*I); - Out << "<namespace alias> " << NAD->getNameAsString() << "\n"; + Out << "<namespace alias> " << NAD << '\n'; break; } case Decl::ClassTemplate: { ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); - Out << "<class template> " << CTD->getNameAsString() << '\n'; + Out << "<class template> " << CTD << '\n'; break; } default: - Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; + Out << "DeclKind: " << DK << '"' << *I << "\"\n"; assert(0 && "decl unhandled"); } } @@ -437,150 +436,6 @@ ASTConsumer *clang::CreateDeclContextPrinter() { } //===----------------------------------------------------------------------===// -/// RecordLayoutDumper - C++ Record Layout Dumping. -namespace { -class RecordLayoutDumper : public ASTConsumer { - llvm::raw_ostream& Out; - - void PrintOffset(uint64_t Offset, unsigned IndentLevel) { - Out << llvm::format("%4d | ", Offset); - for (unsigned I = 0; I < IndentLevel * 2; ++I) Out << ' '; - } - - void DumpRecordLayoutOffsets(const CXXRecordDecl *RD, ASTContext &C, - uint64_t Offset, - unsigned IndentLevel, const char* Description, - bool IncludeVirtualBases) { - const ASTRecordLayout &Info = C.getASTRecordLayout(RD); - - PrintOffset(Offset, IndentLevel); - Out << C.getTypeDeclType((CXXRecordDecl *)RD).getAsString(); - if (Description) - Out << ' ' << Description; - if (RD->isEmpty()) - Out << " (empty)"; - Out << '\n'; - - IndentLevel++; - - const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase(); - - // Vtable pointer. - if (RD->isDynamicClass() && !PrimaryBase) { - PrintOffset(Offset, IndentLevel); - Out << '(' << RD->getNameAsString() << " 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; - - DumpRecordLayoutOffsets(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())) { - DumpRecordLayoutOffsets(D, C, FieldOffset, IndentLevel, - Field->getNameAsCString(), - /*IncludeVirtualBases=*/true); - continue; - } - } - - PrintOffset(FieldOffset, IndentLevel); - Out << Field->getType().getAsString() << ' '; - Out << Field->getNameAsString() << '\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; - DumpRecordLayoutOffsets(VBase, C, VBaseOffset, IndentLevel, - VBase == PrimaryBase ? - "(primary virtual base)" : "(virtual base)", - /*IncludeVirtualBases=*/false); - } - } - - // FIXME: Maybe this could be useful in ASTContext.cpp. - void DumpRecordLayout(const CXXRecordDecl *RD, ASTContext &C) { - const ASTRecordLayout &Info = C.getASTRecordLayout(RD); - - DumpRecordLayoutOffsets(RD, C, 0, 0, 0, - /*IncludeVirtualBases=*/true); - Out << " sizeof=" << Info.getSize() / 8; - Out << ", dsize=" << Info.getDataSize() / 8; - Out << ", align=" << Info.getAlignment() / 8 << '\n'; - Out << " nvsize=" << Info.getNonVirtualSize() / 8; - Out << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n'; - Out << '\n'; - } - -public: - RecordLayoutDumper() : Out(llvm::errs()) {} - - void HandleTranslationUnit(ASTContext &C) { - for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); - I != E; ++I) { - const RecordType *RT = dyn_cast<RecordType>(*I); - if (!RT) - continue; - - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - continue; - - if (RD->isImplicit()) - continue; - - if (RD->isDependentType()) - continue; - - if (RD->isInvalidDecl()) - continue; - - if (!RD->getDefinition()) - continue; - - // FIXME: Do we really need to hard code this? - if (RD->getQualifiedNameAsString() == "__va_list_tag") - continue; - - DumpRecordLayout(RD, C); - } - } -}; -} // end anonymous namespace -ASTConsumer *clang::CreateRecordLayoutDumper() { - return new RecordLayoutDumper(); -} - -//===----------------------------------------------------------------------===// /// InheritanceViewer - C++ Inheritance Visualization namespace { diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 427bd6a..4730bdc 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -265,8 +265,16 @@ public: TopLevelDeclTrackerConsumer(ASTUnit &_Unit) : Unit(_Unit) {} void HandleTopLevelDecl(DeclGroupRef D) { - for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) - Unit.getTopLevelDecls().push_back(*it); + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { + Decl *D = *it; + // FIXME: Currently ObjC method declarations are incorrectly being + // reported as top-level declarations, even though their DeclContext + // is the containing ObjC @interface/@implementation. This is a + // fundamental problem in the parser right now. + if (isa<ObjCMethodDecl>(D)) + continue; + Unit.getTopLevelDecls().push_back(D); + } } }; @@ -431,8 +439,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, const driver::ArgStringList &CCArgs = Cmd->getArguments(); llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation); - CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(), - (const char**) CCArgs.data()+CCArgs.size(), + CompilerInvocation::CreateFromArgs(*CI, + const_cast<const char **>(CCArgs.data()), + const_cast<const char **>(CCArgs.data()) + + CCArgs.size(), *Diags); // Override any files that need remapping diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index d764fd0..87c3fca 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -41,10 +41,6 @@ using namespace clang; static ExplodedNode::Auditor* CreateUbiViz(); //===----------------------------------------------------------------------===// -// Basic type definitions. -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// // Special PathDiagnosticClients. //===----------------------------------------------------------------------===// @@ -62,20 +58,21 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix, namespace { - class AnalysisConsumer : public ASTConsumer { - public: +class AnalysisConsumer : public ASTConsumer { +public: typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, TranslationUnitDecl &TU); - private: +private: typedef std::vector<CodeAction> Actions; typedef std::vector<TUAction> TUActions; Actions FunctionActions; Actions ObjCMethodActions; Actions ObjCImplementationActions; - TUActions TranslationUnitActions; + Actions CXXMethodActions; + TUActions TranslationUnitActions; // Remove this. public: ASTContext* Ctx; @@ -150,7 +147,7 @@ public: if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { const NamedDecl *ND = cast<NamedDecl>(D); - llvm::errs() << ' ' << ND->getNameAsString() << '\n'; + llvm::errs() << ' ' << ND << '\n'; } else if (isa<BlockDecl>(D)) { llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" @@ -161,103 +158,100 @@ public: void addCodeAction(CodeAction action) { FunctionActions.push_back(action); ObjCMethodActions.push_back(action); - } - - void addObjCImplementationAction(CodeAction action) { - ObjCImplementationActions.push_back(action); + CXXMethodActions.push_back(action); } void addTranslationUnitAction(TUAction action) { TranslationUnitActions.push_back(action); } + void addObjCImplementationAction(CodeAction action) { + ObjCImplementationActions.push_back(action); + } + virtual void Initialize(ASTContext &Context) { Ctx = &Context; Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, + Opts.MaxNodes, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, Opts.TrimGraph)); } - virtual void HandleTopLevelDecl(DeclGroupRef D) { - declDisplayed = false; - for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) - HandleTopLevelSingleDecl(*I); - } - - void HandleTopLevelSingleDecl(Decl *D); virtual void HandleTranslationUnit(ASTContext &C); - - void HandleCode(Decl* D, Stmt* Body, Actions& actions); + void HandleCode(Decl *D, Stmt* Body, Actions& actions); }; } // end anonymous namespace -namespace llvm { - template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> { - static inline void Profile(AnalysisConsumer::CodeAction X, - FoldingSetNodeID& ID) { - ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X))); - } - }; -} - //===----------------------------------------------------------------------===// // AnalysisConsumer implementation. //===----------------------------------------------------------------------===// -void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { - switch (D->getKind()) { - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - case Decl::CXXMethod: - case Decl::Function: { - FunctionDecl* FD = cast<FunctionDecl>(D); - if (!Opts.AnalyzeSpecificFunction.empty() && - FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) - break; - - if (Stmt *Body = FD->getBody()) - HandleCode(FD, Body, FunctionActions); - break; - } - - case Decl::ObjCMethod: { - ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); +void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) - return; + TranslationUnitDecl *TU = C.getTranslationUnitDecl(); - if (Stmt* Body = MD->getBody()) - HandleCode(MD, Body, ObjCMethodActions); - break; - } + for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end(); + I != E; ++I) { + Decl *D = *I; + + switch (D->getKind()) { + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: + case Decl::Function: { + FunctionDecl* FD = cast<FunctionDecl>(D); + + if (FD->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) + break; + HandleCode(FD, FD->getBody(), FunctionActions); + } + break; + } - default: - break; - } -} + case Decl::ObjCMethod: { + ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); + + if (MD->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) + break; + HandleCode(MD, MD->getBody(), ObjCMethodActions); + } + break; + } -void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { + case Decl::ObjCImplementation: { + ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); + HandleCode(ID, 0, ObjCImplementationActions); + + for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), + ME = ID->meth_end(); MI != ME; ++MI) { + if ((*MI)->isThisDeclarationADefinition()) { + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) + break; + HandleCode(*MI, (*MI)->getBody(), ObjCMethodActions); + } + } + break; + } - TranslationUnitDecl *TU = C.getTranslationUnitDecl(); + default: + break; + } + } for (TUActions::iterator I = TranslationUnitActions.begin(), E = TranslationUnitActions.end(); I != E; ++I) { (*I)(*this, *Mgr, *TU); } - if (!ObjCImplementationActions.empty()) { - for (DeclContext::decl_iterator I = TU->decls_begin(), - E = TU->decls_end(); - I != E; ++I) - if (ObjCImplementationDecl* ID = dyn_cast<ObjCImplementationDecl>(*I)) - HandleCode(ID, 0, ObjCImplementationActions); - } - // Explicitly destroy the PathDiagnosticClient. This will flush its output. // FIXME: This should be replaced with something that doesn't rely on // side-effects in PathDiagnosticClient's destructor. This is required when @@ -278,7 +272,8 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { // Don't run the actions if an error has occured with parsing the file. - if (PP.getDiagnostics().hasErrorOccurred()) + Diagnostic &Diags = PP.getDiagnostics(); + if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; // Don't run the actions on declarations in header files unless @@ -310,7 +305,6 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) { static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (LiveVariables *L = mgr.getLiveVariables(D)) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); } @@ -319,7 +313,6 @@ static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (CFG* c = mgr.getCFG(D)) { - C.DisplayFunction(D); CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); } } @@ -331,15 +324,11 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, llvm::OwningPtr<GRTransferFuncs> TF(tf); - // Display progress. - C.DisplayFunction(D); - // Construct the analysis engine. We first query for the LiveVariables // information to see if the CFG is valid. // FIXME: Inter-procedural analysis will need to handle invalid CFGs. if (!mgr.getLiveVariables(D)) return; - GRExprEngine Eng(mgr, TF.take()); if (C.Opts.EnableExperimentalInternalChecks) @@ -358,7 +347,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, } // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getStackFrame(D)); + Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes()); // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. @@ -406,28 +395,24 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, static void ActionDisplayLiveVariables(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (LiveVariables* L = mgr.getLiveVariables(D)) { - C.DisplayFunction(D); L->dumpBlockLiveness(mgr.getSourceManager()); } } static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (CFG *cfg = mgr.getCFG(D)) { - C.DisplayFunction(D); cfg->dump(mgr.getLangOptions()); } } static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (CFG *cfg = mgr.getCFG(D)) { - C.DisplayFunction(D); cfg->viewCFG(mgr.getLangOptions()); } } static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckSecuritySyntaxOnly(D, BR); } @@ -443,86 +428,28 @@ static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) return; - - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); } static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); } static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); } static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, Decl *D) { - C.DisplayFunction(D); BugReporter BR(mgr); CheckSizeofPointer(D, BR); } -static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr, - TranslationUnitDecl &TU) { - - // Find the entry function definition (if any). - FunctionDecl *D = 0; - - // Must specify an entry function. - if (!C.Opts.AnalyzeSpecificFunction.empty()) { - for (DeclContext::decl_iterator I=TU.decls_begin(), E=TU.decls_end(); - I != E; ++I) { - if (FunctionDecl *fd = dyn_cast<FunctionDecl>(*I)) - if (fd->isThisDeclarationADefinition() && - fd->getNameAsString() == C.Opts.AnalyzeSpecificFunction) { - D = fd; - break; - } - } - } - - if (!D) - return; - - - // FIXME: This is largely copy of ActionGRExprEngine. Needs cleanup. - // Display progress. - C.DisplayFunction(D); - - // FIXME: Make a fake transfer function. The GRTransferFunc interface - // eventually will be removed. - GRExprEngine Eng(mgr, new GRTransferFuncs()); - - if (C.Opts.EnableExperimentalInternalChecks) - RegisterExperimentalInternalChecks(Eng); - - RegisterAppleChecks(Eng, *D); - - if (C.Opts.EnableExperimentalChecks) - RegisterExperimentalChecks(Eng); - - // Register call inliner as the last checker. - RegisterCallInliner(Eng); - - // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getStackFrame(D)); - - // Visualize the exploded graph. - if (mgr.shouldVisualizeGraphviz()) - Eng.ViewGraph(mgr.shouldTrimGraph()); - - // Display warnings. - Eng.getBugReporter().FlushReports(); -} - //===----------------------------------------------------------------------===// // AnalysisConsumer creation. //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index d069e8f..a5fcebe 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -475,7 +475,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) { if (!P.isAbsolute()) continue; - const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics()); + const llvm::MemoryBuffer *B = C.getBuffer(PP.getDiagnostics(), SM); if (!B) continue; FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User); @@ -550,8 +550,7 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { // Lex through the entire file. This will populate SourceManager with // all of the header information. Token Tok; - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. diff --git a/lib/Frontend/CodeGenAction.cpp b/lib/Frontend/CodeGenAction.cpp index b1795a3..79d7d5f 100644 --- a/lib/Frontend/CodeGenAction.cpp +++ b/lib/Frontend/CodeGenAction.cpp @@ -8,16 +8,18 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CodeGenAction.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/ADT/OwningPtr.h" @@ -28,6 +30,8 @@ #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/StandardPasses.h" #include "llvm/Support/Timer.h" #include "llvm/Target/SubtargetFeature.h" @@ -87,7 +91,7 @@ namespace { const LangOptions &langopts, const CodeGenOptions &compopts, const TargetOptions &targetopts, bool TimePasses, const std::string &infile, llvm::raw_ostream *OS, - LLVMContext& C) : + LLVMContext &C) : Diags(_Diags), Action(action), CodeGenOpts(compopts), @@ -175,6 +179,15 @@ namespace { virtual void CompleteTentativeDefinition(VarDecl *D) { Gen->CompleteTentativeDefinition(D); } + + static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context, + unsigned LocCookie) { + SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie); + ((BackendConsumer*)Context)->InlineAsmDiagHandler2(SM, Loc); + } + + void InlineAsmDiagHandler2(const llvm::SMDiagnostic &, + SourceLocation LocCookie); }; } @@ -211,127 +224,122 @@ bool BackendConsumer::AddEmitPasses() { if (Action == Backend_EmitBC) { getPerModulePasses()->add(createBitcodeWriterPass(FormattedOutStream)); - } else if (Action == Backend_EmitLL) { + return true; + } + + if (Action == Backend_EmitLL) { getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream)); + return true; + } + + bool Fast = CodeGenOpts.OptimizationLevel == 0; + + // Create the TargetMachine for generating code. + std::string Error; + std::string Triple = TheModule->getTargetTriple(); + const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); + if (!TheTarget) { + Diags.Report(diag::err_fe_unable_to_create_target) << Error; + return false; + } + + // FIXME: Expose these capabilities via actual APIs!!!! Aside from just + // being gross, this is also totally broken if we ever care about + // concurrency. + llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; + if (CodeGenOpts.FloatABI == "soft") + llvm::FloatABIType = llvm::FloatABI::Soft; + else if (CodeGenOpts.FloatABI == "hard") + llvm::FloatABIType = llvm::FloatABI::Hard; + else { + assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); + llvm::FloatABIType = llvm::FloatABI::Default; + } + NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; + llvm::UseSoftFloat = CodeGenOpts.SoftFloat; + UnwindTablesMandatory = CodeGenOpts.UnwindTables; + + TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); + + TargetMachine::setFunctionSections(CodeGenOpts.FunctionSections); + TargetMachine::setDataSections (CodeGenOpts.DataSections); + + // FIXME: Parse this earlier. + if (CodeGenOpts.RelocationModel == "static") { + TargetMachine::setRelocationModel(llvm::Reloc::Static); + } else if (CodeGenOpts.RelocationModel == "pic") { + TargetMachine::setRelocationModel(llvm::Reloc::PIC_); } else { - bool Fast = CodeGenOpts.OptimizationLevel == 0; - - // Create the TargetMachine for generating code. - std::string Error; - std::string Triple = TheModule->getTargetTriple(); - const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); - if (!TheTarget) { - Diags.Report(diag::err_fe_unable_to_create_target) << Error; - return false; - } + assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && + "Invalid PIC model!"); + TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); + } + // FIXME: Parse this earlier. + if (CodeGenOpts.CodeModel == "small") { + TargetMachine::setCodeModel(llvm::CodeModel::Small); + } else if (CodeGenOpts.CodeModel == "kernel") { + TargetMachine::setCodeModel(llvm::CodeModel::Kernel); + } else if (CodeGenOpts.CodeModel == "medium") { + TargetMachine::setCodeModel(llvm::CodeModel::Medium); + } else if (CodeGenOpts.CodeModel == "large") { + TargetMachine::setCodeModel(llvm::CodeModel::Large); + } else { + assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); + TargetMachine::setCodeModel(llvm::CodeModel::Default); + } - // FIXME: Expose these capabilities via actual APIs!!!! Aside from just - // being gross, this is also totally broken if we ever care about - // concurrency. - llvm::NoFramePointerElim = CodeGenOpts.DisableFPElim; - if (CodeGenOpts.FloatABI == "soft") - llvm::FloatABIType = llvm::FloatABI::Soft; - else if (CodeGenOpts.FloatABI == "hard") - llvm::FloatABIType = llvm::FloatABI::Hard; - else { - assert(CodeGenOpts.FloatABI.empty() && "Invalid float abi!"); - llvm::FloatABIType = llvm::FloatABI::Default; - } - NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; - llvm::UseSoftFloat = CodeGenOpts.SoftFloat; - UnwindTablesMandatory = CodeGenOpts.UnwindTables; - - TargetMachine::setAsmVerbosityDefault(CodeGenOpts.AsmVerbose); - - // FIXME: Parse this earlier. - if (CodeGenOpts.RelocationModel == "static") { - TargetMachine::setRelocationModel(llvm::Reloc::Static); - } else if (CodeGenOpts.RelocationModel == "pic") { - TargetMachine::setRelocationModel(llvm::Reloc::PIC_); - } else { - assert(CodeGenOpts.RelocationModel == "dynamic-no-pic" && - "Invalid PIC model!"); - TargetMachine::setRelocationModel(llvm::Reloc::DynamicNoPIC); - } - // FIXME: Parse this earlier. - if (CodeGenOpts.CodeModel == "small") { - TargetMachine::setCodeModel(llvm::CodeModel::Small); - } else if (CodeGenOpts.CodeModel == "kernel") { - TargetMachine::setCodeModel(llvm::CodeModel::Kernel); - } else if (CodeGenOpts.CodeModel == "medium") { - TargetMachine::setCodeModel(llvm::CodeModel::Medium); - } else if (CodeGenOpts.CodeModel == "large") { - TargetMachine::setCodeModel(llvm::CodeModel::Large); - } else { - assert(CodeGenOpts.CodeModel.empty() && "Invalid code model!"); - TargetMachine::setCodeModel(llvm::CodeModel::Default); - } + std::vector<const char *> BackendArgs; + BackendArgs.push_back("clang"); // Fake program name. + if (!CodeGenOpts.DebugPass.empty()) { + BackendArgs.push_back("-debug-pass"); + BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); + } + if (!CodeGenOpts.LimitFloatPrecision.empty()) { + BackendArgs.push_back("-limit-float-precision"); + BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); + } + if (llvm::TimePassesIsEnabled) + BackendArgs.push_back("-time-passes"); + BackendArgs.push_back(0); + llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, + const_cast<char **>(&BackendArgs[0])); + + std::string FeaturesStr; + if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { + SubtargetFeatures Features; + Features.setCPU(TargetOpts.CPU); + for (std::vector<std::string>::const_iterator + it = TargetOpts.Features.begin(), + ie = TargetOpts.Features.end(); it != ie; ++it) + Features.AddFeature(*it); + FeaturesStr = Features.getString(); + } + TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); - std::vector<const char *> BackendArgs; - BackendArgs.push_back("clang"); // Fake program name. - if (!CodeGenOpts.DebugPass.empty()) { - BackendArgs.push_back("-debug-pass"); - BackendArgs.push_back(CodeGenOpts.DebugPass.c_str()); - } - if (!CodeGenOpts.LimitFloatPrecision.empty()) { - BackendArgs.push_back("-limit-float-precision"); - BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str()); - } - if (llvm::TimePassesIsEnabled) - BackendArgs.push_back("-time-passes"); - BackendArgs.push_back(0); - llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, - (char**) &BackendArgs[0]); - - std::string FeaturesStr; - if (TargetOpts.CPU.size() || TargetOpts.Features.size()) { - SubtargetFeatures Features; - Features.setCPU(TargetOpts.CPU); - for (std::vector<std::string>::const_iterator - it = TargetOpts.Features.begin(), - ie = TargetOpts.Features.end(); it != ie; ++it) - Features.AddFeature(*it); - FeaturesStr = Features.getString(); - } - TargetMachine *TM = TheTarget->createTargetMachine(Triple, FeaturesStr); - - // Set register scheduler & allocation policy. - RegisterScheduler::setDefault(createDefaultScheduler); - RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : - createLinearScanRegisterAllocator); - - // From llvm-gcc: - // If there are passes we have to run on the entire module, we do codegen - // as a separate "pass" after that happens. - // FIXME: This is disabled right now until bugs can be worked out. Reenable - // this for fast -O0 compiles! - FunctionPassManager *PM = getCodeGenPasses(); - CodeGenOpt::Level OptLevel = CodeGenOpt::Default; - - switch (CodeGenOpts.OptimizationLevel) { - default: break; - case 0: OptLevel = CodeGenOpt::None; break; - case 3: OptLevel = CodeGenOpt::Aggressive; break; - } + // Set register scheduler & allocation policy. + RegisterScheduler::setDefault(createDefaultScheduler); + RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator : + createLinearScanRegisterAllocator); - // Request that addPassesToEmitFile run the Verifier after running - // passes which modify the IR. -#ifndef NDEBUG - bool DisableVerify = false; -#else - bool DisableVerify = true; -#endif - - // Normal mode, emit a .s or .o file by running the code generator. Note, - // this also adds codegenerator level optimization passes. - TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; - if (Action == Backend_EmitObj) - CGFT = TargetMachine::CGFT_ObjectFile; - if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel, - DisableVerify)) { - Diags.Report(diag::err_fe_unable_to_interface_with_target); - return false; - } + // Create the code generator passes. + FunctionPassManager *PM = getCodeGenPasses(); + CodeGenOpt::Level OptLevel = CodeGenOpt::Default; + + switch (CodeGenOpts.OptimizationLevel) { + default: break; + case 0: OptLevel = CodeGenOpt::None; break; + case 3: OptLevel = CodeGenOpt::Aggressive; break; + } + + // Normal mode, emit a .s or .o file by running the code generator. Note, + // this also adds codegenerator level optimization passes. + TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; + if (Action == Backend_EmitObj) + CGFT = TargetMachine::CGFT_ObjectFile; + if (TM->addPassesToEmitFile(*PM, FormattedOutStream, CGFT, OptLevel, + /*DisableVerify=*/!CodeGenOpts.VerifyModule)) { + Diags.Report(diag::err_fe_unable_to_interface_with_target); + return false; } return true; @@ -432,14 +440,81 @@ void BackendConsumer::EmitAssembly() { if (CodeGenPasses) { PrettyStackTraceString CrashInfo("Code generation"); + + // Install an inline asm handler so that diagnostics get printed through our + // diagnostics hooks. + LLVMContext &Ctx = TheModule->getContext(); + void *OldHandler = Ctx.getInlineAsmDiagnosticHandler(); + void *OldContext = Ctx.getInlineAsmDiagnosticContext(); + Ctx.setInlineAsmDiagnosticHandler((void*)(intptr_t)InlineAsmDiagHandler, + this); + CodeGenPasses->doInitialization(); for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) if (!I->isDeclaration()) CodeGenPasses->run(*I); CodeGenPasses->doFinalization(); + + Ctx.setInlineAsmDiagnosticHandler(OldHandler, OldContext); } } +/// ConvertBackendLocation - Convert a location in a temporary llvm::SourceMgr +/// buffer to be a valid FullSourceLoc. +static FullSourceLoc ConvertBackendLocation(const llvm::SMDiagnostic &D, + SourceManager &CSM) { + // Get both the clang and llvm source managers. The location is relative to + // a memory buffer that the LLVM Source Manager is handling, we need to add + // a copy to the Clang source manager. + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + + // We need to copy the underlying LLVM memory buffer because llvm::SourceMgr + // already owns its one and clang::SourceManager wants to own its one. + const MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + + // Create the copy and transfer ownership to clang::SourceManager. + llvm::MemoryBuffer *CBuf = + llvm::MemoryBuffer::getMemBufferCopy(LBuf->getBuffer(), + LBuf->getBufferIdentifier()); + FileID FID = CSM.createFileIDForMemBuffer(CBuf); + + // Translate the offset into the file. + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + SourceLocation NewLoc = + CSM.getLocForStartOfFile(FID).getFileLocWithOffset(Offset); + return FullSourceLoc(NewLoc, CSM); +} + + +/// InlineAsmDiagHandler2 - This function is invoked when the backend hits an +/// error parsing inline asm. The SMDiagnostic indicates the error relative to +/// the temporary memory buffer that the inline asm parser has set up. +void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, + SourceLocation LocCookie) { + // There are a couple of different kinds of errors we could get here. First, + // we re-format the SMDiagnostic in terms of a clang diagnostic. + + // Strip "error: " off the start of the message string. + llvm::StringRef Message = D.getMessage(); + if (Message.startswith("error: ")) + Message = Message.substr(7); + + // There are two cases: the SMDiagnostic could have a inline asm source + // location or it might not. If it does, translate the location. + FullSourceLoc Loc; + if (D.getLoc() != SMLoc()) + Loc = ConvertBackendLocation(D, Context->getSourceManager()); + Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message); + + // This could be a problem with no clang-level source location information. + // In this case, LocCookie is invalid. If there is source level information, + // print an "generated from" note. + if (LocCookie.isValid()) + Diags.Report(FullSourceLoc(LocCookie, Context->getSourceManager()), + diag::note_fe_inline_asm_here); +} + // CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {} diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 1f915e3..5ed9c40 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -513,11 +513,20 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { } } - if (getDiagnosticOpts().ShowCarets) - if (unsigned NumDiagnostics = getDiagnostics().getNumDiagnostics()) - OS << NumDiagnostics << " diagnostic" - << (NumDiagnostics == 1 ? "" : "s") - << " generated.\n"; + if (getDiagnosticOpts().ShowCarets) { + unsigned NumWarnings = getDiagnostics().getNumWarnings(); + unsigned NumErrors = getDiagnostics().getNumErrors() - + getDiagnostics().getNumErrorsSuppressed(); + + if (NumWarnings) + OS << NumWarnings << " warning" << (NumWarnings == 1 ? "" : "s"); + if (NumWarnings && NumErrors) + OS << " and "; + if (NumErrors) + OS << NumErrors << " error" << (NumErrors == 1 ? "" : "s"); + if (NumWarnings || NumErrors) + OS << " generated.\n"; + } if (getFrontendOpts().ShowStats) { getFileManager().PrintStats(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index dc2c6bf..8ffdde2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -145,9 +145,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, // TimePasses is only derived. // UnitAtATime is unused. // UnrollLoops is only derived. - // VerifyModule is only derived. // Inlining is only derived. + if (Opts.DataSections) + Res.push_back("-fdata-sections"); + if (Opts.FunctionSections) + Res.push_back("-ffunction-sections"); if (Opts.AsmVerbose) Res.push_back("-masm-verbose"); if (!Opts.CodeModel.empty()) { @@ -174,8 +177,16 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, } if (Opts.NoZeroInitializedInBSS) Res.push_back("-mno-zero-initialized-bss"); - if (Opts.ObjCLegacyDispatch) - Res.push_back("-fobjc-legacy-dispatch"); + switch (Opts.getObjCDispatchMethod()) { + case CodeGenOptions::Legacy: + break; + case CodeGenOptions::Mixed: + Res.push_back("-fobjc-dispatch-method=mixed"); + break; + case CodeGenOptions::NonLegacy: + Res.push_back("-fobjc-dispatch-method=non-legacy"); + break; + } if (Opts.SoftFloat) Res.push_back("-msoft-float"); if (Opts.UnwindTables) @@ -232,6 +243,15 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fdiagnostics-binary"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); + if (Opts.ErrorLimit) { + Res.push_back("-ferror-limit"); + Res.push_back(llvm::utostr(Opts.ErrorLimit)); + } + if (Opts.TemplateBacktraceLimit != 10) { + Res.push_back("-ftemplate-backtrace-limit"); + Res.push_back(llvm::utostr(Opts.TemplateBacktraceLimit)); + } + if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) { Res.push_back("-ftabstop"); Res.push_back(llvm::utostr(Opts.TabStop)); @@ -279,7 +299,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTPrintXML: return "-ast-print-xml"; case frontend::ASTView: return "-ast-view"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; - case frontend::DumpRecordLayouts: return "-dump-record-layouts"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; case frontend::EmitBC: return "-emit-llvm-bc"; @@ -349,12 +368,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-cxx-inheritance-view"); Res.push_back(Opts.ViewClassInheritance); } - for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) { - Res.push_back("-fixit-at"); - Res.push_back(Opts.FixItLocations[i].FileName + ":" + - llvm::utostr(Opts.FixItLocations[i].Line) + ":" + - llvm::utostr(Opts.FixItLocations[i].Column)); - } if (!Opts.CodeCompletionAt.FileName.empty()) { Res.push_back("-code-completion-at"); Res.push_back(Opts.CodeCompletionAt.FileName + ":" + @@ -376,6 +389,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); } + for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { + Res.push_back("-mllvm"); + Res.push_back(Opts.LLVMArgs[i]); + } } static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, @@ -389,7 +406,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) - llvm::llvm_report_error("Invalid option set!"); + llvm::report_fatal_error("Invalid option set!"); if (E.IsUserSupplied) { if (E.Group == frontend::After) { Res.push_back("-idirafter"); @@ -403,7 +420,7 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, } } else { if (E.Group != frontend::Angled && E.Group != frontend::System) - llvm::llvm_report_error("Invalid option set!"); + llvm::report_fatal_error("Invalid option set!"); Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : "-iwithprefix"); } @@ -412,23 +429,23 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, if (!Opts.EnvIncPath.empty()) { // FIXME: Provide an option for this, and move env detection to driver. - llvm::llvm_report_error("Not yet implemented!"); + llvm::report_fatal_error("Not yet implemented!"); } if (!Opts.CEnvIncPath.empty()) { // FIXME: Provide an option for this, and move env detection to driver. - llvm::llvm_report_error("Not yet implemented!"); + llvm::report_fatal_error("Not yet implemented!"); } if (!Opts.ObjCEnvIncPath.empty()) { // FIXME: Provide an option for this, and move env detection to driver. - llvm::llvm_report_error("Not yet implemented!"); + llvm::report_fatal_error("Not yet implemented!"); } if (!Opts.CXXEnvIncPath.empty()) { // FIXME: Provide an option for this, and move env detection to driver. - llvm::llvm_report_error("Not yet implemented!"); + llvm::report_fatal_error("Not yet implemented!"); } if (!Opts.ObjCXXEnvIncPath.empty()) { // FIXME: Provide an option for this, and move env detection to driver. - llvm::llvm_report_error("Not yet implemented!"); + llvm::report_fatal_error("Not yet implemented!"); } if (!Opts.ResourceDir.empty()) { Res.push_back("-resource-dir"); @@ -462,6 +479,10 @@ static void LangOptsToArgs(const LangOptions &Opts, // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode if (Opts.DollarIdents) Res.push_back("-fdollars-in-identifiers"); + if (Opts.GNUMode && !Opts.GNUKeywords) + Res.push_back("-fno-gnu-keywords"); + if (!Opts.GNUMode && Opts.GNUKeywords) + Res.push_back("-fgnu-keywords"); if (Opts.Microsoft) Res.push_back("-fms-extensions"); if (Opts.ObjCNonFragileABI) @@ -515,15 +536,24 @@ static void LangOptsToArgs(const LangOptions &Opts, // OptimizeSize is implicit. if (Opts.Static) Res.push_back("-static-define"); + if (Opts.DumpRecordLayouts) + Res.push_back("-fdump-record-layouts"); + if (Opts.DumpVTableLayouts) + Res.push_back("-fdump-vtable-layouts"); + if (Opts.NoBitFieldTypeAlign) + Res.push_back("-fno-bitfield-type-alignment"); + if (Opts.SjLjExceptions) + Res.push_back("-fsjlj-exceptions"); if (Opts.PICLevel) { Res.push_back("-pic-level"); Res.push_back(llvm::utostr(Opts.PICLevel)); } if (Opts.ObjCGCBitmapPrint) Res.push_back("-print-ivar-layout"); - // FIXME: Don't forget to update when the default changes! - if (Opts.AccessControl) - Res.push_back("-faccess-control"); + if (Opts.NoConstantCFStrings) + Res.push_back("-fno-constant-cfstrings"); + if (!Opts.AccessControl) + Res.push_back("-fno-access-control"); if (!Opts.CharIsSigned) Res.push_back("-fno-signed-char"); if (Opts.ShortWChar) @@ -606,7 +636,7 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, std::vector<std::string> &Res) { if (!Opts.ShowCPP && !Opts.ShowMacros) - llvm::llvm_report_error("Invalid option combination!"); + llvm::report_fatal_error("Invalid option combination!"); if (Opts.ShowCPP && Opts.ShowMacros) Res.push_back("-dD"); @@ -756,6 +786,7 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.EnableExperimentalInternalChecks = Args.hasArg(OPT_analyzer_experimental_internal_checks); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); + Opts.MaxNodes = getLastArgIntValue(Args, OPT_analyzer_max_nodes,150000,Diags); } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, @@ -796,13 +827,28 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.FloatABI = getLastArgValue(Args, OPT_mfloat_abi); Opts.LimitFloatPrecision = getLastArgValue(Args, OPT_mlimit_float_precision); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); - Opts.ObjCLegacyDispatch = Args.hasArg(OPT_fobjc_legacy_dispatch); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); + Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections); + Opts.DataSections = Args.hasArg(OPT_fdata_sections); + Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + + if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { + llvm::StringRef Name = A->getValue(Args); + unsigned Method = llvm::StringSwitch<unsigned>(Name) + .Case("legacy", CodeGenOptions::Legacy) + .Case("non-legacy", CodeGenOptions::NonLegacy) + .Case("mixed", CodeGenOptions::Mixed) + .Default(~0U); + if (Method == ~0U) + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + else + Opts.ObjCDispatchMethod = Method; + } } static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, @@ -830,6 +876,9 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); + Opts.ErrorLimit = getLastArgIntValue(Args, OPT_ferror_limit, 0, Diags); + Opts.TemplateBacktraceLimit + = getLastArgIntValue(Args, OPT_ftemplate_backtrace_limit, 0, Diags); Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop, DiagnosticOptions::DefaultTabStop, Diags); if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) { @@ -860,8 +909,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::ASTView; break; case OPT_dump_raw_tokens: Opts.ProgramAction = frontend::DumpRawTokens; break; - case OPT_dump_record_layouts: - Opts.ProgramAction = frontend::DumpRecordLayouts; break; case OPT_dump_tokens: Opts.ProgramAction = frontend::DumpTokens; break; case OPT_S: @@ -876,6 +923,9 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::EmitLLVMOnly; break; case OPT_emit_obj: Opts.ProgramAction = frontend::EmitObj; break; + case OPT_fixit_EQ: + Opts.FixItSuffix = A->getValue(Args); + // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; case OPT_emit_pch: @@ -922,20 +972,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { !Args.hasArg(OPT_no_code_completion_debug_printer); Opts.DisableFree = Args.hasArg(OPT_disable_free); - Opts.FixItLocations.clear(); - for (arg_iterator it = Args.filtered_begin(OPT_fixit_at), - ie = Args.filtered_end(); it != ie; ++it) { - const char *Loc = it->getValue(Args); - ParsedSourceLocation PSL = ParsedSourceLocation::FromString(Loc); - - if (PSL.FileName.empty()) { - Diags.Report(diag::err_drv_invalid_value) << it->getAsString(Args) << Loc; - continue; - } - - Opts.FixItLocations.push_back(PSL); - } - Opts.OutputFile = getLastArgValue(Args, OPT_o); Opts.Plugins = getAllArgValues(Args, OPT_load); Opts.RelocatablePCH = Args.hasArg(OPT_relocatable_pch); @@ -946,6 +982,7 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = getLastArgValue(Args, OPT_cxx_inheritance_view); Opts.ASTMergeFiles = getAllArgValues(Args, OPT_ast_merge); + Opts.LLVMArgs = getAllArgValues(Args, OPT_mllvm); FrontendOptions::InputKind DashX = FrontendOptions::IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1129,6 +1166,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, // OpenCL and C++ both have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension + // keywords. This behavior is provided by GCC's poorly named '-fasm' flag, + // while a subset (the non-C++ GNU keywords) is provided by GCC's + // '-fgnu-keywords'. Clang conflates the two for simplicity under the single + // name, as it doesn't seem a useful distinction. + Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords, + Opts.GNUMode); + if (Opts.CPlusPlus) Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names); @@ -1139,6 +1184,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Args.hasArg(OPT_print_ivar_layout)) Opts.ObjCGCBitmapPrint = 1; + if (Args.hasArg(OPT_fno_constant_cfstrings)) + Opts.NoConstantCFStrings = 1; if (Args.hasArg(OPT_faltivec)) Opts.AltiVec = 1; @@ -1186,10 +1233,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); - Opts.AccessControl = Args.hasArg(OPT_faccess_control); + Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Opts.MathErrno = Args.hasArg(OPT_fmath_errno); - Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99, + Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 1024, Diags); Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime); Opts.ObjCConstantStringClass = getLastArgValue(Args, @@ -1203,7 +1250,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); Opts.Static = Args.hasArg(OPT_static_define); - Opts.DumpVtableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); + Opts.DumpRecordLayouts = Args.hasArg(OPT_fdump_record_layouts); + Opts.DumpVTableLayouts = Args.hasArg(OPT_fdump_vtable_layouts); + Opts.NoBitFieldTypeAlign = Args.hasArg(OPT_fno_bitfield_type_align); Opts.OptimizeSize = 0; // FIXME: Eliminate this dependency. @@ -1268,6 +1317,10 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.Includes.push_back(it->getValue(Args)); } + // Include 'altivec.h' if -faltivec option present + if (Args.hasArg(OPT_faltivec)) + Opts.Includes.push_back("altivec.h"); + for (arg_iterator it = Args.filtered_begin(OPT_remap_file), ie = Args.filtered_end(); it != ie; ++it) { std::pair<llvm::StringRef,llvm::StringRef> Split = diff --git a/lib/Frontend/FixItRewriter.cpp b/lib/Frontend/FixItRewriter.cpp index 20d452e..7c9a566 100644 --- a/lib/Frontend/FixItRewriter.cpp +++ b/lib/Frontend/FixItRewriter.cpp @@ -14,6 +14,8 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/FixItRewriter.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Support/raw_ostream.h" @@ -24,8 +26,12 @@ using namespace clang; FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, - const LangOptions &LangOpts) - : Diags(Diags), Rewrite(SourceMgr, LangOpts), NumFailures(0) { + const LangOptions &LangOpts, + FixItPathRewriter *PathRewriter) + : Diags(Diags), + Rewrite(SourceMgr, LangOpts), + PathRewriter(PathRewriter), + NumFailures(0) { Client = Diags.getClient(); Diags.setClient(this); } @@ -34,92 +40,53 @@ FixItRewriter::~FixItRewriter() { Diags.setClient(Client); } -bool FixItRewriter::WriteFixedFile(const std::string &InFileName, - const std::string &OutFileName) { +bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) { + const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(ID); + if (!RewriteBuf) return true; + RewriteBuf->write(OS); + OS.flush(); + return false; +} + +bool FixItRewriter::WriteFixedFiles() { if (NumFailures > 0) { Diag(FullSourceLoc(), diag::warn_fixit_no_changes); return true; } - llvm::OwningPtr<llvm::raw_ostream> OwnedStream; - llvm::raw_ostream *OutFile; - if (!OutFileName.empty()) { - std::string Err; - OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err, - llvm::raw_fd_ostream::F_Binary); - OwnedStream.reset(OutFile); - } else if (InFileName == "-") { - OutFile = &llvm::outs(); - } else { - llvm::sys::Path Path(InFileName); - std::string Suffix = Path.getSuffix(); - Path.eraseSuffix(); - Path.appendSuffix("fixit." + Suffix); + for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { + const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); + std::string Filename = Entry->getName(); + if (PathRewriter) + Filename = PathRewriter->RewriteFilename(Filename); std::string Err; - OutFile = new llvm::raw_fd_ostream(Path.c_str(), Err, - llvm::raw_fd_ostream::F_Binary); - OwnedStream.reset(OutFile); - } - - FileID MainFileID = Rewrite.getSourceMgr().getMainFileID(); - if (const RewriteBuffer *RewriteBuf = - Rewrite.getRewriteBufferFor(MainFileID)) { - *OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); - } else { - Diag(FullSourceLoc(), diag::note_fixit_main_file_unchanged); + llvm::raw_fd_ostream OS(Filename.c_str(), Err, + llvm::raw_fd_ostream::F_Binary); + if (!Err.empty()) { + Diags.Report(clang::diag::err_fe_unable_to_open_output) + << Filename << Err; + continue; + } + RewriteBuffer &RewriteBuf = I->second; + RewriteBuf.write(OS); + OS.flush(); } - OutFile->flush(); return false; } bool FixItRewriter::IncludeInDiagnosticCounts() const { - return Client? Client->IncludeInDiagnosticCounts() : true; + return Client ? Client->IncludeInDiagnosticCounts() : true; } void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, const DiagnosticInfo &Info) { Client->HandleDiagnostic(DiagLevel, Info); - // Skip over any diagnostics that are ignored. - if (DiagLevel == Diagnostic::Ignored) + // Skip over any diagnostics that are ignored or notes. + if (DiagLevel <= Diagnostic::Note) return; - if (!FixItLocations.empty()) { - // The user has specified the locations where we should perform - // the various fix-it modifications. - - // If this diagnostic does not have any code modifications, - // completely ignore it, even if it's an error: fix-it locations - // are meant to perform specific fix-ups even in the presence of - // other errors. - if (Info.getNumFixItHints() == 0) - return; - - // See if the location of the error is one that matches what the - // user requested. - bool AcceptableLocation = false; - const FileEntry *File - = Rewrite.getSourceMgr().getFileEntryForID( - Info.getLocation().getFileID()); - unsigned Line = Info.getLocation().getSpellingLineNumber(); - unsigned Column = Info.getLocation().getSpellingColumnNumber(); - for (llvm::SmallVector<RequestedSourceLocation, 4>::iterator - Loc = FixItLocations.begin(), LocEnd = FixItLocations.end(); - Loc != LocEnd; ++Loc) { - if (Loc->File == File && Loc->Line == Line && Loc->Column == Column) { - AcceptableLocation = true; - break; - } - } - - if (!AcceptableLocation) - return; - } else if (DiagLevel == Diagnostic::Note) { - // Don't apply fix-it modifications in notes. - return; - } - // Make sure that we can perform all of the modifications we // in this diagnostic. bool CanRewrite = Info.getNumFixItHints() > 0; @@ -196,3 +163,5 @@ void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) { Diags.Report(Loc, DiagID); Diags.setClient(this); } + +FixItPathRewriter::~FixItPathRewriter() {} diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 251b8e4..6cd960b 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -19,6 +19,7 @@ #include "clang/Frontend/FixItRewriter.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -74,11 +75,6 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, return CreateDeclContextPrinter(); } -ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - return CreateRecordLayoutDumper(); -} - ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; @@ -118,43 +114,38 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, return new ASTConsumer(); } -/// AddFixItLocations - Add any individual user specified "fix-it" locations, -/// and return true on success. -static bool AddFixItLocations(CompilerInstance &CI, - FixItRewriter &FixItRewrite) { - const std::vector<ParsedSourceLocation> &Locs = - CI.getFrontendOpts().FixItLocations; - for (unsigned i = 0, e = Locs.size(); i != e; ++i) { - const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName); - if (!File) { - CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file) - << Locs[i].FileName; - return false; - } - - RequestedSourceLocation Requested; - Requested.File = File; - Requested.Line = Locs[i].Line; - Requested.Column = Locs[i].Column; - FixItRewrite.addFixItLocation(Requested); - } +class FixItActionSuffixInserter : public FixItPathRewriter { + std::string NewSuffix; - return true; -} +public: + explicit FixItActionSuffixInserter(std::string NewSuffix) + : NewSuffix(NewSuffix) {} + + std::string RewriteFilename(const std::string &Filename) { + llvm::sys::Path Path(Filename); + std::string Suffix = Path.getSuffix(); + Path.eraseSuffix(); + Path.appendSuffix(NewSuffix + "." + Suffix); + return Path.c_str(); + } +}; bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, llvm::StringRef Filename) { + const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); + if (!FEOpts.FixItSuffix.empty()) { + PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix)); + } else { + PathRewriter.reset(); + } Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts())); - if (!AddFixItLocations(CI, *Rewriter)) - return false; - + CI.getLangOpts(), PathRewriter.get())); return true; } void FixItAction::EndSourceFileAction() { - const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); - Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile); + // Otherwise rewrite all files. + Rewriter->WriteFixedFiles(); } ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, @@ -197,8 +188,7 @@ void DumpTokensAction::ExecuteAction() { Preprocessor &PP = getCompilerInstance().getPreprocessor(); // Start preprocessing the specified input file. Token Tok; - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); do { PP.Lex(Tok); PP.DumpToken(Tok, true); @@ -212,7 +202,7 @@ void GeneratePTHAction::ExecuteAction() { CI.getFrontendOpts().OutputFile == "-") { // FIXME: Don't fail this way. // FIXME: Verify that we can actually seek in the given file. - llvm::llvm_report_error("PTH requires a seekable file for output!"); + llvm::report_fatal_error("PTH requires a seekable file for output!"); } llvm::raw_fd_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); @@ -226,8 +216,7 @@ void ParseOnlyAction::ExecuteAction() { llvm::OwningPtr<Action> PA(new MinimalAction(PP)); Parser P(PP, *PA); - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); P.ParseTranslationUnit(); } @@ -236,8 +225,7 @@ void PreprocessOnlyAction::ExecuteAction() { Token Tok; // Start parsing the specified input file. - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); @@ -252,8 +240,7 @@ void PrintParseAction::ExecuteAction() { llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); Parser P(PP, *PA); - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); P.ParseTranslationUnit(); } diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 9f5bced..12a4d4d 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -355,7 +355,7 @@ static bool getVisualStudioDir(std::string &path) { else if (vs80comntools) vscomntools = vs80comntools; if (vscomntools && *vscomntools) { - char *p = (char*)strstr(vscomntools, "\\Common7\\Tools"); + char *p = const_cast<char *>(strstr(vscomntools, "\\Common7\\Tools")); if (p) *p = '\0'; path = vscomntools; @@ -429,6 +429,49 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple) { } } break; + case llvm::Triple::Haiku: + AddPath("/boot/common/include", System, true, false, false); + AddPath("/boot/develop/headers/os", System, true, false, false); + AddPath("/boot/develop/headers/os/app", System, true, false, false); + AddPath("/boot/develop/headers/os/arch", System, true, false, false); + AddPath("/boot/develop/headers/os/device", System, true, false, false); + AddPath("/boot/develop/headers/os/drivers", System, true, false, false); + AddPath("/boot/develop/headers/os/game", System, true, false, false); + AddPath("/boot/develop/headers/os/interface", System, true, false, false); + AddPath("/boot/develop/headers/os/kernel", System, true, false, false); + AddPath("/boot/develop/headers/os/locale", System, true, false, false); + AddPath("/boot/develop/headers/os/mail", System, true, false, false); + AddPath("/boot/develop/headers/os/media", System, true, false, false); + AddPath("/boot/develop/headers/os/midi", System, true, false, false); + AddPath("/boot/develop/headers/os/midi2", System, true, false, false); + AddPath("/boot/develop/headers/os/net", System, true, false, false); + AddPath("/boot/develop/headers/os/storage", System, true, false, false); + AddPath("/boot/develop/headers/os/support", System, true, false, false); + AddPath("/boot/develop/headers/os/translation", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/graphics", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/input_server", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/screen_saver", + System, true, false, false); + AddPath("/boot/develop/headers/os/add-ons/tracker", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/Deskbar", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/NetPositive", + System, true, false, false); + AddPath("/boot/develop/headers/os/be_apps/Tracker", + System, true, false, false); + AddPath("/boot/develop/headers/cpp", System, true, false, false); + AddPath("/boot/develop/headers/cpp/i586-pc-haiku", + System, true, false, false); + AddPath("/boot/develop/headers/3rdparty", System, true, false, false); + AddPath("/boot/develop/headers/bsd", System, true, false, false); + AddPath("/boot/develop/headers/glibc", System, true, false, false); + AddPath("/boot/develop/headers/posix", System, true, false, false); + AddPath("/boot/develop/headers", System, true, false, false); + break; case llvm::Triple::MinGW64: case llvm::Triple::MinGW32: AddPath("c:/mingw/include", System, true, false, false); @@ -521,14 +564,26 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); + // Fedora 11 x86_64 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", + "x86_64-redhat-linux", "32", "", triple); + // Fedora 12 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", "i686-redhat-linux","", "", triple); + // Fedora 12 x86_64 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.2", + "x86_64-redhat-linux", "32", "", triple); + // Fedora 12 (February-2010+) AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", "i686-redhat-linux","", "", triple); - + + // Fedora 12 (February-2010+) x86_64 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.3", + "x86_64-redhat-linux", "32", "", triple); + // openSUSE 11.1 32 bit AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3", "i586-suse-linux", "", "", triple); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 8bcd3a8..f1e9819 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Version.h" #include "clang/Frontend/Utils.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetInfo.h" @@ -212,7 +213,20 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Compiler version introspection macros. Builder.defineMacro("__llvm__"); // LLVM Backend Builder.defineMacro("__clang__"); // Clang Frontend - +#define TOSTR2(X) #X +#define TOSTR(X) TOSTR2(X) + Builder.defineMacro("__clang_major__", TOSTR(CLANG_VERSION_MAJOR)); + Builder.defineMacro("__clang_minor__", TOSTR(CLANG_VERSION_MINOR)); +#ifdef CLANG_VERSION_PATCHLEVEL + Builder.defineMacro("__clang_patchlevel__", TOSTR(CLANG_VERSION_PATCHLEVEL)); +#else + Builder.defineMacro("__clang_patchlevel__", "0"); +#endif + Builder.defineMacro("__clang_version__", + "\"" CLANG_VERSION_STRING " (" + + getClangFullRepositoryVersion() + ")\""); +#undef TOSTR +#undef TOSTR2 // Currently claim to be compatible with GCC 4.2.1-5621. Builder.defineMacro("__GNUC_MINOR__", "2"); Builder.defineMacro("__GNUC_PATCHLEVEL__", "1"); @@ -294,8 +308,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // C++ translation unit. Builder.defineMacro("__cplusplus", "199711L"); Builder.defineMacro("__private_extern__", "extern"); - // Ugly hack to work with GNU libstdc++. - Builder.defineMacro("_GNU_SOURCE"); } if (LangOpts.Microsoft) { @@ -503,7 +515,11 @@ void clang::InitializePreprocessor(Preprocessor &PP, InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); - Builder.append("# 1 \"<built-in>\" 3"); + // Emit line markers for various builtin sections of the file. We don't do + // this in asm preprocessor mode, because "# 4" is not a line marker directive + // in this mode. + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<built-in>\" 3"); // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) @@ -512,7 +528,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. - Builder.append("# 1 \"<command line>\" 1"); + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<command line>\" 1"); // Process #define's and #undef's in the order they are given. for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { @@ -538,7 +555,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, } // Exit the command line and go back to <built-in> (2 is LC_LEAVE). - Builder.append("# 1 \"<built-in>\" 2"); + if (!PP.getLangOptions().AsmPreprocessor) + Builder.append("# 1 \"<built-in>\" 2"); // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); diff --git a/lib/Frontend/LangStandards.cpp b/lib/Frontend/LangStandards.cpp index ed0ea1f..af1721d 100644 --- a/lib/Frontend/LangStandards.cpp +++ b/lib/Frontend/LangStandards.cpp @@ -22,7 +22,7 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { default: llvm_unreachable("Invalid language kind!"); case lang_unspecified: - llvm::llvm_report_error("getLangStandardForKind() on unspecified kind"); + llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); #define LANGSTANDARD(id, name, desc, features) \ case lang_##id: return Lang_##id; #include "clang/Frontend/LangStandards.def" diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index b96c04d0..ae57ce5 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -62,6 +62,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_BENIGN(DollarIdents); PARSE_LANGOPT_BENIGN(AsmPreprocessor); PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); + PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords); PARSE_LANGOPT_BENIGN(ImplicitInt); PARSE_LANGOPT_BENIGN(Digraphs); PARSE_LANGOPT_BENIGN(HexFloats); @@ -74,6 +75,8 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2); + PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings, + diag::warn_pch_no_constant_cfstrings); PARSE_LANGOPT_BENIGN(PascalStrings); PARSE_LANGOPT_BENIGN(WritableStrings); PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, @@ -910,8 +913,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } - if ((off_t)Record[4] != File->getSize() || - (time_t)Record[5] != File->getModificationTime()) { + if ((off_t)Record[4] != File->getSize() +#if !defined(LLVM_ON_WIN32) + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || (time_t)Record[5] != File->getModificationTime() +#endif + ) { Diag(diag::err_fe_pch_file_modified) << Filename; return Failure; @@ -1757,17 +1766,16 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { if (unsigned ObjCClassRedef = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); -#if 0 - // FIXME. Accommodate for this in several PCH/Index tests - if (unsigned ObjCSelRedef - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) - Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); -#endif if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) Context->setBlockDescriptorType(GetType(String)); if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) Context->setBlockDescriptorExtendedType(GetType(String)); + if (unsigned ObjCSelRedef + = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) + Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); + if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING]) + Context->setNSConstantStringType(GetType(String)); } /// \brief Retrieve the name of the original source file name @@ -1879,6 +1887,7 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(DollarIdents); PARSE_LANGOPT(AsmPreprocessor); PARSE_LANGOPT(GNUMode); + PARSE_LANGOPT(GNUKeywords); PARSE_LANGOPT(ImplicitInt); PARSE_LANGOPT(Digraphs); PARSE_LANGOPT(HexFloats); @@ -1891,6 +1900,7 @@ bool PCHReader::ParseLanguageOptions( PARSE_LANGOPT(ObjC2); PARSE_LANGOPT(ObjCNonFragileABI); PARSE_LANGOPT(ObjCNonFragileABI2); + PARSE_LANGOPT(NoConstantCFStrings); PARSE_LANGOPT(PascalStrings); PARSE_LANGOPT(WritableStrings); PARSE_LANGOPT(LaxVectorConversions); @@ -2843,6 +2853,14 @@ Selector PCHReader::DecodeSelector(unsigned ID) { return SelectorsLoaded[Index]; } +Selector PCHReader::GetSelector(uint32_t ID) { + return DecodeSelector(ID); +} + +uint32_t PCHReader::GetNumKnownSelectors() { + return TotalNumSelectors + 1; +} + DeclarationName PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index f847bec..14dd2e9 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -179,6 +179,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setPreviousDeclaration( cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++]))); FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); + FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]); FD->setInlineSpecified(Record[Idx++]); FD->setVirtualAsWritten(Record[Idx++]); FD->setPure(Record[Idx++]); @@ -196,6 +197,11 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); FD->setParams(Params.data(), NumParams); + + // FIXME: order this properly w.r.t. friendness + // FIXME: this same thing needs to happen for function templates + if (FD->isOverloadedOperator() && !FD->getDeclContext()->isRecord()) + FD->setNonMemberOperator(); } void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { @@ -212,6 +218,7 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setSynthesized(Record[Idx++]); MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); + MD->setNumSelectorArgs(unsigned(Record[Idx++])); MD->setResultType(Reader.GetType(Record[Idx++])); MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -220,7 +227,8 @@ void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) Params.push_back(cast<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); - MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams); + MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams, + NumParams); } void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { @@ -375,6 +383,7 @@ void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); D->setSuperClass( cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++]))); + // FIXME. Add reading of IvarInitializers and NumIvarInitializers. } @@ -397,9 +406,11 @@ void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { void PCHDeclReader::VisitVarDecl(VarDecl *VD) { VisitDeclaratorDecl(VD); VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]); + VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]); VD->setThreadSpecified(Record[Idx++]); VD->setCXXDirectInitializer(Record[Idx++]); VD->setDeclaredInCondition(Record[Idx++]); + VD->setExceptionVariable(Record[Idx++]); VD->setPreviousDeclaration( cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); if (Record[Idx++]) @@ -744,7 +755,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { break; case pch::DECL_VAR: D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - VarDecl::None); + VarDecl::None, VarDecl::None); break; case pch::DECL_IMPLICIT_PARAM: @@ -753,7 +764,7 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { case pch::DECL_PARM_VAR: D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - VarDecl::None, 0); + VarDecl::None, VarDecl::None, 0); break; case pch::DECL_FILE_SCOPE_ASM: D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 7b94805..ef6b770 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -71,6 +71,7 @@ namespace { unsigned VisitCharacterLiteral(CharacterLiteral *E); unsigned VisitParenExpr(ParenExpr *E); unsigned VisitUnaryOperator(UnaryOperator *E); + unsigned VisitOffsetOfExpr(OffsetOfExpr *E); unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E); unsigned VisitCallExpr(CallExpr *E); @@ -432,6 +433,49 @@ unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) { return 1; } +unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { + typedef OffsetOfExpr::OffsetOfNode Node; + VisitExpr(E); + assert(E->getNumComponents() == Record[Idx]); + ++Idx; + assert(E->getNumExpressions() == Record[Idx]); + ++Idx; + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]); + SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]); + SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]); + switch (Kind) { + case Node::Array: + E->setComponent(I, Node(Start, Record[Idx++], End)); + break; + + case Node::Field: + E->setComponent(I, + Node(Start, + dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])), + End)); + break; + + case Node::Identifier: + E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End)); + break; + + case Node::Base: + // FIXME: Implement this! + llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); + break; + } + } + + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + E->setIndexExpr(I, cast_or_null<Expr>(StmtStack[StmtStack.size() - N + I])); + + return E->getNumExpressions(); +} + unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); E->setSizeof(Record[Idx++]); @@ -554,9 +598,9 @@ unsigned PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { unsigned PCHStmtReader::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); unsigned NumInits = Record[Idx++]; - E->reserveInits(NumInits); + E->reserveInits(*Reader.getContext(), NumInits); for (unsigned I = 0; I != NumInits; ++I) - E->updateInit(I, + E->updateInit(*Reader.getContext(), I, cast<Expr>(StmtStack[StmtStack.size() - NumInits - 1 + I])); E->setSyntacticForm(cast_or_null<InitListExpr>(StmtStack.back())); E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); @@ -725,7 +769,7 @@ unsigned PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) { unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { VisitExpr(E); - E->setEncodedType(Reader.GetType(Record[Idx++])); + E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); return 0; @@ -782,25 +826,42 @@ unsigned PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr( unsigned PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { VisitExpr(E); - E->setNumArgs(Record[Idx++]); - E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setSelector(Reader.GetSelector(Record, Idx)); - E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); - - E->setReceiver( + assert(Record[Idx] == E->getNumArgs()); + ++Idx; + ObjCMessageExpr::ReceiverKind Kind + = static_cast<ObjCMessageExpr::ReceiverKind>(Record[Idx++]); + switch (Kind) { + case ObjCMessageExpr::Instance: + E->setInstanceReceiver( cast_or_null<Expr>(StmtStack[StmtStack.size() - E->getNumArgs() - 1])); - if (!E->getReceiver()) { - ObjCMessageExpr::ClassInfo CI; - CI.Decl = cast_or_null<ObjCInterfaceDecl>(Reader.GetDecl(Record[Idx++])); - CI.Name = Reader.GetIdentifierInfo(Record, Idx); - CI.Loc = SourceLocation::getFromRawEncoding(Record[Idx++]); - E->setClassInfo(CI); + break; + + case ObjCMessageExpr::Class: + E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx)); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: { + QualType T = Reader.GetType(Record[Idx++]); + SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]); + E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); + break; } + } + + assert(Kind == E->getReceiverKind()); + + if (Record[Idx++]) + E->setMethodDecl(cast_or_null<ObjCMethodDecl>(Reader.GetDecl(Record[Idx++]))); + else + E->setSelector(Reader.GetSelector(Record, Idx)); + + E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I])); - return E->getNumArgs() + 1; + return E->getNumArgs() + (Kind == ObjCMessageExpr::Instance); } unsigned PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) { @@ -821,12 +882,11 @@ unsigned PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { unsigned PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { VisitStmt(S); - S->setCatchBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2])); - S->setNextCatchStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); - S->setCatchParamDecl(cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); + S->setCatchBody(cast_or_null<Stmt>(StmtStack.back())); + S->setCatchParamDecl(cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++]))); S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - return 2; + return 1; } unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { @@ -838,11 +898,21 @@ unsigned PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { unsigned PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { VisitStmt(S); - S->setTryBody(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 3])); - S->setCatchStmts(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 2])); - S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); + assert(Record[Idx] == S->getNumCatchStmts()); + ++Idx; + bool HasFinally = Record[Idx++]; + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + unsigned Offset = StmtStack.size() - N - HasFinally + I; + S->setCatchStmt(I, cast_or_null<ObjCAtCatchStmt>(StmtStack[Offset])); + } + + unsigned TryOffset + = StmtStack.size() - S->getNumCatchStmts() - HasFinally - 1; + S->setTryBody(cast_or_null<Stmt>(StmtStack[TryOffset])); + if (HasFinally) + S->setFinallyStmt(cast_or_null<Stmt>(StmtStack[StmtStack.size() - 1])); S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - return 3; + return 1 + S->getNumCatchStmts() + HasFinally; } unsigned PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { @@ -1079,6 +1149,12 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) UnaryOperator(Empty); break; + case pch::EXPR_OFFSETOF: + S = OffsetOfExpr::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields], + Record[PCHStmtReader::NumExprFields + 1]); + break; + case pch::EXPR_SIZEOF_ALIGN_OF: S = new (Context) SizeOfAlignOfExpr(Empty); break; @@ -1124,7 +1200,7 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { break; case pch::EXPR_INIT_LIST: - S = new (Context) InitListExpr(Empty); + S = new (Context) InitListExpr(*getContext(), Empty); break; case pch::EXPR_DESIGNATED_INIT: @@ -1195,7 +1271,8 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty); break; case pch::EXPR_OBJC_MESSAGE_EXPR: - S = new (Context) ObjCMessageExpr(Empty); + S = ObjCMessageExpr::CreateEmpty(*Context, + Record[PCHStmtReader::NumExprFields]); break; case pch::EXPR_OBJC_SUPER_EXPR: S = new (Context) ObjCSuperExpr(Empty); @@ -1213,7 +1290,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) ObjCAtFinallyStmt(Empty); break; case pch::STMT_OBJC_AT_TRY: - S = new (Context) ObjCAtTryStmt(Empty); + S = ObjCAtTryStmt::CreateEmpty(*Context, + Record[PCHStmtReader::NumStmtFields], + Record[PCHStmtReader::NumStmtFields + 1]); break; case pch::STMT_OBJC_AT_SYNCHRONIZED: S = new (Context) ObjCAtSynchronizedStmt(Empty); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 4dd8dc3..e56dd31 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1,4 +1,4 @@ -//===--- PCHWriter.h - Precompiled Headers Writer ---------------*- C++ -*-===// +//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===// // // The LLVM Compiler Infrastructure // @@ -63,6 +63,7 @@ namespace { #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" + void VisitInjectedClassNameType(const InjectedClassNameType *T); }; } @@ -240,7 +241,7 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) { void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { Writer.AddDeclRef(T->getDecl(), Record); - Writer.AddTypeRef(T->getUnderlyingType(), Record); + Writer.AddTypeRef(T->getInjectedSpecializationType(), Record); Code = pch::TYPE_INJECTED_CLASS_NAME; } @@ -745,6 +746,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) + Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. @@ -760,6 +762,7 @@ void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { // modern abi enabled. Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced // modern abi enabled. + Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings Record.push_back(LangOpts.WritableStrings); // Allow writable strings @@ -1103,7 +1106,7 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // that is required by llvm::MemoryBuffer::getMemBuffer (on // the reader side). const llvm::MemoryBuffer *Buffer - = Content->getBuffer(PP.getDiagnostics()); + = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); const char *Name = Buffer->getBufferIdentifier(); Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, llvm::StringRef(Name, strlen(Name) + 1)); @@ -2093,12 +2096,10 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddTypeRef(Context.getsigjmp_bufType(), Record); AddTypeRef(Context.ObjCIdRedefinitionType, Record); AddTypeRef(Context.ObjCClassRedefinitionType, Record); -#if 0 - // FIXME. Accommodate for this in several PCH/Indexer tests - AddTypeRef(Context.ObjCSelRedefinitionType, Record); -#endif AddTypeRef(Context.getRawBlockdescriptorType(), Record); AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); + AddTypeRef(Context.ObjCSelRedefinitionType, Record); + AddTypeRef(Context.getRawNSConstantStringType(), Record); Stream.EmitRecord(pch::SPECIAL_TYPES, Record); // Keep writing types and declarations until all types and diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 7917280..7b780623 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -176,6 +176,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Writer.AddStmt(D->getBody()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back(D->getStorageClass()); // FIXME: stable encoding + Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->isInlineSpecified()); Record.push_back(D->isVirtualAsWritten()); Record.push_back(D->isPure()); @@ -211,6 +212,7 @@ void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { Record.push_back(D->getImplementationControl()); // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway Record.push_back(D->getObjCDeclQualifier()); + Record.push_back(D->getNumSelectorArgs()); Writer.AddTypeRef(D->getResultType(), Record); Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record); @@ -359,6 +361,7 @@ void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); Writer.AddDeclRef(D->getSuperClass(), Record); + // FIXME add writing of IvarInitializers and NumIvarInitializers. Code = pch::DECL_OBJC_IMPLEMENTATION; } @@ -382,9 +385,11 @@ void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { void PCHDeclWriter::VisitVarDecl(VarDecl *D) { VisitDeclaratorDecl(D); Record.push_back(D->getStorageClass()); // FIXME: stable encoding + Record.push_back(D->getStorageClassAsWritten()); Record.push_back(D->isThreadSpecified()); Record.push_back(D->hasCXXDirectInitializer()); Record.push_back(D->isDeclaredInCondition()); + Record.push_back(D->isExceptionVariable()); Writer.AddDeclRef(D->getPreviousDeclaration(), Record); Record.push_back(D->getInit()? 1 : 0); if (D->getInit()) @@ -425,6 +430,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition"); + assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl"); assert(D->getInit() == 0 && "PARM_VAR_DECL never has init"); } @@ -493,9 +499,11 @@ void PCHWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType // VarDecl Abv->Add(BitCodeAbbrevOp(0)); // StorageClass + Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition + Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl Abv->Add(BitCodeAbbrevOp(0)); // HasInit // ParmVarDecl @@ -608,7 +616,7 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); if (!W.Code) - llvm::llvm_report_error(llvm::StringRef("unexpected declaration kind '") + + llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") + D->getDeclKindName() + "'"); Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 9a5417c..a1993d3 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -62,6 +62,7 @@ namespace { void VisitCharacterLiteral(CharacterLiteral *E); void VisitParenExpr(ParenExpr *E); void VisitUnaryOperator(UnaryOperator *E); + void VisitOffsetOfExpr(OffsetOfExpr *E); void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); void VisitArraySubscriptExpr(ArraySubscriptExpr *E); void VisitCallExpr(CallExpr *E); @@ -393,6 +394,42 @@ void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) { Code = pch::EXPR_UNARY_OPERATOR; } +void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumComponents()); + Record.push_back(E->getNumExpressions()); + Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I); + Record.push_back(ON.getKind()); // FIXME: Stable encoding + Writer.AddSourceLocation(ON.getRange().getBegin(), Record); + Writer.AddSourceLocation(ON.getRange().getEnd(), Record); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + Record.push_back(ON.getArrayExprIndex()); + break; + + case OffsetOfExpr::OffsetOfNode::Field: + Writer.AddDeclRef(ON.getField(), Record); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + Writer.AddIdentifierRef(ON.getFieldName(), Record); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // FIXME: Implement this! + llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); + break; + } + } + for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) + Writer.WriteSubStmt(E->getIndexExpr(I)); + Code = pch::EXPR_OFFSETOF; +} + void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { VisitExpr(E); Record.push_back(E->isSizeOf()); @@ -655,7 +692,7 @@ void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) { void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { VisitExpr(E); - Writer.AddTypeRef(E->getEncodedType(), Record); + Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record); Writer.AddSourceLocation(E->getAtLoc(), Record); Writer.AddSourceLocation(E->getRParenLoc(), Record); Code = pch::EXPR_OBJC_ENCODE; @@ -712,18 +749,33 @@ void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr( void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); + Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding + switch (E->getReceiverKind()) { + case ObjCMessageExpr::Instance: + Writer.WriteSubStmt(E->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record); + break; + + case ObjCMessageExpr::SuperClass: + case ObjCMessageExpr::SuperInstance: + Writer.AddTypeRef(E->getSuperType(), Record); + Writer.AddSourceLocation(E->getSuperLoc(), Record); + break; + } + + if (E->getMethodDecl()) { + Record.push_back(1); + Writer.AddDeclRef(E->getMethodDecl(), Record); + } else { + Record.push_back(0); + Writer.AddSelectorRef(E->getSelector(), Record); + } + Writer.AddSourceLocation(E->getLeftLoc(), Record); Writer.AddSourceLocation(E->getRightLoc(), Record); - Writer.AddSelectorRef(E->getSelector(), Record); - Writer.AddDeclRef(E->getMethodDecl(), Record); // optional - Writer.WriteSubStmt(E->getReceiver()); - - if (!E->getReceiver()) { - ObjCMessageExpr::ClassInfo CI = E->getClassInfo(); - Writer.AddDeclRef(CI.Decl, Record); - Writer.AddIdentifierRef(CI.Name, Record); - Writer.AddSourceLocation(CI.Loc, Record); - } for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); Arg != ArgEnd; ++Arg) @@ -749,7 +801,6 @@ void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { Writer.WriteSubStmt(S->getCatchBody()); - Writer.WriteSubStmt(S->getNextCatchStmt()); Writer.AddDeclRef(S->getCatchParamDecl(), Record); Writer.AddSourceLocation(S->getAtCatchLoc(), Record); Writer.AddSourceLocation(S->getRParenLoc(), Record); @@ -763,9 +814,13 @@ void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { } void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + Record.push_back(S->getNumCatchStmts()); + Record.push_back(S->getFinallyStmt() != 0); Writer.WriteSubStmt(S->getTryBody()); - Writer.WriteSubStmt(S->getCatchStmts()); - Writer.WriteSubStmt(S->getFinallyStmt()); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) + Writer.WriteSubStmt(S->getCatchStmt(I)); + if (S->getFinallyStmt()) + Writer.WriteSubStmt(S->getFinallyStmt()); Writer.AddSourceLocation(S->getAtTryLoc(), Record); Code = pch::STMT_OBJC_AT_TRY; } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 8d64a64..4df5c52 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -197,7 +197,7 @@ namespace { } virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -405,8 +405,8 @@ namespace { // Objective-c statements virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, - DeclPtrTy Parm, StmtArg Body, - StmtArg CatchList) { + DeclPtrTy Parm, + StmtArg Body) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); } @@ -418,7 +418,8 @@ namespace { } virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, StmtArg Catch, + StmtArg Try, + MultiStmtArg CatchStmts, StmtArg Finally) { Out << __FUNCTION__ << "\n"; return StmtEmpty(); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 02afd24..b6c18b7 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -78,6 +78,7 @@ static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, namespace { class PrintPPOutputPPCallbacks : public PPCallbacks { Preprocessor &PP; + SourceManager &SM; TokenConcatenation ConcatInfo; public: llvm::raw_ostream &OS; @@ -94,7 +95,8 @@ private: public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, bool lineMarkers, bool defines) - : PP(pp), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), + : PP(pp), SM(PP.getSourceManager()), + ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), DumpDefines(defines) { CurLine = 0; CurFilename += "<uninit>"; @@ -118,9 +120,14 @@ public: bool HandleFirstTokOnLine(Token &Tok); - bool MoveToLine(SourceLocation Loc); - bool AvoidConcat(const Token &PrevTok, const Token &Tok) { - return ConcatInfo.AvoidConcat(PrevTok, Tok); + bool MoveToLine(SourceLocation Loc) { + return MoveToLine(SM.getPresumedLoc(Loc).getLine()); + } + bool MoveToLine(unsigned LineNo); + + bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, + const Token &Tok) { + return ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok); } void WriteLineInfo(unsigned LineNo, const char *Extra=0, unsigned ExtraLen=0); @@ -166,9 +173,7 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo, /// object. We can do this by emitting some number of \n's, or be emitting a /// #line directive. This returns false if already at the specified line, true /// if some newlines were emitted. -bool PrintPPOutputPPCallbacks::MoveToLine(SourceLocation Loc) { - unsigned LineNo = PP.getSourceManager().getInstantiationLineNumber(Loc); - +bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) { if (DisableLineMarkers) { if (LineNo == CurLine) return false; @@ -211,27 +216,29 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, SrcMgr::CharacteristicKind NewFileType) { // Unless we are exiting a #include, make sure to skip ahead to the line the // #include directive was at. - SourceManager &SourceMgr = PP.getSourceManager(); + SourceManager &SourceMgr = SM; + + PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc); + unsigned NewLine = UserLoc.getLine(); + if (Reason == PPCallbacks::EnterFile) { SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc(); if (IncludeLoc.isValid()) MoveToLine(IncludeLoc); } else if (Reason == PPCallbacks::SystemHeaderPragma) { - MoveToLine(Loc); + MoveToLine(NewLine); // TODO GCC emits the # directive for this directive on the line AFTER the // directive and emits a bunch of spaces that aren't needed. Emulate this // strange behavior. } - - Loc = SourceMgr.getInstantiationLoc(Loc); - // FIXME: Should use presumed line #! - CurLine = SourceMgr.getInstantiationLineNumber(Loc); + + CurLine = NewLine; if (DisableLineMarkers) return; CurFilename.clear(); - CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename(); + CurFilename += UserLoc.getFilename(); Lexer::Stringify(CurFilename); FileType = NewFileType; @@ -318,8 +325,7 @@ bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) { // Print out space characters so that the first token on a line is // indented for easy reading. - const SourceManager &SourceMgr = PP.getSourceManager(); - unsigned ColNo = SourceMgr.getInstantiationColumnNumber(Tok.getLocation()); + unsigned ColNo = SM.getInstantiationColumnNumber(Tok.getLocation()); // This hack prevents stuff like: // #define HASH # @@ -391,6 +397,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, PrintPPOutputPPCallbacks *Callbacks, llvm::raw_ostream &OS) { char Buffer[256]; + Token PrevPrevTok; Token PrevTok; while (1) { @@ -402,7 +409,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, // useful to look at and no concatenation could happen anyway. (Callbacks->hasEmittedTokensOnThisLine() && // Don't print "-" next to "-", it would form "--". - Callbacks->AvoidConcat(PrevTok, Tok))) { + Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) { OS << ' '; } @@ -433,6 +440,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, if (Tok.is(tok::eof)) break; + PrevPrevTok = PrevTok; PrevTok = Tok; PP.Lex(Tok); } @@ -448,8 +456,7 @@ static int MacroIDCompare(const void* a, const void* b) { static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { // -dM mode just scans and ignores all tokens in the files, then dumps out // the macro table at the end. - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); Token Tok; do PP.Lex(Tok); @@ -484,8 +491,6 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, // to -C or -CC. PP.SetCommentRetentionState(Opts.ShowComments, Opts.ShowMacroComments); - OS->SetBufferSize(64*1024); - PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, Opts.ShowMacros); @@ -496,8 +501,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, PP.addPPCallbacks(Callbacks); // After we have configured the preprocessor, enter the main file. - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); // Consume all of the tokens that come from the predefines buffer. Those // should not be emitted into the output and are guaranteed to be at the diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index 4ffb297..954e8e2 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -101,8 +101,7 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { // Get the first preprocessing token. - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); Token PPTok; PP.Lex(PPTok); diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index cba9298..1169832 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -444,7 +444,7 @@ namespace { CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, CastExpr::CastKind Kind, Expr *E) { TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo, + return new (Ctx) CStyleCastExpr(Ty, Kind, E, CXXBaseSpecifierArray(), TInfo, SourceLocation(), SourceLocation()); } } @@ -640,7 +640,9 @@ void RewriteObjC::Initialize(ASTContext &context) { if (LangOpts.Microsoft) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; + Preamble += "#ifndef KEEP_ATTRIBUTES\n"; // We use this for clang tests. Preamble += "#define __attribute__(X)\n"; + Preamble += "#endif\n"; Preamble += "#define __weak\n"; } else { @@ -1237,11 +1239,26 @@ Stmt *RewriteObjC::RewritePropertySetter(BinaryOperator *BinOp, Expr *newStmt, // This allows us to handle chain/nested property getters. Receiver = PropGetters[PRE]; } - MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver), - PDecl->getSetterName(), PDecl->getType(), - PDecl->getSetterMethodDecl(), - SourceLocation(), SourceLocation(), - &ExprVec[0], 1); + if (isa<ObjCSuperExpr>(Receiver)) + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME?*/SourceLocation(), + Receiver->getLocStart(), + /*IsInstanceSuper=*/true, + cast<Expr>(Receiver)->getType(), + PDecl->getSetterName(), + PDecl->getSetterMethodDecl(), + &ExprVec[0], 1, + /*FIXME:*/SourceLocation()); + else + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME: */SourceLocation(), + cast<Expr>(Receiver), + PDecl->getSetterName(), + PDecl->getSetterMethodDecl(), + &ExprVec[0], 1, + /*FIXME:*/SourceLocation()); Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); // Now do the actual rewrite. @@ -1266,11 +1283,27 @@ Stmt *RewriteObjC::RewritePropertyGetter(ObjCPropertyRefExpr *PropRefExpr) { // This allows us to handle chain/nested property getters. Receiver = PropGetters[PRE]; } - MsgExpr = new (Context) ObjCMessageExpr(*Context, dyn_cast<Expr>(Receiver), - PDecl->getGetterName(), PDecl->getType(), - PDecl->getGetterMethodDecl(), - SourceLocation(), SourceLocation(), - 0, 0); + + if (isa<ObjCSuperExpr>(Receiver)) + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME:*/SourceLocation(), + Receiver->getLocStart(), + /*IsInstanceSuper=*/true, + cast<Expr>(Receiver)->getType(), + PDecl->getGetterName(), + PDecl->getGetterMethodDecl(), + 0, 0, + /*FIXME:*/SourceLocation()); + else + MsgExpr = ObjCMessageExpr::Create(*Context, + PDecl->getType().getNonReferenceType(), + /*FIXME:*/SourceLocation(), + cast<Expr>(Receiver), + PDecl->getGetterName(), + PDecl->getGetterMethodDecl(), + 0, 0, + /*FIXME:*/SourceLocation()); Stmt *ReplacingStmt = SynthMessageExpr(MsgExpr); @@ -1828,8 +1861,7 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { assert((*startBuf == '}') && "bogus @try block"); SourceLocation lastCurlyLoc = startLoc; - ObjCAtCatchStmt *catchList = S->getCatchStmts(); - if (catchList) { + if (S->getNumCatchStmts()) { startLoc = startLoc.getFileLocWithOffset(1); buf = " /* @catch begin */ else {\n"; buf += " id _caught = objc_exception_extract(&_stack);\n"; @@ -1847,26 +1879,27 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { } bool sawIdTypedCatch = false; Stmt *lastCatchBody = 0; - while (catchList) { - ParmVarDecl *catchDecl = catchList->getCatchParamDecl(); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *Catch = S->getCatchStmt(I); + VarDecl *catchDecl = Catch->getCatchParamDecl(); - if (catchList == S->getCatchStmts()) + if (I == 0) buf = "if ("; // we are generating code for the first catch clause else buf = "else if ("; - startLoc = catchList->getLocStart(); + startLoc = Catch->getLocStart(); startBuf = SM->getCharacterData(startLoc); assert((*startBuf == '@') && "bogus @catch location"); const char *lParenLoc = strchr(startBuf, '('); - if (catchList->hasEllipsis()) { + if (Catch->hasEllipsis()) { // Now rewrite the body... - lastCatchBody = catchList->getCatchBody(); + lastCatchBody = Catch->getCatchBody(); SourceLocation bodyLoc = lastCatchBody->getLocStart(); const char *bodyBuf = SM->getCharacterData(bodyLoc); - assert(*SM->getCharacterData(catchList->getRParenLoc()) == ')' && + assert(*SM->getCharacterData(Catch->getRParenLoc()) == ')' && "bogus @catch paren location"); assert((*bodyBuf == '{') && "bogus @catch body location"); @@ -1890,8 +1923,8 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { } } // Now rewrite the body... - lastCatchBody = catchList->getCatchBody(); - SourceLocation rParenLoc = catchList->getRParenLoc(); + lastCatchBody = Catch->getCatchBody(); + SourceLocation rParenLoc = Catch->getRParenLoc(); SourceLocation bodyLoc = lastCatchBody->getLocStart(); const char *bodyBuf = SM->getCharacterData(bodyLoc); const char *rParenBuf = SM->getCharacterData(rParenLoc); @@ -1904,8 +1937,6 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { } else { assert(false && "@catch rewrite bug"); } - // make sure all the catch bodies get rewritten! - catchList = catchList->getNextCatchStmt(); } // Complete the catch list... if (lastCatchBody) { @@ -2054,10 +2085,10 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( // Now, we cast the reference to a pointer to the objc_msgSend type. QualType pToFunc = Context->getPointerType(msgSendType); - ImplicitCastExpr *ICE = new (Context) ImplicitCastExpr(pToFunc, - CastExpr::CK_Unknown, - DRE, - /*isLvalue=*/false); + ImplicitCastExpr *ICE = + new (Context) ImplicitCastExpr(pToFunc, CastExpr::CK_Unknown, + DRE, CXXBaseSpecifierArray(), + /*isLvalue=*/false); const FunctionType *FT = msgSendType->getAs<FunctionType>(); @@ -2267,7 +2298,8 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() { SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SelGetUidIdent, getFuncType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { @@ -2364,7 +2396,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); @@ -2385,7 +2418,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); @@ -2409,7 +2443,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); @@ -2430,7 +2465,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthMsgSendSuperStretFunctionDecl - @@ -2456,7 +2492,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); @@ -2477,7 +2514,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthGetClassFunctionDecl - id objc_getClass(const char *name); @@ -2493,7 +2531,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() { GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } // SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); @@ -2508,9 +2547,12 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { false, false, 0, 0, FunctionType::ExtInfo()); GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, - SourceLocation(), - getSuperClassIdent, getClassType, 0, - FunctionDecl::Extern, false); + SourceLocation(), + getSuperClassIdent, + getClassType, 0, + FunctionDecl::Extern, + FunctionDecl::None, + false); } // SynthGetMetaClassFunctionDecl - id objc_getClass(const char *name); @@ -2526,7 +2568,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() { GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, - FunctionDecl::Extern, false); + FunctionDecl::Extern, + FunctionDecl::None, false); } Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { @@ -2560,7 +2603,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(S), strType, 0, - VarDecl::Static); + VarDecl::Static, VarDecl::None); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation()); Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, Context->getPointerType(DRE->getType()), @@ -2665,7 +2708,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, FunctionDecl *MsgSendStretFlavor = 0; if (ObjCMethodDecl *mDecl = Exp->getMethodDecl()) { QualType resultType = mDecl->getResultType(); - if (resultType->isStructureType() || resultType->isUnionType()) + if (resultType->isRecordType()) MsgSendStretFlavor = MsgSendStretFunctionDecl; else if (resultType->isRealFloatingType()) MsgSendFlavor = MsgSendFpretFunctionDecl; @@ -2673,203 +2716,211 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // Synthesize a call to objc_msgSend(). llvm::SmallVector<Expr*, 8> MsgExprs; - IdentifierInfo *clsName = Exp->getClassName(); - - // Derive/push the receiver/selector, 2 implicit arguments to objc_msgSend(). - if (clsName) { // class message. - // FIXME: We need to fix Sema (and the AST for ObjCMessageExpr) to handle - // the 'super' idiom within a class method. - if (clsName->getName() == "super") { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - - llvm::SmallVector<Expr*, 4> InitExprs; - - // set the receiver to self, the first argument to all methods. - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - Context->getObjCIdType(), - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getNameStart(), - ClassDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, - EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CastExpr::CK_Unknown, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, - Context->getObjCIdType(), - CastExpr::CK_Unknown, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.Microsoft) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - superType, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - superType, SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, - Context->getPointerType(SuperRep->getType()), - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, ILE, false); - // struct objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, - Context->getPointerType(SuperRep->getType()), - SourceLocation()); - } - MsgExprs.push_back(SuperRep); + switch (Exp->getReceiverKind()) { + case ObjCMessageExpr::SuperClass: { + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + + llvm::SmallVector<Expr*, 4> InitExprs; + + // set the receiver to self, the first argument to all methods. + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + Context->getObjCIdType(), + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, + EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.Microsoft) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + superType, SourceLocation()); + SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], + InitExprs.size(), + superType, SourceLocation()); + // The code for super is a little tricky to prevent collision with + // the structure definition in the header. The rewriter has it's own + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); } else { - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - clsName->getNameStart(), - clsName->getLength(), - false, argType, - SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - MsgExprs.push_back(Cls); + // (struct objc_super) { <exprs from above> } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), + &InitExprs[0], InitExprs.size(), + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); + // struct objc_super * + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); } - } else { // instance message. - Expr *recExpr = Exp->getReceiver(); - - if (isSuperReceiver(recExpr)) { - MsgSendFlavor = MsgSendSuperFunctionDecl; - if (MsgSendStretFlavor) - MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; - assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); - ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); - llvm::SmallVector<Expr*, 4> InitExprs; - - InitExprs.push_back( - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, - new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), - Context->getObjCIdType(), - SourceLocation())) - ); // set the 'receiver'. - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - llvm::SmallVector<Expr*, 8> ClsExprs; - QualType argType = Context->getPointerType(Context->CharTy); - ClsExprs.push_back(StringLiteral::Create(*Context, - ClassDecl->getIdentifier()->getNameStart(), - ClassDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); - CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, - &ClsExprs[0], - ClsExprs.size(), - StartLoc, EndLoc); - // (Class)objc_getClass("CurrentClass") - CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, - Context->getObjCClassType(), - CastExpr::CK_Unknown, Cls); - ClsExprs.clear(); - ClsExprs.push_back(ArgExpr); - Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, - &ClsExprs[0], ClsExprs.size(), - StartLoc, EndLoc); - - // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) - // To turn off a warning, type-cast to 'id' - InitExprs.push_back( - // set 'super class', using class_getSuperclass(). - NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, Cls)); - // struct objc_super - QualType superType = getSuperStructType(); - Expr *SuperRep; - - if (LangOpts.Microsoft) { - SynthSuperContructorFunctionDecl(); - // Simulate a contructor call... - DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, - superType, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), - superType, SourceLocation()); - // The code for super is a little tricky to prevent collision with - // the structure definition in the header. The rewriter has it's own - // internal definition (__rw_objc_super) that is uses. This is why - // we need the cast below. For example: - // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) - // - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, - Context->getPointerType(SuperRep->getType()), - SourceLocation()); - SuperRep = NoTypeInfoCStyleCastExpr(Context, - Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep); - } else { - // (struct objc_super) { <exprs from above> } - InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(), - &InitExprs[0], InitExprs.size(), - SourceLocation()); - TypeSourceInfo *superTInfo - = Context->getTrivialTypeSourceInfo(superType); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, - superType, ILE, false); - } - MsgExprs.push_back(SuperRep); + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Class: { + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ObjCInterfaceDecl *Class + = Exp->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + IdentifierInfo *clsName = Class->getIdentifier(); + ClsExprs.push_back(StringLiteral::Create(*Context, + clsName->getNameStart(), + clsName->getLength(), + false, argType, + SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + MsgExprs.push_back(Cls); + break; + } + + case ObjCMessageExpr::SuperInstance:{ + MsgSendFlavor = MsgSendSuperFunctionDecl; + if (MsgSendStretFlavor) + MsgSendStretFlavor = MsgSendSuperStretFunctionDecl; + assert(MsgSendFlavor && "MsgSendFlavor is NULL!"); + ObjCInterfaceDecl *ClassDecl = CurMethodDef->getClassInterface(); + llvm::SmallVector<Expr*, 4> InitExprs; + + InitExprs.push_back( + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), + Context->getObjCIdType(), + SourceLocation())) + ); // set the 'receiver'. + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + llvm::SmallVector<Expr*, 8> ClsExprs; + QualType argType = Context->getPointerType(Context->CharTy); + ClsExprs.push_back(StringLiteral::Create(*Context, + ClassDecl->getIdentifier()->getNameStart(), + ClassDecl->getIdentifier()->getLength(), + false, argType, SourceLocation())); + CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, + &ClsExprs[0], + ClsExprs.size(), + StartLoc, EndLoc); + // (Class)objc_getClass("CurrentClass") + CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, + Context->getObjCClassType(), + CastExpr::CK_Unknown, Cls); + ClsExprs.clear(); + ClsExprs.push_back(ArgExpr); + Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, + &ClsExprs[0], ClsExprs.size(), + StartLoc, EndLoc); + + // (id)class_getSuperclass((Class)objc_getClass("CurrentClass")) + // To turn off a warning, type-cast to 'id' + InitExprs.push_back( + // set 'super class', using class_getSuperclass(). + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); + // struct objc_super + QualType superType = getSuperStructType(); + Expr *SuperRep; + + if (LangOpts.Microsoft) { + SynthSuperContructorFunctionDecl(); + // Simulate a contructor call... + DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, + superType, SourceLocation()); + SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], + InitExprs.size(), + superType, SourceLocation()); + // The code for super is a little tricky to prevent collision with + // the structure definition in the header. The rewriter has it's own + // internal definition (__rw_objc_super) that is uses. This is why + // we need the cast below. For example: + // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) + // + SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + Context->getPointerType(SuperRep->getType()), + SourceLocation()); + SuperRep = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(superType), + CastExpr::CK_Unknown, SuperRep); } else { - // Remove all type-casts because it may contain objc-style types; e.g. - // Foo<Proto> *. - while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) - recExpr = CE->getSubExpr(); - recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, recExpr); - MsgExprs.push_back(recExpr); + // (struct objc_super) { <exprs from above> } + InitListExpr *ILE = + new (Context) InitListExpr(*Context, SourceLocation(), + &InitExprs[0], InitExprs.size(), + SourceLocation()); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); } + MsgExprs.push_back(SuperRep); + break; + } + + case ObjCMessageExpr::Instance: { + // Remove all type-casts because it may contain objc-style types; e.g. + // Foo<Proto> *. + Expr *recExpr = Exp->getInstanceReceiver(); + while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) + recExpr = CE->getSubExpr(); + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, recExpr); + MsgExprs.push_back(recExpr); + break; } + } + // Create a call to sel_registerName("selName"), it will be the 2nd argument. llvm::SmallVector<Expr*, 8> SelExprs; QualType argType = Context->getPointerType(Context->CharTy); @@ -3070,7 +3121,8 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - ID, getProtocolType(), 0, VarDecl::Extern); + ID, getProtocolType(), 0, + VarDecl::Extern, VarDecl::None); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation()); Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, Context->getPointerType(DRE->getType()), @@ -5066,8 +5118,8 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) { IdentifierInfo *ID = &Context->Idents.get(name); QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); return FunctionDecl::Create(*Context, TUDecl,SourceLocation(), - ID, FType, 0, FunctionDecl::Extern, false, - false); + ID, FType, 0, FunctionDecl::Extern, + FunctionDecl::None, false, false); } Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, @@ -5147,7 +5199,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(DescData.c_str()), Context->VoidPtrTy, 0, - VarDecl::Static); + VarDecl::Static, VarDecl::None); UnaryOperator *DescRefExpr = new (Context) UnaryOperator( new (Context) DeclRefExpr(NewVD, Context->VoidPtrTy, SourceLocation()), diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index ce474d3..21dc0ba 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -125,6 +125,7 @@ namespace { void VisitFloatingLiteral(FloatingLiteral *Node); void VisitStringLiteral(StringLiteral *Str); void VisitUnaryOperator(UnaryOperator *Node); + void VisitOffsetOfExpr(OffsetOfExpr *Node); void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); void VisitMemberExpr(MemberExpr *Node); void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); @@ -308,6 +309,10 @@ void StmtXML::VisitUnaryOperator(UnaryOperator *Node) { Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); } +void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) { + DumpExpr(Node); +} + void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { DumpExpr(Node); Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof"); diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 4e91f8d..28bb17a 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -148,9 +148,16 @@ static void SelectInterestingSourceRegion(std::string &SourceLine, std::string &FixItInsertionLine, unsigned EndOfCaretToken, unsigned Columns) { - if (CaretLine.size() > SourceLine.size()) - SourceLine.resize(CaretLine.size(), ' '); - + unsigned MaxSize = std::max(SourceLine.size(), + std::max(CaretLine.size(), + FixItInsertionLine.size())); + if (MaxSize > SourceLine.size()) + SourceLine.resize(MaxSize, ' '); + if (MaxSize > CaretLine.size()) + CaretLine.resize(MaxSize, ' '); + if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size()) + FixItInsertionLine.resize(MaxSize, ' '); + // Find the slice that we need to display the full caret line // correctly. unsigned CaretStart = 0, CaretEnd = CaretLine.size(); @@ -275,7 +282,7 @@ static void SelectInterestingSourceRegion(std::string &SourceLine, void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceRange *Ranges, unsigned NumRanges, - SourceManager &SM, + const SourceManager &SM, const FixItHint *Hints, unsigned NumHints, unsigned Columns) { @@ -796,8 +803,13 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, OutStr += " [-W"; OutStr += Opt; OutStr += ']'; - } else if (Diagnostic::isBuiltinExtensionDiag(Info.getID())) { - OutStr += " [-pedantic]"; + } else { + // If the diagnostic is an extension diagnostic and not enabled by default + // then it must have been turned on with -pedantic. + bool EnabledByDefault; + if (Diagnostic::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && + !EnabledByDefault) + OutStr += " [-pedantic]"; } } diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp index 99ec910..ae36481 100644 --- a/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -16,6 +16,7 @@ #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -71,97 +72,267 @@ bool VerifyDiagnosticsClient::HadErrors() { typedef TextDiagnosticBuffer::DiagList DiagList; typedef TextDiagnosticBuffer::const_iterator const_diag_iterator; -/// FindDiagnostics - Go through the comment and see if it indicates expected -/// diagnostics. If so, then put them in a diagnostic list. +namespace { + +/// Directive - Abstract class representing a parsed verify directive. /// -static void FindDiagnostics(const char *CommentStart, unsigned CommentLen, - DiagList &ExpectedDiags, - Preprocessor &PP, SourceLocation Pos, - const char *ExpectedStr) { - const char *CommentEnd = CommentStart+CommentLen; - unsigned ExpectedStrLen = strlen(ExpectedStr); - - // Find all expected-foo diagnostics in the string and add them to - // ExpectedDiags. - while (CommentStart != CommentEnd) { - CommentStart = std::find(CommentStart, CommentEnd, 'e'); - if (unsigned(CommentEnd-CommentStart) < ExpectedStrLen) return; - - // If this isn't expected-foo, ignore it. - if (memcmp(CommentStart, ExpectedStr, ExpectedStrLen)) { - ++CommentStart; - continue; - } +class Directive { +public: + static Directive* Create(bool RegexKind, const SourceLocation &Location, + const std::string &Text, unsigned Count); +public: + SourceLocation Location; + const std::string Text; + unsigned Count; + + virtual ~Directive() { } + + // Returns true if directive text is valid. + // Otherwise returns false and populates E. + virtual bool isValid(std::string &Error) = 0; + + // Returns true on match. + virtual bool Match(const std::string &S) = 0; + +protected: + Directive(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Location(Location), Text(Text), Count(Count) { } + +private: + Directive(const Directive&); // DO NOT IMPLEMENT + void operator=(const Directive&); // DO NOT IMPLEMENT +}; + +/// StandardDirective - Directive with string matching. +/// +class StandardDirective : public Directive { +public: + StandardDirective(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Directive(Location, Text, Count) { } + + virtual bool isValid(std::string &Error) { + // all strings are considered valid; even empty ones + return true; + } + + virtual bool Match(const std::string &S) { + return S.find(Text) != std::string::npos || + Text.find(S) != std::string::npos; + } +}; + +/// RegexDirective - Directive with regular-expression matching. +/// +class RegexDirective : public Directive { +public: + RegexDirective(const SourceLocation &Location, const std::string &Text, + unsigned Count) + : Directive(Location, Text, Count), Regex(Text) { } + + virtual bool isValid(std::string &Error) { + if (Regex.isValid(Error)) + return true; + return false; + } + + virtual bool Match(const std::string &S) { + return Regex.match(S); + } - CommentStart += ExpectedStrLen; - - // Skip whitespace. - while (CommentStart != CommentEnd && - isspace(CommentStart[0])) - ++CommentStart; - - // Default, if we find the '{' now, is 1 time. - int Times = 1; - int Temp = 0; - // In extended syntax, there could be a digit now. - while (CommentStart != CommentEnd && - CommentStart[0] >= '0' && CommentStart[0] <= '9') { - Temp *= 10; - Temp += CommentStart[0] - '0'; - ++CommentStart; +private: + llvm::Regex Regex; +}; + +typedef std::vector<Directive*> DirectiveList; + +/// ExpectedData - owns directive objects and deletes on destructor. +/// +struct ExpectedData { + DirectiveList Errors; + DirectiveList Warnings; + DirectiveList Notes; + + ~ExpectedData() { + DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; + for (DirectiveList **PL = Lists; *PL; ++PL) { + DirectiveList * const L = *PL; + for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) + delete *I; } - if (Temp > 0) - Times = Temp; - - // Skip whitespace again. - while (CommentStart != CommentEnd && - isspace(CommentStart[0])) - ++CommentStart; - - // We should have a {{ now. - if (CommentEnd-CommentStart < 2 || - CommentStart[0] != '{' || CommentStart[1] != '{') { - if (std::find(CommentStart, CommentEnd, '{') != CommentEnd) - PP.Diag(Pos, diag::err_verify_bogus_characters); - else - PP.Diag(Pos, diag::err_verify_missing_start); - return; + } +}; + +class ParseHelper +{ +public: + ParseHelper(const char *Begin, const char *End) + : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } + + // Return true if string literal is next. + bool Next(const std::string &S) { + std::string::size_type LEN = S.length(); + P = C; + PEnd = C + LEN; + if (PEnd > End) + return false; + return !memcmp(P, S.c_str(), LEN); + } + + // Return true if number is next. + // Output N only if number is next. + bool Next(unsigned &N) { + unsigned TMP = 0; + P = C; + for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) { + TMP *= 10; + TMP += P[0] - '0'; } - CommentStart += 2; - - // Find the }}. - const char *ExpectedEnd = CommentStart; - while (1) { - ExpectedEnd = std::find(ExpectedEnd, CommentEnd, '}'); - if (CommentEnd-ExpectedEnd < 2) { - PP.Diag(Pos, diag::err_verify_missing_end); - return; - } + if (P == C) + return false; + PEnd = P; + N = TMP; + return true; + } + + // Return true if string literal is found. + // When true, P marks begin-position of S in content. + bool Search(const std::string &S) { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.length(); + return P != End; + } + + // Advance 1-past previous next/search. + // Behavior is undefined if previous next/search failed. + bool Advance() { + C = PEnd; + return C < End; + } + + // Skip zero or more whitespace. + void SkipWhitespace() { + for (; C < End && isspace(*C); ++C) + ; + } + + // Return true if EOF reached. + bool Done() { + return !(C < End); + } + + const char * const Begin; // beginning of expected content + const char * const End; // end of expected content (1-past) + const char *C; // position of next char in content + const char *P; + +private: + const char *PEnd; // previous next/search subject end (1-past) +}; + +} // namespace anonymous + +/// ParseDirective - Go through the comment and see if it indicates expected +/// diagnostics. If so, then put them in the appropriate directive list. +/// +static void ParseDirective(const char *CommentStart, unsigned CommentLen, + ExpectedData &ED, Preprocessor &PP, + SourceLocation Pos) { + // A single comment may contain multiple directives. + for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { + // search for token: expected + if (!PH.Search("expected")) + break; + PH.Advance(); + + // next token: - + if (!PH.Next("-")) + continue; + PH.Advance(); + + // next token: { error | warning | note } + DirectiveList* DL = NULL; + if (PH.Next("error")) + DL = &ED.Errors; + else if (PH.Next("warning")) + DL = &ED.Warnings; + else if (PH.Next("note")) + DL = &ED.Notes; + else + continue; + PH.Advance(); - if (ExpectedEnd[1] == '}') - break; + // default directive kind + bool RegexKind = false; + const char* KindStr = "string"; - ++ExpectedEnd; // Skip over singular }'s + // next optional token: - + if (PH.Next("-re")) { + PH.Advance(); + RegexKind = true; + KindStr = "regex"; } - std::string Msg(CommentStart, ExpectedEnd); - std::string::size_type FindPos; - while ((FindPos = Msg.find("\\n")) != std::string::npos) - Msg.replace(FindPos, 2, "\n"); - // Add is possibly multiple times. - for (int i = 0; i < Times; ++i) - ExpectedDiags.push_back(std::make_pair(Pos, Msg)); + // skip optional whitespace + PH.SkipWhitespace(); + + // next optional token: positive integer + unsigned Count = 1; + if (PH.Next(Count)) + PH.Advance(); + + // skip optional whitespace + PH.SkipWhitespace(); + + // next token: {{ + if (!PH.Next("{{")) { + PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_start) << KindStr; + continue; + } + PH.Advance(); + const char* const ContentBegin = PH.C; // mark content begin - CommentStart = ExpectedEnd; + // search for token: }} + if (!PH.Search("}}")) { + PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin), + diag::err_verify_missing_end) << KindStr; + continue; + } + const char* const ContentEnd = PH.P; // mark content end + PH.Advance(); + + // build directive text; convert \n to newlines + std::string Text; + llvm::StringRef NewlineStr = "\\n"; + llvm::StringRef Content(ContentBegin, ContentEnd-ContentBegin); + size_t CPos = 0; + size_t FPos; + while ((FPos = Content.find(NewlineStr, CPos)) != llvm::StringRef::npos) { + Text += Content.substr(CPos, FPos-CPos); + Text += '\n'; + CPos = FPos + NewlineStr.size(); + } + if (Text.empty()) + Text.assign(ContentBegin, ContentEnd); + + // construct new directive + Directive *D = Directive::Create(RegexKind, Pos, Text, Count); + std::string Error; + if (D->isValid(Error)) + DL->push_back(D); + else { + PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin), + diag::err_verify_invalid_content) + << KindStr << Error; + } } } /// FindExpectedDiags - Lex the main source file to find all of the // expected errors and warnings. -static void FindExpectedDiags(Preprocessor &PP, - DiagList &ExpectedErrors, - DiagList &ExpectedWarnings, - DiagList &ExpectedNotes) { +static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { // Create a raw lexer to pull all the comments out of the main file. We don't // want to look in #include'd headers for expected-error strings. SourceManager &SM = PP.getSourceManager(); @@ -185,17 +356,8 @@ static void FindExpectedDiags(Preprocessor &PP, std::string Comment = PP.getSpelling(Tok); if (Comment.empty()) continue; - // Find all expected errors. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, - Tok.getLocation(), "expected-error"); - - // Find all expected warnings. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, - Tok.getLocation(), "expected-warning"); - - // Find all expected notes. - FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, - Tok.getLocation(), "expected-note"); + // Find all expected errors/warnings/notes. + ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); }; } @@ -225,49 +387,68 @@ static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, return std::distance(diag_begin, diag_end); } -/// CompareDiagLists - Compare two diagnostic lists and return the difference -/// between them. +static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr, + DirectiveList &DL, const char *Kind, + bool Expected) { + if (DL.empty()) + return 0; + + llvm::SmallString<256> Fmt; + llvm::raw_svector_ostream OS(Fmt); + for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { + Directive& D = **I; + if (D.Location.isInvalid() || !SourceMgr) + OS << "\n (frontend)"; + else + OS << "\n Line " << SourceMgr->getInstantiationLineNumber(D.Location); + OS << ": " << D.Text; + } + + Diags.Report(diag::err_verify_inconsistent_diags) + << Kind << !Expected << OS.str(); + return DL.size(); +} + +/// CheckLists - Compare expected to seen diagnostic lists and return the +/// the difference between them. /// -static unsigned CompareDiagLists(Diagnostic &Diags, - SourceManager &SourceMgr, - const_diag_iterator d1_begin, - const_diag_iterator d1_end, - const_diag_iterator d2_begin, - const_diag_iterator d2_end, - const char *Label) { - DiagList LeftOnly; - DiagList Left(d1_begin, d1_end); +static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr, + const char *Label, + DirectiveList &Left, + const_diag_iterator d2_begin, + const_diag_iterator d2_end) { + DirectiveList LeftOnly; DiagList Right(d2_begin, d2_end); - for (const_diag_iterator I = Left.begin(), E = Left.end(); I != E; ++I) { - unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(I->first); - const std::string &Diag1 = I->second; + for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { + Directive& D = **I; + unsigned LineNo1 = SourceMgr.getInstantiationLineNumber(D.Location); - DiagList::iterator II, IE; - for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { - unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); - if (LineNo1 != LineNo2) continue; + for (unsigned i = 0; i < D.Count; ++i) { + DiagList::iterator II, IE; + for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { + unsigned LineNo2 = SourceMgr.getInstantiationLineNumber(II->first); + if (LineNo1 != LineNo2) + continue; - const std::string &Diag2 = II->second; - if (Diag2.find(Diag1) != std::string::npos || - Diag1.find(Diag2) != std::string::npos) { - break; + const std::string &RightText = II->second; + if (D.Match(RightText)) + break; + } + if (II == IE) { + // Not found. + LeftOnly.push_back(*I); + } else { + // Found. The same cannot be found twice. + Right.erase(II); } - } - if (II == IE) { - // Not found. - LeftOnly.push_back(*I); - } else { - // Found. The same cannot be found twice. - Right.erase(II); } } // Now all that's left in Right are those that were not matched. - return (PrintProblem(Diags, &SourceMgr, - LeftOnly.begin(), LeftOnly.end(), Label, true) + - PrintProblem(Diags, &SourceMgr, - Right.begin(), Right.end(), Label, false)); + return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) + + PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), + Label, false)); } /// CheckResults - This compares the expected results to those that @@ -276,9 +457,7 @@ static unsigned CompareDiagLists(Diagnostic &Diags, /// static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, - const DiagList &ExpectedErrors, - const DiagList &ExpectedWarnings, - const DiagList &ExpectedNotes) { + ExpectedData &ED) { // We want to capture the delta between what was expected and what was // seen. // @@ -287,31 +466,22 @@ static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr, unsigned NumProblems = 0; // See if there are error mismatches. - NumProblems += CompareDiagLists(Diags, SourceMgr, - ExpectedErrors.begin(), ExpectedErrors.end(), - Buffer.err_begin(), Buffer.err_end(), - "error"); + NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors, + Buffer.err_begin(), Buffer.err_end()); // See if there are warning mismatches. - NumProblems += CompareDiagLists(Diags, SourceMgr, - ExpectedWarnings.begin(), - ExpectedWarnings.end(), - Buffer.warn_begin(), Buffer.warn_end(), - "warning"); + NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings, + Buffer.warn_begin(), Buffer.warn_end()); // See if there are note mismatches. - NumProblems += CompareDiagLists(Diags, SourceMgr, - ExpectedNotes.begin(), - ExpectedNotes.end(), - Buffer.note_begin(), Buffer.note_end(), - "note"); + NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes, + Buffer.note_begin(), Buffer.note_end()); return NumProblems; } - void VerifyDiagnosticsClient::CheckDiagnostics() { - DiagList ExpectedErrors, ExpectedWarnings, ExpectedNotes; + ExpectedData ED; // Ensure any diagnostics go to the primary client. DiagnosticClient *CurClient = Diags.getClient(); @@ -320,13 +490,11 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { // If we have a preprocessor, scan the source for expected diagnostic // markers. If not then any diagnostics are unexpected. if (CurrentPreprocessor) { - FindExpectedDiags(*CurrentPreprocessor, ExpectedErrors, ExpectedWarnings, - ExpectedNotes); + FindExpectedDiags(*CurrentPreprocessor, ED); // Check that the expected diagnostics occurred. NumErrors += CheckResults(Diags, CurrentPreprocessor->getSourceManager(), - *Buffer, - ExpectedErrors, ExpectedWarnings, ExpectedNotes); + *Buffer, ED); } else { NumErrors += (PrintProblem(Diags, 0, Buffer->err_begin(), Buffer->err_end(), @@ -344,3 +512,10 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { // Reset the buffer, we have processed all the diagnostics in it. Buffer.reset(new TextDiagnosticBuffer()); } + +Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, + const std::string &Text, unsigned Count) { + if (RegexKind) + return new RegexDirective(Location, Text, Count); + return new StandardDirective(Location, Text, Count); +} diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index ea9635e..84c4f5d 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -35,6 +35,12 @@ void clang::ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); + + // Handle -ferror-limit + if (Opts.ErrorLimit) + Diags.setErrorLimit(Opts.ErrorLimit); + if (Opts.TemplateBacktraceLimit) + Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit); // If -pedantic or -pedantic-errors was specified, then we want to map all // extension diagnostics onto WARNING or ERROR unless the user has futz'd diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index e63291b..047fdb3 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -1,4 +1,6 @@ set(files + altivec.h + arm_neon.h emmintrin.h float.h iso646.h diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h new file mode 100644 index 0000000..1cd0db8 --- /dev/null +++ b/lib/Headers/altivec.h @@ -0,0 +1,1483 @@ +/*===---- altivec.h - Standard header for type generic math ---------------===*\ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * +\*===----------------------------------------------------------------------===*/ + +#ifndef __ALTIVEC_H +#define __ALTIVEC_H + +#ifndef __ALTIVEC__ +#error "AltiVec support not enabled" +#endif + +/* constants for mapping CR6 bits to predicate result. */ + +#define __CR6_EQ 0 +#define __CR6_EQ_REV 1 +#define __CR6_LT 2 +#define __CR6_LT_REV 3 + +#define _ATTRS_o_ai __attribute__((__overloadable__, __always_inline__)) + +/* vec_abs */ + +#define __builtin_vec_abs vec_abs +#define __builtin_altivec_abs_v16qi vec_abs +#define __builtin_altivec_abs_v8hi vec_abs +#define __builtin_altivec_abs_v4si vec_abs + +static vector signed char _ATTRS_o_ai +vec_abs(vector signed char a) +{ + return __builtin_altivec_vmaxsb(a, -a); +} + +static vector signed short _ATTRS_o_ai +vec_abs(vector signed short a) +{ + return __builtin_altivec_vmaxsh(a, -a); +} + +static vector signed int _ATTRS_o_ai +vec_abs(vector signed int a) +{ + return __builtin_altivec_vmaxsw(a, -a); +} + +static vector float _ATTRS_o_ai +vec_abs(vector float a) +{ + vector unsigned int res = (vector unsigned int)a & + (vector unsigned int)(0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF); + return (vector float)res; +} + +/* vec_abss */ + +#define __builtin_vec_abss vec_abss +#define __builtin_altivec_abss_v16qi vec_abss +#define __builtin_altivec_abss_v8hi vec_abss +#define __builtin_altivec_abss_v4si vec_abss + +static vector signed char _ATTRS_o_ai +vec_abss(vector signed char a) +{ + return __builtin_altivec_vmaxsb(a, __builtin_altivec_vsubsbs( + (vector signed char)(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), a)); +} + +static vector signed short _ATTRS_o_ai +vec_abss(vector signed short a) +{ + return __builtin_altivec_vmaxsh(a, __builtin_altivec_vsubshs( + (vector signed short)(0, 0, 0, 0, 0, 0, 0, 0), a)); +} + +static vector signed int _ATTRS_o_ai +vec_abss(vector signed int a) +{ + return __builtin_altivec_vmaxsw(a, __builtin_altivec_vsubsws( + (vector signed int)(0, 0, 0, 0), a)); +} + +/* vec_add */ + +#define __builtin_altivec_vaddubm vec_add +#define __builtin_altivec_vadduhm vec_add +#define __builtin_altivec_vadduwm vec_add +#define __builtin_altivec_vaddfp vec_add +#define __builtin_vec_vaddubm vec_add +#define __builtin_vec_vadduhm vec_add +#define __builtin_vec_vadduwm vec_add +#define __builtin_vec_vaddfp vec_add +#define vec_vaddubm vec_add +#define vec_vadduhm vec_add +#define vec_vadduwm vec_add +#define vec_vaddfp vec_add + +static vector signed char _ATTRS_o_ai +vec_add(vector signed char a, vector signed char b) +{ + return a + b; +} + +static vector unsigned char _ATTRS_o_ai +vec_add(vector unsigned char a, vector unsigned char b) +{ + return a + b; +} + +static vector short _ATTRS_o_ai +vec_add(vector short a, vector short b) +{ + return a + b; +} + +static vector unsigned short _ATTRS_o_ai +vec_add(vector unsigned short a, vector unsigned short b) +{ + return a + b; +} + +static vector int _ATTRS_o_ai +vec_add(vector int a, vector int b) +{ + return a + b; +} + +static vector unsigned int _ATTRS_o_ai +vec_add(vector unsigned int a, vector unsigned int b) +{ + return a + b; +} + +static vector float _ATTRS_o_ai +vec_add(vector float a, vector float b) +{ + return a + b; +} + +/* vec_addc */ + +#define __builtin_vec_addc __builtin_altivec_vaddcuw +#define vec_vaddcuw __builtin_altivec_vaddcuw +#define vec_addc __builtin_altivec_vaddcuw + +/* vec_adds */ + +#define __builtin_vec_vaddsbs __builtin_altivec_vaddsbs +#define __builtin_vec_vaddubs __builtin_altivec_vaddubs +#define __builtin_vec_vaddshs __builtin_altivec_vaddshs +#define __builtin_vec_vadduhs __builtin_altivec_vadduhs +#define __builtin_vec_vaddsws __builtin_altivec_vaddsws +#define __builtin_vec_vadduws __builtin_altivec_vadduws +#define vec_vaddsbs __builtin_altivec_vaddsbs +#define vec_vaddubs __builtin_altivec_vaddubs +#define vec_vaddshs __builtin_altivec_vaddshs +#define vec_vadduhs __builtin_altivec_vadduhs +#define vec_vaddsws __builtin_altivec_vaddsws +#define vec_vadduws __builtin_altivec_vadduws + +static vector signed char _ATTRS_o_ai +vec_adds(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vaddsbs(a, b); +} + +static vector unsigned char _ATTRS_o_ai +vec_adds(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vaddubs(a, b); +} + +static vector short _ATTRS_o_ai +vec_adds(vector short a, vector short b) +{ + return __builtin_altivec_vaddshs(a, b); +} + +static vector unsigned short _ATTRS_o_ai +vec_adds(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vadduhs(a, b); +} + +static vector int _ATTRS_o_ai +vec_adds(vector int a, vector int b) +{ + return __builtin_altivec_vaddsws(a, b); +} + +static vector unsigned int _ATTRS_o_ai +vec_adds(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vadduws(a, b); +} + +/* vec_sub */ + +#define __builtin_altivec_vsububm vec_sub +#define __builtin_altivec_vsubuhm vec_sub +#define __builtin_altivec_vsubuwm vec_sub +#define __builtin_altivec_vsubfp vec_sub +#define __builtin_vec_vsububm vec_sub +#define __builtin_vec_vsubuhm vec_sub +#define __builtin_vec_vsubuwm vec_sub +#define __builtin_vec_vsubfp vec_sub +#define vec_vsububm vec_sub +#define vec_vsubuhm vec_sub +#define vec_vsubuwm vec_sub +#define vec_vsubfp vec_sub + +static vector signed char _ATTRS_o_ai +vec_sub(vector signed char a, vector signed char b) +{ + return a - b; +} + +static vector unsigned char _ATTRS_o_ai +vec_sub(vector unsigned char a, vector unsigned char b) +{ + return a - b; +} + +static vector short _ATTRS_o_ai +vec_sub(vector short a, vector short b) +{ + return a - b; +} + +static vector unsigned short _ATTRS_o_ai +vec_sub(vector unsigned short a, vector unsigned short b) +{ + return a - b; +} + +static vector int _ATTRS_o_ai +vec_sub(vector int a, vector int b) +{ + return a - b; +} + +static vector unsigned int _ATTRS_o_ai +vec_sub(vector unsigned int a, vector unsigned int b) +{ + return a - b; +} + +static vector float _ATTRS_o_ai +vec_sub(vector float a, vector float b) +{ + return a - b; +} + +/* vec_subs */ + +#define __builtin_vec_vsubsbs __builtin_altivec_vsubsbs +#define __builtin_vec_vsububs __builtin_altivec_vsububs +#define __builtin_vec_vsubshs __builtin_altivec_vsubshs +#define __builtin_vec_vsubuhs __builtin_altivec_vsubuhs +#define __builtin_vec_vsubsws __builtin_altivec_vsubsws +#define __builtin_vec_vsubuws __builtin_altivec_vsubuws +#define vec_vsubsbs __builtin_altivec_vsubsbs +#define vec_vsububs __builtin_altivec_vsububs +#define vec_vsubshs __builtin_altivec_vsubshs +#define vec_vsubuhs __builtin_altivec_vsubuhs +#define vec_vsubsws __builtin_altivec_vsubsws +#define vec_vsubuws __builtin_altivec_vsubuws + +static vector signed char _ATTRS_o_ai +vec_subs(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vsubsbs(a, b); +} + +static vector unsigned char _ATTRS_o_ai +vec_subs(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vsububs(a, b); +} + +static vector short _ATTRS_o_ai +vec_subs(vector short a, vector short b) +{ + return __builtin_altivec_vsubshs(a, b); +} + +static vector unsigned short _ATTRS_o_ai +vec_subs(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vsubuhs(a, b); +} + +static vector int _ATTRS_o_ai +vec_subs(vector int a, vector int b) +{ + return __builtin_altivec_vsubsws(a, b); +} + +static vector unsigned int _ATTRS_o_ai +vec_subs(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vsubuws(a, b); +} + +/* vec_avg */ + +#define __builtin_vec_vavgsb __builtin_altivec_vavgsb +#define __builtin_vec_vavgub __builtin_altivec_vavgub +#define __builtin_vec_vavgsh __builtin_altivec_vavgsh +#define __builtin_vec_vavguh __builtin_altivec_vavguh +#define __builtin_vec_vavgsw __builtin_altivec_vavgsw +#define __builtin_vec_vavguw __builtin_altivec_vavguw +#define vec_vavgsb __builtin_altivec_vavgsb +#define vec_vavgub __builtin_altivec_vavgub +#define vec_vavgsh __builtin_altivec_vavgsh +#define vec_vavguh __builtin_altivec_vavguh +#define vec_vavgsw __builtin_altivec_vavgsw +#define vec_vavguw __builtin_altivec_vavguw + +static vector signed char _ATTRS_o_ai +vec_avg(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vavgsb(a, b); +} + +static vector unsigned char _ATTRS_o_ai +vec_avg(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vavgub(a, b); +} + +static vector short _ATTRS_o_ai +vec_avg(vector short a, vector short b) +{ + return __builtin_altivec_vavgsh(a, b); +} + +static vector unsigned short _ATTRS_o_ai +vec_avg(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vavguh(a, b); +} + +static vector int _ATTRS_o_ai +vec_avg(vector int a, vector int b) +{ + return __builtin_altivec_vavgsw(a, b); +} + +static vector unsigned int _ATTRS_o_ai +vec_avg(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vavguw(a, b); +} + +/* vec_st */ + +#define __builtin_vec_st vec_st +#define vec_stvx vec_st + +static void _ATTRS_o_ai +vec_st(vector signed char a, int b, vector signed char *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector unsigned char a, int b, vector unsigned char *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector short a, int b, vector short *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector unsigned short a, int b, vector unsigned short *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector int a, int b, vector int *c) +{ + __builtin_altivec_stvx(a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector unsigned int a, int b, vector unsigned int *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_st(vector float a, int b, vector float *c) +{ + __builtin_altivec_stvx((vector int)a, b, (void *)c); +} + +/* vec_stl */ + +#define __builtin_vec_stl vec_stl +#define vec_stvxl vec_stl + +static void _ATTRS_o_ai +vec_stl(vector signed char a, int b, vector signed char *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector unsigned char a, int b, vector unsigned char *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector short a, int b, vector short *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector unsigned short a, int b, vector unsigned short *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector int a, int b, vector int *c) +{ + __builtin_altivec_stvxl(a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector unsigned int a, int b, vector unsigned int *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_stl(vector float a, int b, vector float *c) +{ + __builtin_altivec_stvxl((vector int)a, b, (void *)c); +} + +/* vec_ste */ + +#define __builtin_vec_stvebx __builtin_altivec_stvebx +#define __builtin_vec_stvehx __builtin_altivec_stvehx +#define __builtin_vec_stvewx __builtin_altivec_stvewx +#define vec_stvebx __builtin_altivec_stvebx +#define vec_stvehx __builtin_altivec_stvehx +#define vec_stvewx __builtin_altivec_stvewx + +static void _ATTRS_o_ai +vec_ste(vector signed char a, int b, vector signed char *c) +{ + __builtin_altivec_stvebx((vector char)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector unsigned char a, int b, vector unsigned char *c) +{ + __builtin_altivec_stvebx((vector char)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector short a, int b, vector short *c) +{ + __builtin_altivec_stvehx(a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector unsigned short a, int b, vector unsigned short *c) +{ + __builtin_altivec_stvehx((vector short)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector int a, int b, vector int *c) +{ + __builtin_altivec_stvewx(a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector unsigned int a, int b, vector unsigned int *c) +{ + __builtin_altivec_stvewx((vector int)a, b, (void *)c); +} + +static void _ATTRS_o_ai +vec_ste(vector float a, int b, vector float *c) +{ + __builtin_altivec_stvewx((vector int)a, b, (void *)c); +} + +/* vec_cmpb */ + +#define vec_cmpb __builtin_altivec_vcmpbfp +#define vec_vcmpbfp __builtin_altivec_vcmpbfp +#define __builtin_vec_cmpb __builtin_altivec_vcmpbfp + +/* vec_cmpeq */ + +#define __builtin_vec_cmpeq vec_cmpeq + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmpeq(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpequb((vector char)a, (vector char)b); +} + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmpeq(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpequb((vector char)a, (vector char)b); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmpeq(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh(a, b); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmpeq(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpequh((vector short)a, (vector short)b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpeq(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw(a, b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpeq(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw((vector int)a, (vector int)b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpeq(vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp(a, b); +} + +/* vec_cmpge */ + +#define vec_cmpge __builtin_altivec_vcmpgefp +#define vec_vcmpgefp __builtin_altivec_vcmpgefp +#define __builtin_vec_cmpge __builtin_altivec_vcmpgefp + +/* vec_cmpgt */ + +#define vec_vcmpgtsb __builtin_altivec_vcmpgtsb +#define vec_vcmpgtub __builtin_altivec_vcmpgtub +#define vec_vcmpgtsh __builtin_altivec_vcmpgtsh +#define vec_vcmpgtuh __builtin_altivec_vcmpgtuh +#define vec_vcmpgtsw __builtin_altivec_vcmpgtsw +#define vec_vcmpgtuw __builtin_altivec_vcmpgtuw +#define vec_vcmpgtfp __builtin_altivec_vcmpgtfp +#define __builtin_vec_vcmpgtsb __builtin_altivec_vcmpgtsb +#define __builtin_vec_vcmpgtub __builtin_altivec_vcmpgtub +#define __builtin_vec_vcmpgtsh __builtin_altivec_vcmpgtsh +#define __builtin_vec_vcmpgtuh __builtin_altivec_vcmpgtuh +#define __builtin_vec_vcmpgtsw __builtin_altivec_vcmpgtsw +#define __builtin_vec_vcmpgtuw __builtin_altivec_vcmpgtuw +#define __builtin_vec_vcmpgtfp __builtin_altivec_vcmpgtfp + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmpgt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb(a, b); +} + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmpgt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub(a, b); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmpgt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh(a, b); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmpgt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh(a, b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpgt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw(a, b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpgt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw(a, b); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmpgt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp(a, b); +} + +/* vec_cmple */ + +#define __builtin_vec_cmple vec_cmple + +static vector /*bool*/ int __attribute__((__always_inline__)) +vec_cmple(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp(b, a); +} + +/* vec_cmplt */ + +#define __builtin_vec_cmplt vec_cmplt + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmplt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb(b, a); +} + +static vector /*bool*/ char _ATTRS_o_ai +vec_cmplt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub(b, a); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmplt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh(b, a); +} + +static vector /*bool*/ short _ATTRS_o_ai +vec_cmplt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh(b, a); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmplt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw(b, a); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmplt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw(b, a); +} + +static vector /*bool*/ int _ATTRS_o_ai +vec_cmplt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp(b, a); +} + +/* vec_max */ + +#define __builtin_vec_vmaxsb __builtin_altivec_vmaxsb +#define __builtin_vec_vmaxub __builtin_altivec_vmaxub +#define __builtin_vec_vmaxsh __builtin_altivec_vmaxsh +#define __builtin_vec_vmaxuh __builtin_altivec_vmaxuh +#define __builtin_vec_vmaxsw __builtin_altivec_vmaxsw +#define __builtin_vec_vmaxuw __builtin_altivec_vmaxuw +#define __builtin_vec_vmaxfp __builtin_altivec_vmaxfp +#define vec_vmaxsb __builtin_altivec_vmaxsb +#define vec_vmaxub __builtin_altivec_vmaxub +#define vec_vmaxsh __builtin_altivec_vmaxsh +#define vec_vmaxuh __builtin_altivec_vmaxuh +#define vec_vmaxsw __builtin_altivec_vmaxsw +#define vec_vmaxuw __builtin_altivec_vmaxuw +#define vec_vmaxfp __builtin_altivec_vmaxfp +#define __builtin_vec_max vec_max + +static vector signed char _ATTRS_o_ai +vec_max(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmaxsb(a, b); +} + +static vector unsigned char _ATTRS_o_ai +vec_max(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmaxub(a, b); +} + +static vector short _ATTRS_o_ai +vec_max(vector short a, vector short b) +{ + return __builtin_altivec_vmaxsh(a, b); +} + +static vector unsigned short _ATTRS_o_ai +vec_max(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmaxuh(a, b); +} + +static vector int _ATTRS_o_ai +vec_max(vector int a, vector int b) +{ + return __builtin_altivec_vmaxsw(a, b); +} + +static vector unsigned int _ATTRS_o_ai +vec_max(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vmaxuw(a, b); +} + +static vector float _ATTRS_o_ai +vec_max(vector float a, vector float b) +{ + return __builtin_altivec_vmaxfp(a, b); +} + +/* vec_mfvscr */ + +#define __builtin_vec_mfvscr __builtin_altivec_mfvscr +#define vec_mfvscr __builtin_altivec_mfvscr + +/* vec_min */ + +#define __builtin_vec_vminsb __builtin_altivec_vminsb +#define __builtin_vec_vminub __builtin_altivec_vminub +#define __builtin_vec_vminsh __builtin_altivec_vminsh +#define __builtin_vec_vminuh __builtin_altivec_vminuh +#define __builtin_vec_vminsw __builtin_altivec_vminsw +#define __builtin_vec_vminuw __builtin_altivec_vminuw +#define __builtin_vec_vminfp __builtin_altivec_vminfp +#define vec_vminsb __builtin_altivec_vminsb +#define vec_vminub __builtin_altivec_vminub +#define vec_vminsh __builtin_altivec_vminsh +#define vec_vminuh __builtin_altivec_vminuh +#define vec_vminsw __builtin_altivec_vminsw +#define vec_vminuw __builtin_altivec_vminuw +#define vec_vminfp __builtin_altivec_vminfp +#define __builtin_vec_min vec_min + +static vector signed char _ATTRS_o_ai +vec_min(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vminsb(a, b); +} + +static vector unsigned char _ATTRS_o_ai +vec_min(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vminub(a, b); +} + +static vector short _ATTRS_o_ai +vec_min(vector short a, vector short b) +{ + return __builtin_altivec_vminsh(a, b); +} + +static vector unsigned short _ATTRS_o_ai +vec_min(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vminuh(a, b); +} + +static vector int _ATTRS_o_ai +vec_min(vector int a, vector int b) +{ + return __builtin_altivec_vminsw(a, b); +} + +static vector unsigned int _ATTRS_o_ai +vec_min(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vminuw(a, b); +} + +static vector float _ATTRS_o_ai +vec_min(vector float a, vector float b) +{ + return __builtin_altivec_vminfp(a, b); +} + +/* vec_mtvscr */ + +#define __builtin_vec_mtvscr __builtin_altivec_mtvscr +#define vec_mtvscr __builtin_altivec_mtvscr + +/* ------------------------------ predicates ------------------------------------ */ + +static int __attribute__((__always_inline__)) +__builtin_vec_vcmpeq_p(char CR6_param, vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp_p(CR6_param, a, b); +} + +static int __attribute__((__always_inline__)) +__builtin_vec_vcmpge_p(char CR6_param, vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp_p(CR6_param, a, b); +} + +static int __attribute__((__always_inline__)) +__builtin_vec_vcmpgt_p(char CR6_param, vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(CR6_param, a, b); +} + +/* vec_all_eq */ + +static int _ATTRS_o_ai +vec_all_eq(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); +} + +static int _ATTRS_o_ai +vec_all_eq(vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b); +} + +/* vec_all_ge */ + +static int _ATTRS_o_ai +vec_all_ge(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_ge(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a); +} + +/* vec_all_gt */ + +static int _ATTRS_o_ai +vec_all_gt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b); +} + +static int _ATTRS_o_ai +vec_all_gt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b); +} + +/* vec_all_in */ + +static int __attribute__((__always_inline__)) +vec_all_in(vector float a, vector float b) +{ + return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b); +} + +/* vec_all_le */ + +static int _ATTRS_o_ai +vec_all_le(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_le(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b); +} + +/* vec_all_lt */ + +static int _ATTRS_o_ai +vec_all_lt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a); +} + +static int _ATTRS_o_ai +vec_all_lt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a); +} + +/* vec_all_nan */ + +static int __attribute__((__always_inline__)) +vec_all_nan(vector float a) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a); +} + +/* vec_all_ne */ + +static int _ATTRS_o_ai +vec_all_ne(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); +} + +static int _ATTRS_o_ai +vec_all_ne(vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b); +} + +/* vec_all_nge */ + +static int __attribute__((__always_inline__)) +vec_all_nge(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b); +} + +/* vec_all_ngt */ + +static int __attribute__((__always_inline__)) +vec_all_ngt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b); +} + +/* vec_all_nle */ + +static int __attribute__((__always_inline__)) +vec_all_nle(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a); +} + +/* vec_all_nlt */ + +static int __attribute__((__always_inline__)) +vec_all_nlt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a); +} + +/* vec_all_numeric */ + +static int __attribute__((__always_inline__)) +vec_all_numeric(vector float a) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a); +} + +/* vec_any_eq */ + +static int _ATTRS_o_ai +vec_any_eq(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); +} + +static int _ATTRS_o_ai +vec_any_eq(vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b); +} + +/* vec_any_ge */ + +static int _ATTRS_o_ai +vec_any_ge(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_ge(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a); +} + +/* vec_any_gt */ + +static int _ATTRS_o_ai +vec_any_gt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_gt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b); +} + +/* vec_any_le */ + +static int _ATTRS_o_ai +vec_any_le(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_le(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b); +} + +/* vec_any_lt */ + +static int _ATTRS_o_ai +vec_any_lt(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a); +} + +static int _ATTRS_o_ai +vec_any_lt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a); +} + +/* vec_any_nan */ + +static int __attribute__((__always_inline__)) +vec_any_nan(vector float a) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a); +} + +/* vec_any_ne */ + +static int _ATTRS_o_ai +vec_any_ne(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); +} + +static int _ATTRS_o_ai +vec_any_ne(vector float a, vector float b) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, b); +} + +/* vec_any_nge */ + +static int __attribute__((__always_inline__)) +vec_any_nge(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, a, b); +} + +/* vec_any_ngt */ + +static int __attribute__((__always_inline__)) +vec_any_ngt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b); +} + +/* vec_any_nle */ + +static int __attribute__((__always_inline__)) +vec_any_nle(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, b, a); +} + +/* vec_any_nlt */ + +static int __attribute__((__always_inline__)) +vec_any_nlt(vector float a, vector float b) +{ + return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a); +} + +/* vec_any_numeric */ + +static int __attribute__((__always_inline__)) +vec_any_numeric(vector float a) +{ + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, a); +} + +/* vec_any_out */ + +static int __attribute__((__always_inline__)) +vec_any_out(vector float a, vector float b) +{ + return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, a, b); +} + +#undef _ATTRS_o_ai + +#endif /* __ALTIVEC_H */ diff --git a/lib/Headers/arm_neon.h b/lib/Headers/arm_neon.h new file mode 100644 index 0000000..4508a27 --- /dev/null +++ b/lib/Headers/arm_neon.h @@ -0,0 +1,537 @@ +/*===---- arm_neon.h - NEON intrinsics --------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __ARM_NEON_H +#define __ARM_NEON_H + +#ifndef __ARM_NEON__ +#error "NEON support not enabled" +#endif + +// NEON document appears to be specified in terms of stdint types. +#include <stdint.h> + +// Define some NEON-specific scalar types for floats and polynomials. +typedef float float32_t; +typedef uint8_t poly8_t; + +// FIXME: probably need a 'poly' attribute or something for correct codegen to +// disambiguate from uint16_t. +typedef uint16_t poly16_t; + +typedef __attribute__(( __vector_size__(8) )) int8_t __neon_int8x8_t; +typedef __attribute__(( __vector_size__(16) )) int8_t __neon_int8x16_t; +typedef __attribute__(( __vector_size__(8) )) int16_t __neon_int16x4_t; +typedef __attribute__(( __vector_size__(16) )) int16_t __neon_int16x8_t; +typedef __attribute__(( __vector_size__(8) )) int32_t __neon_int32x2_t; +typedef __attribute__(( __vector_size__(16) )) int32_t __neon_int32x4_t; +typedef __attribute__(( __vector_size__(8) )) int64_t __neon_int64x1_t; +typedef __attribute__(( __vector_size__(16) )) int64_t __neon_int64x2_t; +typedef __attribute__(( __vector_size__(8) )) uint8_t __neon_uint8x8_t; +typedef __attribute__(( __vector_size__(16) )) uint8_t __neon_uint8x16_t; +typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_uint16x4_t; +typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_uint16x8_t; +typedef __attribute__(( __vector_size__(8) )) uint32_t __neon_uint32x2_t; +typedef __attribute__(( __vector_size__(16) )) uint32_t __neon_uint32x4_t; +typedef __attribute__(( __vector_size__(8) )) uint64_t __neon_uint64x1_t; +typedef __attribute__(( __vector_size__(16) )) uint64_t __neon_uint64x2_t; +typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_float16x4_t; +typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_float16x8_t; +typedef __attribute__(( __vector_size__(8) )) float32_t __neon_float32x2_t; +typedef __attribute__(( __vector_size__(16) )) float32_t __neon_float32x4_t; +typedef __attribute__(( __vector_size__(8) )) poly8_t __neon_poly8x8_t; +typedef __attribute__(( __vector_size__(16) )) poly8_t __neon_poly8x16_t; +typedef __attribute__(( __vector_size__(8) )) poly16_t __neon_poly16x4_t; +typedef __attribute__(( __vector_size__(16) )) poly16_t __neon_poly16x8_t; + +typedef struct __int8x8_t { + __neon_int8x8_t val; +} int8x8_t; + +typedef struct __int8x16_t { + __neon_int8x16_t val; +} int8x16_t; + +typedef struct __int16x4_t { + __neon_int16x4_t val; +} int16x4_t; + +typedef struct __int16x8_t { + __neon_int16x8_t val; +} int16x8_t; + +typedef struct __int32x2_t { + __neon_int32x2_t val; +} int32x2_t; + +typedef struct __int32x4_t { + __neon_int32x4_t val; +} int32x4_t; + +typedef struct __int64x1_t { + __neon_int64x1_t val; +} int64x1_t; + +typedef struct __int64x2_t { + __neon_int64x2_t val; +} int64x2_t; + +typedef struct __uint8x8_t { + __neon_uint8x8_t val; +} uint8x8_t; + +typedef struct __uint8x16_t { + __neon_uint8x16_t val; +} uint8x16_t; + +typedef struct __uint16x4_t { + __neon_uint16x4_t val; +} uint16x4_t; + +typedef struct __uint16x8_t { + __neon_uint16x8_t val; +} uint16x8_t; + +typedef struct __uint32x2_t { + __neon_uint32x2_t val; +} uint32x2_t; + +typedef struct __uint32x4_t { + __neon_uint32x4_t val; +} uint32x4_t; + +typedef struct __uint64x1_t { + __neon_uint64x1_t val; +} uint64x1_t; + +typedef struct __uint64x2_t { + __neon_uint64x2_t val; +} uint64x2_t; + +typedef struct __float16x4_t { + __neon_float16x4_t val; +} float16x4_t; + +typedef struct __float16x8_t { + __neon_float16x8_t val; +} float16x8_t; + +typedef struct __float32x2_t { + __neon_float32x2_t val; +} float32x2_t; + +typedef struct __float32x4_t { + __neon_float32x4_t val; +} float32x4_t; + +typedef struct __poly8x8_t { + __neon_poly8x8_t val; +} poly8x8_t; + +typedef struct __poly8x16_t { + __neon_poly8x16_t val; +} poly8x16_t; + +typedef struct __poly16x4_t { + __neon_poly16x4_t val; +} poly16x4_t; + +typedef struct __poly16x8_t { + __neon_poly16x8_t val; +} poly16x8_t; + +// FIXME: write tool to stamp out the structure-of-array types, possibly gen this whole file. + +// Intrinsics, per ARM document DUI0348B +#define __ai static __attribute__((__always_inline__)) + +#define INTTYPES_WIDE(op, builtin) \ + __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ + __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ + __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ + __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ + __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \ + __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } + +#define INTTYPES_WIDENING(op, builtin) \ + __ai int16x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ + __ai int32x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ + __ai int64x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ + __ai uint16x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ + __ai uint32x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \ + __ai uint64x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } + +#define INTTYPES_WIDENING_MUL(op, builtin) \ + __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b, int8x8_t c) { return (int16x8_t){ builtin(a.val, b.val, c.val) }; } \ + __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b, int16x4_t c) { return (int32x4_t){ builtin(a.val, b.val, c.val) }; } \ + __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b, int32x2_t c) { return (int64x2_t){ builtin(a.val, b.val, c.val) }; } \ + __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) { return (uint16x8_t){ builtin(a.val, b.val, c.val) }; } \ + __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) { return (uint32x4_t){ builtin(a.val, b.val, c.val) }; } \ + __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) { return (uint64x2_t){ builtin(a.val, b.val, c.val) }; } + +#define INTTYPES_NARROWING(op, builtin) \ + __ai int8x8_t op##_s16(int16x8_t a, int16x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ + __ai int16x4_t op##_s32(int32x4_t a, int32x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ + __ai int32x2_t op##_s64(int64x2_t a, int64x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ + __ai uint8x8_t op##_u16(uint16x8_t a, uint16x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ + __ai uint16x4_t op##_u32(uint32x4_t a, uint32x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ + __ai uint32x2_t op##_u64(uint64x2_t a, uint64x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } + +#define INTTYPES_ADD_32(op, builtin) \ + __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ + __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ + __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ + __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ + __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ + __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ + __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ builtin(a.val, b.val) }; } \ + __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ + __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ + __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ builtin(a.val, b.val) }; } \ + __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ + __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } + +#define INTTYPES_ADD_64(op, builtin) \ + __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ builtin(a.val, b.val) }; } \ + __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ builtin(a.val, b.val) }; } \ + __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ + __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } + +#define FLOATTYPES_CMP(op, builtin) \ + __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ + __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } + +#define INT_FLOAT_CMP_OP(op, cc) \ + __ai uint8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (uint8x8_t){(__neon_uint8x8_t)(a.val cc b.val)}; } \ + __ai uint16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (uint16x4_t){(__neon_uint16x4_t)(a.val cc b.val)}; } \ + __ai uint32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \ + __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \ + __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val cc b.val}; } \ + __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val cc b.val}; } \ + __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val cc b.val}; } \ + __ai uint8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (uint8x16_t){(__neon_uint8x16_t)(a.val cc b.val)}; } \ + __ai uint16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (uint16x8_t){(__neon_uint16x8_t)(a.val cc b.val)}; } \ + __ai uint32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \ + __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \ + __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val cc b.val}; } \ + __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val cc b.val}; } \ + __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val cc b.val}; } + +#define INT_UNARY(op, builtin) \ + __ai int8x8_t op##_s8(int8x8_t a) { return (int8x8_t){ builtin(a.val) }; } \ + __ai int16x4_t op##_s16(int16x4_t a) { return (int16x4_t){ builtin(a.val) }; } \ + __ai int32x2_t op##_s32(int32x2_t a) { return (int32x2_t){ builtin(a.val) }; } \ + __ai int8x16_t op##q_s8(int8x16_t a) { return (int8x16_t){ builtin(a.val) }; } \ + __ai int16x8_t op##q_s16(int16x8_t a) { return (int16x8_t){ builtin(a.val) }; } \ + __ai int32x4_t op##q_s32(int32x4_t a) { return (int32x4_t){ builtin(a.val) }; } + +#define FP_UNARY(op, builtin) \ + __ai float32x2_t op##_f32(float32x2_t a) { return (float32x2_t){ builtin(a.val) }; } \ + __ai float32x4_t op##q_f32(float32x4_t a) { return (float32x4_t){ builtin(a.val) }; } + +#define FP_BINARY(op, builtin) \ + __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } \ + __ai float32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){ builtin(a.val, b.val) }; } + +#define INT_FP_PAIRWISE_ADD(op, builtin) \ + __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ + __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ + __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ + __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ + __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ + __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ + __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } + +#define INT_LOGICAL_OP(op, lop) \ + __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ a.val lop b.val }; } \ + __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ a.val lop b.val }; } \ + __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ a.val lop b.val }; } \ + __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ a.val lop b.val }; } \ + __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ a.val lop b.val }; } \ + __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ a.val lop b.val }; } \ + __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ a.val lop b.val }; } \ + __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ a.val lop b.val }; } \ + __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ a.val lop b.val }; } \ + __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ a.val lop b.val }; } \ + __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ a.val lop b.val }; } \ + __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ a.val lop b.val }; } \ + __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ a.val lop b.val }; } \ + __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ a.val lop b.val }; } \ + __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ a.val lop b.val }; } \ + __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ a.val lop b.val }; } + +// vector add +__ai int8x8_t vadd_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){a.val + b.val}; } +__ai int16x4_t vadd_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){a.val + b.val}; } +__ai int32x2_t vadd_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){a.val + b.val}; } +__ai int64x1_t vadd_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){a.val + b.val}; } +__ai float32x2_t vadd_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){a.val + b.val}; } +__ai uint8x8_t vadd_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val + b.val}; } +__ai uint16x4_t vadd_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val + b.val}; } +__ai uint32x2_t vadd_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val + b.val}; } +__ai uint64x1_t vadd_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){a.val + b.val}; } +__ai int8x16_t vaddq_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){a.val + b.val}; } +__ai int16x8_t vaddq_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){a.val + b.val}; } +__ai int32x4_t vaddq_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){a.val + b.val}; } +__ai int64x2_t vaddq_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){a.val + b.val}; } +__ai float32x4_t vaddq_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){a.val + b.val}; } +__ai uint8x16_t vaddq_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val + b.val}; } +__ai uint16x8_t vaddq_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val + b.val}; } +__ai uint32x4_t vaddq_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val + b.val}; } +__ai uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){a.val + b.val}; } + +// vector long add +INTTYPES_WIDENING(vaddl, __builtin_neon_vaddl) + +// vector wide add +INTTYPES_WIDE(vaddw, __builtin_neon_vaddw) + +// halving add +// rounding halving add +INTTYPES_ADD_32(vhadd, __builtin_neon_vhadd) +INTTYPES_ADD_32(vrhadd, __builtin_neon_vrhadd) + +// saturating add +INTTYPES_ADD_32(vqadd, __builtin_neon_vqadd) +INTTYPES_ADD_64(vqadd, __builtin_neon_vqadd) + +// add high half +// rounding add high half +INTTYPES_NARROWING(vaddhn, __builtin_neon_vaddhn) +INTTYPES_NARROWING(vraddhn, __builtin_neon_vraddhn) + +// multiply +// mul-poly + +// multiple accumulate +// multiple subtract + +// multiple accumulate long +// multiple subtract long +INTTYPES_WIDENING_MUL(vmlal, __builtin_neon_vmlal) +INTTYPES_WIDENING_MUL(vmlsl, __builtin_neon_vmlsl) + +// saturating doubling multiply high +// saturating rounding doubling multiply high + +// saturating doubling multiply accumulate long +// saturating doubling multiply subtract long + +// long multiply +// long multiply-poly +INTTYPES_WIDENING(vmull, __builtin_neon_vmull) +__ai poly16x8_t vmull_p8(poly8x8_t a, poly8x8_t b) { return (poly16x8_t){ __builtin_neon_vmull(a.val, b.val) }; } + +// saturating doubling long multiply + +// subtract + +// long subtract +INTTYPES_WIDENING(vsubl, __builtin_neon_vsubl) + +// wide subtract +INTTYPES_WIDE(vsubw, __builtin_neon_vsubw) + +// saturating subtract +INTTYPES_ADD_32(vqsub, __builtin_neon_vqsub) +INTTYPES_ADD_64(vqsub, __builtin_neon_vqsub) + +// halving subtract +INTTYPES_ADD_32(vhsub, __builtin_neon_vhsub) + +// subtract high half +// rounding subtract high half +INTTYPES_NARROWING(vsubhn, __builtin_neon_vsubhn) +INTTYPES_NARROWING(vrsubhn, __builtin_neon_vrsubhn) + +// compare eq +// compare ge +// compare le +// compare gt +// compare lt +INT_FLOAT_CMP_OP(vceq, ==) +INT_FLOAT_CMP_OP(vcge, >=) +INT_FLOAT_CMP_OP(vcle, <=) +INT_FLOAT_CMP_OP(vcgt, >) +INT_FLOAT_CMP_OP(vclt, <) + +// compare eq-poly + +// compare abs ge +// compare abs le +// compare abs gt +// compare abs lt +FLOATTYPES_CMP(vcage, __builtin_neon_vcage) +FLOATTYPES_CMP(vcale, __builtin_neon_vcale) +FLOATTYPES_CMP(vcagt, __builtin_neon_vcagt) +FLOATTYPES_CMP(vcalt, __builtin_neon_vcalt) + +// test bits + +// abs diff +INTTYPES_ADD_32(vabd, __builtin_neon_vabd) +FP_BINARY(vabd, __builtin_neon_vabd) + +// abs diff long +INTTYPES_WIDENING(vabdl, __builtin_neon_vabdl) + +// abs diff accumulate +// abs diff accumulate long + +// max +// min +INTTYPES_ADD_32(vmax, __builtin_neon_vmax) +FP_BINARY(vmax, __builtin_neon_vmax) +INTTYPES_ADD_32(vmin, __builtin_neon_vmin) +FP_BINARY(vmin, __builtin_neon_vmin) + +// pairwise add +// pairwise max +// pairwise min +INT_FP_PAIRWISE_ADD(vpadd, __builtin_neon_vpadd) +INT_FP_PAIRWISE_ADD(vpmax, __builtin_neon_vpmax) +INT_FP_PAIRWISE_ADD(vpmin, __builtin_neon_vpmin) + +// long pairwise add +// long pairwise add accumulate + +// recip +// recip sqrt +FP_BINARY(vrecps, __builtin_neon_vrecps) +FP_BINARY(vrsqrts, __builtin_neon_vrsqrts) + +// shl by vec +// saturating shl by vec +// rounding shl by vec +// saturating rounding shl by vec + +// shr by constant +// shl by constant +// rounding shr by constant +// shr by constant and accumulate +// rounding shr by constant and accumulate +// saturating shl by constant +// s->u saturating shl by constant +// narrowing saturating shr by constant +// s->u narrowing saturating shr by constant +// s->u rounding narrowing saturating shr by constant +// narrowing saturating shr by constant +// rounding narrowing shr by constant +// rounding narrowing saturating shr by constant +// widening shl by constant + +// shr and insert +// shl and insert + +// loads and stores, single vector +// loads and stores, lane +// loads, dupe + +// loads and stores, arrays + +// vget,vgetq lane +// vset, vsetq lane + +// vcreate +// vdup, vdupq +// vmov, vmovq +// vdup_lane, vdupq_lane +// vcombine +// vget_high, vget_low + +// vcvt {u,s} <-> f, f <-> f16 +// narrow +// long move (unpack) +// saturating narrow +// saturating narrow s->u + +// table lookup +// extended table lookup + +// mla with scalar +// widening mla with scalar +// widening saturating doubling mla with scalar +// mls with scalar +// widening mls with scalar +// widening saturating doubling mls with scalar +// mul by scalar +// long mul with scalar +// long mul by scalar +// saturating doubling long mul with scalar +// saturating doubling long mul by scalar +// saturating doubling mul high with scalar +// saturating doubling mul high by scalar +// saturating rounding doubling mul high with scalar +// saturating rounding doubling mul high by scalar +// mla with scalar +// widening mla with sclar +// widening saturating doubling mla with scalar +// mls with scalar +// widening mls with scalar +// widening saturating doubling mls with scalar + +// extract + +// endian swap (vrev) + +// negate + +// abs +// saturating abs +// saturating negate +// count leading signs +INT_UNARY(vabs, __builtin_neon_vabs) +FP_UNARY(vabs, __builtin_neon_vabs) +INT_UNARY(vqabs, __builtin_neon_vqabs) +INT_UNARY(vqneg, __builtin_neon_vqneg) +INT_UNARY(vcls, __builtin_neon_vcls) + +// count leading zeroes +// popcount + +// recip_est +// recip_sqrt_est + +// not-poly +// not + +// and +// or +// xor +// andn +// orn +INT_LOGICAL_OP(vand, &) +INT_LOGICAL_OP(vorr, |) +INT_LOGICAL_OP(veor, ^) +INT_LOGICAL_OP(vbic, &~) +INT_LOGICAL_OP(vorn, |~) + +// bitselect + +// transpose elts +// interleave elts +// deinterleave elts + +// vreinterpret + +#endif /* __ARM_NEON_H */ diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h index f24352b..cc213ce 100644 --- a/lib/Headers/nmmintrin.h +++ b/lib/Headers/nmmintrin.h @@ -32,4 +32,4 @@ just include it now then. */ #include <smmintrin.h> #endif /* __SSE4_2__ */ -#endif /* _NMMINTRIN_H */
\ No newline at end of file +#endif /* _NMMINTRIN_H */ diff --git a/lib/Headers/stdint.h b/lib/Headers/stdint.h index 15b6eaa..1785f31 100644 --- a/lib/Headers/stdint.h +++ b/lib/Headers/stdint.h @@ -218,11 +218,18 @@ typedef __uint_least8_t uint_fast8_t; #define __intn_t(n) __stdint_join3( int, n, _t) #define __uintn_t(n) __stdint_join3(uint, n, _t) +#ifndef _INTPTR_T #ifndef __intptr_t_defined typedef __intn_t(__INTPTR_WIDTH__) intptr_t; #define __intptr_t_defined +#define _INTPTR_T #endif +#endif + +#ifndef _UINTPTR_T typedef __uintn_t(__INTPTR_WIDTH__) uintptr_t; +#define _UINTPTR_T +#endif /* C99 7.18.1.5 Greatest-width integer types. */ diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h index 09ebc23..07fea1c 100644 --- a/lib/Headers/tmmintrin.h +++ b/lib/Headers/tmmintrin.h @@ -67,7 +67,7 @@ _mm_abs_epi32(__m128i a) } #define _mm_alignr_epi8(a, b, n) (__builtin_ia32_palignr128((a), (b), (n))) -#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n*8))) +#define _mm_alignr_pi8(a, b, n) (__builtin_ia32_palignr((a), (b), (n))) static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) _mm_hadd_epi16(__m128i a, __m128i b) diff --git a/lib/Index/ASTLocation.cpp b/lib/Index/ASTLocation.cpp index c24f3bf..091bc78 100644 --- a/lib/Index/ASTLocation.cpp +++ b/lib/Index/ASTLocation.cpp @@ -87,7 +87,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { case N_Decl: OS << "[Decl: " << AsDecl()->getDeclKindName() << " "; if (const NamedDecl *ND = dyn_cast<NamedDecl>(AsDecl())) - OS << ND->getNameAsString(); + OS << ND; break; case N_Stmt: @@ -97,7 +97,7 @@ void ASTLocation::print(llvm::raw_ostream &OS) const { case N_NamedRef: OS << "[NamedRef: " << AsNamedRef().ND->getDeclKindName() << " "; - OS << AsNamedRef().ND->getNameAsString(); + OS << AsNamedRef().ND; break; case N_Type: { diff --git a/lib/Index/Analyzer.cpp b/lib/Index/Analyzer.cpp index 7b414f2..1354fe6 100644 --- a/lib/Index/Analyzer.cpp +++ b/lib/Index/Analyzer.cpp @@ -153,9 +153,10 @@ public: ObjCInterfaceDecl *MsgD = 0; ObjCMessageExpr *Msg = cast<ObjCMessageExpr>(ASTLoc.AsStmt()); - if (Msg->getReceiver()) { + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Instance: { const ObjCObjectPointerType *OPT = - Msg->getReceiver()->getType()->getAsObjCInterfacePointerType(); + Msg->getInstanceReceiver()->getType()->getAsObjCInterfacePointerType(); // Can be anything! Accept it as a possibility.. if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) @@ -171,15 +172,34 @@ public: // Should be an instance method. if (!IsInstanceMethod) return false; + break; + } - } else { + case ObjCMessageExpr::Class: { + // Expecting class method. + if (IsInstanceMethod) + return false; + + MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + break; + } + + case ObjCMessageExpr::SuperClass: // Expecting class method. if (IsInstanceMethod) return false; - MsgD = Msg->getClassInfo().Decl; - // FIXME: Case when we only have an identifier. - assert(MsgD && "Identifier only"); + MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); + break; + + case ObjCMessageExpr::SuperInstance: + // Expecting instance method. + if (!IsInstanceMethod) + return false; + + MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>() + ->getInterfaceDecl(); + break; } assert(MsgD); @@ -248,31 +268,44 @@ public: ObjCInterfaceDecl *MsgD = 0; while (true) { - if (Msg->getReceiver() == 0) { - CanBeClassMethod = true; - MsgD = Msg->getClassInfo().Decl; - // FIXME: Case when we only have an identifier. - assert(MsgD && "Identifier only"); - break; - } + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Instance: { + const ObjCObjectPointerType *OPT = + Msg->getInstanceReceiver()->getType() + ->getAsObjCInterfacePointerType(); + + if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) { + CanBeInstanceMethod = CanBeClassMethod = true; + break; + } - const ObjCObjectPointerType *OPT = - Msg->getReceiver()->getType()->getAsObjCInterfacePointerType(); + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + CanBeClassMethod = true; + break; + } - if (!OPT || OPT->isObjCIdType() || OPT->isObjCQualifiedIdType()) { - CanBeInstanceMethod = CanBeClassMethod = true; + MsgD = OPT->getInterfaceDecl(); + assert(MsgD); + CanBeInstanceMethod = true; break; } + + case ObjCMessageExpr::Class: + CanBeClassMethod = true; + MsgD = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl(); + break; - if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + case ObjCMessageExpr::SuperClass: CanBeClassMethod = true; + MsgD = Msg->getSuperType()->getAs<ObjCInterfaceType>()->getDecl(); break; - } - MsgD = OPT->getInterfaceDecl(); - assert(MsgD); - CanBeInstanceMethod = true; - break; + case ObjCMessageExpr::SuperInstance: + CanBeInstanceMethod = true; + MsgD = Msg->getSuperType()->getAs<ObjCObjectPointerType>() + ->getInterfaceDecl(); + break; + } } assert(CanBeInstanceMethod || CanBeClassMethod); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 19f25ea..74e8d74 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1874,9 +1874,10 @@ LexNextToken: if (PP->isCurrentLexer(this)) { // Start a new token. If this is a #include or something, the PP may // want us starting at the beginning of the line again. If so, set - // the StartOfLine flag. + // the StartOfLine flag and clear LeadingSpace. if (IsAtStartOfLine) { Result.setFlag(Token::StartOfLine); + Result.clearFlag(Token::LeadingSpace); IsAtStartOfLine = false; } goto LexNextToken; // GCC isn't tail call eliminating. @@ -2024,9 +2025,10 @@ LexNextToken: if (PP->isCurrentLexer(this)) { // Start a new token. If this is a #include or something, the PP may // want us starting at the beginning of the line again. If so, set - // the StartOfLine flag. + // the StartOfLine flag and clear LeadingSpace. if (IsAtStartOfLine) { Result.setFlag(Token::StartOfLine); + Result.clearFlag(Token::LeadingSpace); IsAtStartOfLine = false; } goto LexNextToken; // GCC isn't tail call eliminating. diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 1cfa0e3..f425582 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -654,6 +654,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, llvm::APInt LitVal(PP.getTargetInfo().getIntWidth(), 0); unsigned NumCharsSoFar = 0; + bool Warned = false; while (begin[0] != '\'') { uint64_t ResultChar; if (begin[0] != '\\') // If this is a normal character, consume it. @@ -670,8 +671,10 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, } else { // Narrow character literals act as though their value is concatenated // in this implementation, but warn on overflow. - if (LitVal.countLeadingZeros() < 8) + if (LitVal.countLeadingZeros() < 8 && !Warned) { PP.Diag(Loc, diag::warn_char_constant_too_large); + Warned = true; + } LitVal <<= 8; } } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 757ba90..417724b 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -716,7 +716,8 @@ void Preprocessor::HandleLineDirective(Token &Tok) { SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID); if (Callbacks) - Callbacks->FileChanged(DigitTok.getLocation(), PPCallbacks::RenameFile, + Callbacks->FileChanged(CurPPLexer->getSourceLocation(), + PPCallbacks::RenameFile, SrcMgr::C_User); } @@ -865,7 +866,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { else if (IsSystemHeader) FileKind = SrcMgr::C_System; - Callbacks->FileChanged(DigitTok.getLocation(), Reason, FileKind); + Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind); } } @@ -1087,11 +1088,6 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, return; } - // Ask HeaderInfo if we should enter this #include file. If not, #including - // this file will have no effect. - if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) - return; - // The #included file will be considered to be a system header if either it is // in a system include directory, or if the #includer is a system include // header. @@ -1099,6 +1095,14 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, std::max(HeaderInfo.getFileDirFlavor(File), SourceMgr.getFileCharacteristic(FilenameTok.getLocation())); + // Ask HeaderInfo if we should enter this #include file. If not, #including + // this file will have no effect. + if (!HeaderInfo.ShouldEnterIncludeFile(File, isImport)) { + if (Callbacks) + Callbacks->FileSkipped(*File, FilenameTok, FileCharacter); + return; + } + // Look up the file, create a File ID for it. FileID FID = SourceMgr.createFileID(File, FilenameTok.getLocation(), FileCharacter); @@ -1108,10 +1112,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, } // Finally, if all is good, enter the new file! - std::string ErrorStr; - if (EnterSourceFile(FID, CurDir, ErrorStr)) - Diag(FilenameTok, diag::err_pp_error_opening_file) - << std::string(SourceMgr.getFileEntryForID(FID)->getName()) << ErrorStr; + EnterSourceFile(FID, CurDir, FilenameTok.getLocation()); } /// HandleIncludeNextDirective - Implements #include_next. @@ -1666,4 +1667,3 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) { return SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, /*FoundElse*/CI.FoundElse); } - diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 335d3db..4a40405 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -64,8 +64,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. -bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, - std::string &ErrorStr) { +void Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, + SourceLocation Loc) { assert(CurTokenLexer == 0 && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -75,19 +75,23 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, if (PTH) { if (PTHLexer *PL = PTH->CreateLexer(FID)) { EnterSourceFileWithPTH(PL, CurDir); - return false; + return; } } // Get the MemoryBuffer for this FID, if it fails, we fail. bool Invalid = false; - const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID, - &Invalid); - if (Invalid) - return true; + const llvm::MemoryBuffer *InputFile = + getSourceManager().getBuffer(FID, Loc, &Invalid); + if (Invalid) { + SourceLocation FileStart = SourceMgr.getLocForStartOfFile(FID); + Diag(Loc, diag::err_pp_error_opening_file) + << std::string(SourceMgr.getBufferName(FileStart)) << ""; + return; + } EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); - return false; + return; } /// EnterSourceFileWithLexer - Add a source file to the top of the include stack diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 1c6a5ad..71bb4fc 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -487,28 +487,29 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { const LangOptions &LangOpts = PP.getLangOptions(); return llvm::StringSwitch<bool>(II->getName()) + .Case("attribute_analyzer_noreturn", true) + .Case("attribute_cf_returns_not_retained", true) + .Case("attribute_cf_returns_retained", true) + .Case("attribute_ext_vector_type", true) + .Case("attribute_ns_returns_not_retained", true) + .Case("attribute_ns_returns_retained", true) + .Case("attribute_objc_ivar_unused", true) + .Case("attribute_overloadable", true) .Case("blocks", LangOpts.Blocks) - .Case("cxx_rtti", LangOpts.RTTI) - //.Case("cxx_lambdas", false) - //.Case("cxx_nullptr", false) - //.Case("cxx_concepts", false) - .Case("cxx_decltype", LangOpts.CPlusPlus0x) + .Case("cxx_attributes", LangOpts.CPlusPlus0x) .Case("cxx_auto_type", LangOpts.CPlusPlus0x) + .Case("cxx_decltype", LangOpts.CPlusPlus0x) + .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) .Case("cxx_exceptions", LangOpts.Exceptions) - .Case("cxx_attributes", LangOpts.CPlusPlus0x) + .Case("cxx_rtti", LangOpts.RTTI) .Case("cxx_static_assert", LangOpts.CPlusPlus0x) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) - .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) + .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) + //.Case("cxx_concepts", false) + //.Case("cxx_lambdas", false) + //.Case("cxx_nullptr", false) //.Case("cxx_rvalue_references", false) - .Case("attribute_overloadable", true) //.Case("cxx_variadic_templates", false) - .Case("attribute_ext_vector_type", true) - .Case("attribute_analyzer_noreturn", true) - .Case("attribute_cf_returns_not_retained", true) - .Case("attribute_cf_returns_retained", true) - .Case("attribute_ns_returns_not_retained", true) - .Case("attribute_ns_returns_retained", true) - .Case("attribute_objc_ivar_unused", true) .Default(false); } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 4598383..ce6d9ab 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -490,7 +490,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. -bool Preprocessor::EnterMainSourceFile() { +void Preprocessor::EnterMainSourceFile() { // We do not allow the preprocessor to reenter the main file. Doing so will // cause FileID's to accumulate information from both runs (e.g. #line // information) and predefined macros aren't guaranteed to be set properly. @@ -498,9 +498,7 @@ bool Preprocessor::EnterMainSourceFile() { FileID MainFileID = SourceMgr.getMainFileID(); // Enter the main file source buffer. - std::string ErrorStr; - if (EnterSourceFile(MainFileID, 0, ErrorStr)) - return true; + EnterSourceFile(MainFileID, 0, SourceLocation()); // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. @@ -515,7 +513,7 @@ bool Preprocessor::EnterMainSourceFile() { assert(!FID.isInvalid() && "Could not create FileID for predefines?"); // Start parsing the predefines. - return EnterSourceFile(FID, 0, ErrorStr); + EnterSourceFile(FID, 0, SourceLocation()); } void Preprocessor::EndSourceFile() { diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp index 51d2e23..fc6db21 100644 --- a/lib/Lex/TokenConcatenation.cpp +++ b/lib/Lex/TokenConcatenation.cpp @@ -124,7 +124,8 @@ static char GetFirstChar(Preprocessor &PP, const Token &Tok) { /// but the resulting output won't have incorrect concatenations going on. /// Examples include "..", which we print with a space between, because we /// don't want to track enough to tell "x.." from "...". -bool TokenConcatenation::AvoidConcat(const Token &PrevTok, +bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok, + const Token &PrevTok, const Token &Tok) const { // First, check to see if the tokens were directly adjacent in the original // source. If they were, it must be okay to stick them together: if there @@ -192,7 +193,8 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevTok, return isalnum(FirstChar) || Tok.is(tok::numeric_constant) || FirstChar == '+' || FirstChar == '-' || FirstChar == '.'; case tok::period: // ..., .*, .1234 - return FirstChar == '.' || isdigit(FirstChar) || + return (FirstChar == '.' && PrevPrevTok.is(tok::period)) || + isdigit(FirstChar) || (PP.getLangOptions().CPlusPlus && FirstChar == '*'); case tok::amp: // && return FirstChar == '&'; diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 3cd74d5..bae2a09 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -23,7 +23,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, AttributeList *n, bool declspec, bool cxx0x) : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), - DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) { + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { if (numArgs == 0) Args = 0; @@ -105,6 +105,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("overloadable", AT_overloadable) .Case("address_space", AT_address_space) .Case("always_inline", AT_always_inline) + .Case("returns_twice", IgnoredAttribute) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("ext_vector_type", AT_ext_vector_type) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 11865ab..5dc08b3 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -433,6 +433,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); + SaveStorageSpecifierAsWritten(); // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 5f48897..5a03767 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -26,11 +26,40 @@ ActionBase::~ActionBase() {} /// Out-of-line virtual destructor to provide home for Action class. Action::~Action() {} +Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType) { + ReceiverType = 0; + + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) { + DeclSpec DS; + const char *PrevSpec = 0; + unsigned DiagID = 0; + if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec, + DiagID, TyName)) { + DS.SetRangeEnd(NameLoc); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = ActOnTypeName(S, DeclaratorInfo); + if (!Ty.isInvalid()) + ReceiverType = Ty.get(); + } + return ObjCClassMessage; + } + + return ObjCInstanceMessage; +} + // Defined out-of-line here because of dependecy on AttributeList Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { @@ -47,7 +76,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -144,7 +173,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { /// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking. Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName, TypeTy *ObjectType) { if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>()) if (TI->isTypeName) @@ -161,7 +190,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, TemplateNameKind MinimalAction::isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 87e22fa..5405c0c 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -29,12 +29,14 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, "Current token not a '{', ':' or 'try'!"); Action::MultiTemplateParamsArg TemplateParams(Actions, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); + DeclPtrTy FnD; if (D.getDeclSpec().isFriendSpecified()) // FIXME: Friend templates - FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams)); + FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, + move(TemplateParams)); else // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, move(TemplateParams), 0, 0, @@ -53,7 +55,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // We may have a constructor initializer or function-try-block here. if (kind == tok::colon || kind == tok::kw_try) { // Consume everything up to (and including) the left brace. - if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) { + if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) { // We didn't find the left-brace we expected after the // constructor initializer. if (Tok.is(tok::semi)) { @@ -72,13 +74,13 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, ConsumeBrace(); } // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { while (Tok.is(tok::kw_catch)) { - ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks); - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } } @@ -98,7 +100,8 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, + HasClassScope); if (HasClassScope) Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); @@ -217,12 +220,17 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { "ParseFunctionTryBlock left tokens in the token stream!"); continue; } - if (Tok.is(tok::colon)) + if (Tok.is(tok::colon)) { ParseConstructorInitializer(LM.D); - else + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions)); + continue; + } + } else Actions.ActOnDefaultCtorInitializers(LM.D); - // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? ParseFunctionStatementBody(LM.D); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && @@ -238,14 +246,12 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). -/// If EarlyAbortIf is specified, then we will stop early if we find that -/// token at the top level. +/// If StopAtSemi is true, then we will stop early at a ';' character. /// Returns true if token 'T1' or 'T2' was found. /// NOTE: This is a specialized version of Parser::SkipUntil. bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, - tok::TokenKind EarlyAbortIf, - bool ConsumeFinalToken) { + bool StopAtSemi, bool ConsumeFinalToken) { // We always want this function to consume at least one token if the first // token isn't T and if not at EOF. bool isFirstTokenConsumed = true; @@ -259,10 +265,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, return true; } - // If we found the early-abort token, return. - if (Tok.is(EarlyAbortIf)) - return false; - switch (Tok.getKind()) { case tok::eof: // Ran out of tokens. @@ -272,19 +274,19 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, // Recursively consume properly-nested parens. Toks.push_back(Tok); ConsumeParen(); - ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); break; case tok::l_square: // Recursively consume properly-nested square brackets. Toks.push_back(Tok); ConsumeBracket(); - ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); break; case tok::l_brace: // Recursively consume properly-nested braces. Toks.push_back(Tok); ConsumeBrace(); - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. @@ -316,6 +318,10 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, Toks.push_back(Tok); ConsumeStringToken(); break; + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. default: // consume this token. Toks.push_back(Tok); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c85b6ee..91050e0 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -904,7 +904,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // reinforced by the NAD status of core issue 635. TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); - if (DSContext == DSC_top_level && TemplateId->Name && + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { if (isConstructorDeclarator()) { // The user meant this to be an out-of-line constructor @@ -949,7 +951,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If we're in a context where the identifier could be a class name, // check whether this is a constructor declaration. - if (DSContext == DSC_top_level && + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope, &SS)) { if (isConstructorDeclarator()) @@ -1434,6 +1437,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, switch (Tok.getKind()) { case tok::identifier: // foo::bar + // If we already have a type specifier, this identifier is not a type. + if (DS.getTypeSpecType() != DeclSpec::TST_unspecified || + DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified || + DS.getTypeSpecSign() != DeclSpec::TSS_unspecified) + return false; // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; @@ -1892,15 +1900,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - // enums cannot be templates. - if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { - Diag(Tok, diag::err_enum_template); - - // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); - return; - } - // If an identifier is present, consume and remember it. IdentifierInfo *Name = 0; SourceLocation NameLoc; @@ -1924,23 +1923,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TUK = Action::TUK_Declaration; else TUK = Action::TUK_Reference; + + // enums cannot be templates, although they can be referenced from a + // template. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + TUK != Action::TUK_Reference) { + Diag(Tok, diag::err_enum_template); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + bool Owned = false; bool IsDependent = false; + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + const char *PrevSpec = 0; + unsigned DiagID; DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, Attr.get(), AS, Action::MultiTemplateParamsArg(Actions), Owned, IsDependent); - assert(!IsDependent && "didn't expect dependent enum"); + if (IsDependent) { + // This enum has a dependent nested-name-specifier. Handle it as a + // dependent tag. + if (!Name) { + DS.SetTypeSpecError(); + Diag(Tok, diag::err_expected_type_name_after_typename); + return; + } + + TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum, + TUK, SS, Name, StartLoc, + NameLoc); + if (Type.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, + Type.get(), false)) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } + if (!TagDecl.get()) { + // The action failed to produce an enumeration tag. If this is a + // definition, consume the entire definition. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace); + } + + DS.SetTypeSpecError(); + return; + } + if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); // FIXME: The DeclSpec should keep the locations of both the keyword and the // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - const char *PrevSpec = 0; - unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, TagDecl.getAs<void>(), Owned)) Diag(StartLoc, DiagID) << PrevSpec; @@ -2427,7 +2472,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail - if (SS.isSet()) { + if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; @@ -2583,36 +2628,42 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (getLang().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet(); - if (!afterCXXScope) { + if (D.getCXXScopeSpec().isEmpty()) { ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, true); - afterCXXScope = D.getCXXScopeSpec().isSet(); } - if (afterCXXScope) { + if (D.getCXXScopeSpec().isValid()) { if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); - } - + } + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. - bool AllowConstructorName - = ((D.getCXXScopeSpec().isSet() && - D.getContext() == Declarator::FileContext) || - (!D.getCXXScopeSpec().isSet() && - D.getContext() == Declarator::MemberContext)) && - !D.getDeclSpec().hasTypeSpecifier(); + bool AllowConstructorName; + if (D.getDeclSpec().hasTypeSpecifier()) + AllowConstructorName = false; + else if (D.getCXXScopeSpec().isSet()) + AllowConstructorName = + (D.getContext() == Declarator::FileContext || + (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().isFriendSpecified())); + else + AllowConstructorName = (D.getContext() == Declarator::MemberContext); + if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, /*ObjectType=*/0, - D.getName())) { + D.getName()) || + // Once we're past the identifier, if the scope was bad, mark the + // whole declarator bad. + D.getCXXScopeSpec().isInvalid()) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); } else { @@ -2974,7 +3025,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, DefArgToks = new CachedTokens; if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, - tok::semi, false)) { + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 813c24c..015ac5b 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -178,7 +178,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, DeclPtrTy LinkageSpec = Actions.ActOnStartLinkageSpecification(CurScope, /*FIXME: */SourceLocation(), - Loc, Lang.data(), Lang.size(), + Loc, Lang, Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); @@ -465,7 +465,7 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// simple-template-id /// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS) { + CXXScopeSpec *SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -780,9 +780,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Action::DeclResult TagOrTempResult = true; // invalid Action::TypeResult TypeResult = true; // invalid - // FIXME: When TUK == TUK_Reference and we have a template-id, we need - // to turn that template-id into a type. - bool Owned = false; if (TemplateId) { // Explicit specialization, class template partial specialization, @@ -806,7 +803,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateArgsPtr, TemplateId->RAngleLoc, AttrList); - } else if (TUK == Action::TUK_Reference) { + + // Friend template-ids are treated as references unless + // they have template headers, in which case they're ill-formed + // (FIXME: "template <class T> friend class A<T>::B<int>;"). + // We diagnose this error in ActOnClassTemplateSpecialization. + } else if (TUK == Action::TUK_Reference || + (TUK == Action::TUK_Friend && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index af91021..b9e632a 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -29,30 +29,6 @@ #include "llvm/ADT/SmallString.h" using namespace clang; -/// PrecedenceLevels - These are precedences for the binary/ternary operators in -/// the C99 grammar. These have been named to relate with the C99 grammar -/// productions. Low precedences numbers bind more weakly than high numbers. -namespace prec { - enum Level { - Unknown = 0, // Not binary operator. - Comma = 1, // , - Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= - Conditional = 3, // ? - LogicalOr = 4, // || - LogicalAnd = 5, // && - InclusiveOr = 6, // | - ExclusiveOr = 7, // ^ - And = 8, // & - Equality = 9, // ==, != - Relational = 10, // >=, <=, >, < - Shift = 11, // <<, >> - Additive = 12, // -, + - Multiplicative = 13, // *, /, % - PointerToMember = 14 // .*, ->* - }; -} - - /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// @@ -268,11 +244,11 @@ Parser::OwningExprResult Parser::ParseAssignmentExpression() { /// expressions and other binary operators for these expressions as well. Parser::OwningExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, - SourceLocation NameLoc, - IdentifierInfo *ReceiverName, + SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr) { - OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc, - ReceiverName, + OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, + ReceiverType, move(ReceiverExpr))); if (R.isInvalid()) return move(R); R = ParsePostfixExpressionSuffix(move(R)); @@ -297,10 +273,10 @@ Parser::OwningExprResult Parser::ParseConstantExpression() { /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult -Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), - GreaterThanIsOperator, - getLang().CPlusPlus0x); +Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { + prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), + GreaterThanIsOperator, + getLang().CPlusPlus0x); SourceLocation ColonLoc; while (1) { @@ -335,14 +311,15 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { Diag(Tok, diag::ext_gnu_conditional_expr); } - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); + if (Tok.is(tok::colon)) { + // Eat the colon. + ColonLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_colon) + << FixItHint::CreateInsertion(Tok.getLocation(), ": "); Diag(OpToken, diag::note_matching) << "?"; - return ExprError(); + ColonLoc = Tok.getLocation(); } - - // Eat the colon. - ColonLoc = ConsumeToken(); } // Parse another leaf here for the RHS of the operator. @@ -362,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. - unsigned ThisPrec = NextTokPrec; + prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); @@ -379,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. - RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc); + RHS = ParseRHSOfBinaryExpression(move(RHS), + static_cast<prec::Level>(ThisPrec + !isRightAssoc)); if (RHS.isInvalid()) return move(RHS); @@ -480,7 +458,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO] +/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -500,14 +478,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// /// id-expression: [C++ 5.1] /// unqualified-id -/// qualified-id [TODO] +/// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id [TODO] +/// conversion-function-id +/// '~' class-name +/// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id @@ -637,11 +615,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); - // Support 'Class.property' notation. We don't use - // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is - // inappropriate here). + // Support 'Class.property' and 'super.property' notation. if (getLang().ObjC1 && Tok.is(tok::period) && - Actions.getTypeName(II, ILoc, CurScope)) { + (Actions.getTypeName(II, ILoc, CurScope) || + // Allow the base to be 'super' if in an objc-method. + (&II == Ident_super && CurScope->isInObjcMethodScope()))) { SourceLocation DotLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { @@ -810,6 +788,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + // (We can end up in this situation after tentative parsing.) + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::annot_cxxscope)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -897,11 +883,16 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::caret: return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression()); + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeToken(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); case tok::l_square: // These can be followed by postfix-expr pieces. if (getLang().ObjC1) return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); - // FALL THROUGH. + // FALL THROUGH. default: NotCastExpr = true; return ExprError(); @@ -1431,10 +1422,19 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, CastTy = Ty.get(); - if (stopIfCastExpr) { - // Note that this doesn't parse the subsequent cast-expression, it just - // returns the parsed type to the callee. + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) return OwningExprResult(Actions); + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLang().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + CurScope->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); } // Parse the cast-expression that follows it next. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 8528f8f..146762b 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, return false; } +/// \brief Determine whether the current token starts a C++ +/// simple-type-specifier. +bool Parser::isCXXSimpleTypeSpecifier() const { + switch (Tok.getKind()) { + case tok::annot_typename: + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + // FIXME: C++0x decltype support. + // GNU typeof support. + case tok::kw_typeof: + return true; + + default: + break; + } + + return false; +} + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. @@ -837,6 +867,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; + // FIXME: C++0x decltype support. // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); @@ -1703,7 +1734,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Store the tokens of the parentheses. We will parse them after we determine // the context that follows them. - if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) { + if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { // We didn't find the ')' we expected. MatchRHSPunctuation(tok::r_paren, LParenLoc); return ExprError(); diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 9154d8d..a382a9a 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Designator.h" #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Scope.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -33,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) { } } +static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, + Designation &Desig) { + // If we have exactly one array designator, this used the GNU + // 'designation: array-designator' extension, otherwise there should be no + // designators at all! + if (Desig.getNumDesignators() == 1 && + (Desig.getDesignator(0).isArrayDesignator() || + Desig.getDesignator(0).isArrayRangeDesignator())) + P.Diag(Loc, diag::ext_gnu_missing_equal_designator); + else if (Desig.getNumDesignators() > 0) + P.Diag(Loc, diag::err_expected_equal_designator); +} + /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production /// checking to see if the token stream starts with a designator. /// @@ -123,33 +137,97 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // [4][foo bar] -> obsolete GNU designation with objc message send. // SourceLocation StartLoc = ConsumeBracket(); + OwningExprResult Idx(Actions); + + // If Objective-C is enabled and this is a typename (class message + // send) or send to 'super', parse this as a message send + // expression. We handle C++ and C separately, since C++ requires + // much more complicated parsing. + if (getLang().ObjC1 && getLang().CPlusPlus) { + // Send to 'super'. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), 0, + ExprArg(Actions)); + } + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + // If the receiver was a type, we have a class message; parse + // the rest of it. + if (!IsExpr) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + TypeOrExpr, + ExprArg(Actions)); + } - // If Objective-C is enabled and this is a typename or other identifier - // receiver, parse this as a message send expression. - if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { - // If we have exactly one array designator, this used the GNU - // 'designation: array-designator' extension, otherwise there should be no - // designators at all! - if (Desig.getNumDesignators() == 1 && - (Desig.getDesignator(0).isArrayDesignator() || - Desig.getDesignator(0).isArrayRangeDesignator())) - Diag(StartLoc, diag::ext_gnu_missing_equal_designator); - else if (Desig.getNumDesignators() > 0) - Diag(Tok, diag::err_expected_equal_designator); - - IdentifierInfo *Name = Tok.getIdentifierInfo(); - SourceLocation NameLoc = ConsumeToken(); - return ParseAssignmentExprWithObjCMessageExprStart( - StartLoc, NameLoc, Name, ExprArg(Actions)); + // If the receiver was an expression, we still don't know + // whether we have a message send or an array designator; just + // adopt the expression for further analysis below. + // FIXME: potentially-potentially evaluated expression above? + Idx = OwningExprResult(Actions, TypeOrExpr); + } else if (getLang().ObjC1 && Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IILoc = Tok.getLocation(); + TypeTy *ReceiverType; + // Three cases. This is a message send to a type: [type foo] + // This is a message send to super: [super foo] + // This is a message sent to an expr: [super.bar foo] + switch (Action::ObjCMessageKind Kind + = Actions.getObjCMessageKind(CurScope, II, IILoc, + II == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + case Action::ObjCClassMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + if (Kind == Action::ObjCSuperMessage) + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + 0, + ExprArg(Actions)); + ConsumeToken(); // the identifier + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through; we'll just parse the expression and + // (possibly) treat this like an Objective-C message send + // later. + break; + } } + // Parse the index expression, if we haven't already gotten one + // above (which can only happen in Objective-C++). // Note that we parse this as an assignment expression, not a constant // expression (allowing *=, =, etc) to handle the objc case. Sema needs // to validate that the expression is a constant. - OwningExprResult Idx(ParseAssignmentExpression()); - if (Idx.isInvalid()) { - SkipUntil(tok::r_square); - return move(Idx); + // FIXME: We also need to tell Sema that we're in a + // potentially-potentially evaluated context. + if (!Idx.get()) { + Idx = ParseAssignmentExpression(); + if (Idx.isInvalid()) { + SkipUntil(tok::r_square); + return move(Idx); + } } // Given an expression, we could either have a designator (if the next @@ -158,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // an assignment-expression production. if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && Tok.isNot(tok::r_square)) { - - // If we have exactly one array designator, this used the GNU - // 'designation: array-designator' extension, otherwise there should be no - // designators at all! - if (Desig.getNumDesignators() == 1 && - (Desig.getDesignator(0).isArrayDesignator() || - Desig.getDesignator(0).isArrayRangeDesignator())) - Diag(StartLoc, diag::ext_gnu_missing_equal_designator); - else if (Desig.getNumDesignators() > 0) - Diag(Tok, diag::err_expected_equal_designator); - + CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), 0, move(Idx)); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 243be0e..7b1ecf6 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -142,13 +142,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - bool Err = false; - if (Tok.is(tok::l_paren)) { // we have a category. + if (Tok.is(tok::l_paren) && + !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. SourceLocation lparenLoc = ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId); + Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -157,12 +157,6 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( categoryId = Tok.getIdentifierInfo(); categoryLoc = ConsumeToken(); } - else if (isKnownToBeTypeSpecifier(Tok)) { - // Fall thru after diagnosing for better error recovery. - Diag(Tok, diag::err_expected_minus_or_plus); - ConsumeToken(); - Err = true; - } else if (!getLang().ObjC2) { Diag(Tok, diag::err_expected_ident); // missing category name. return DeclPtrTy(); @@ -173,34 +167,32 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( return DeclPtrTy(); } rparenLoc = ConsumeParen(); - if (!Err) { - // Next, we need to check for any protocol references. - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + // Next, we need to check for any protocol references. + SourceLocation LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, LAngleLoc, EndProtoLoc)) - return DeclPtrTy(); + return DeclPtrTy(); - if (attrList) // categories don't support attributes. - Diag(Tok, diag::err_objc_no_attributes_on_category); - - DeclPtrTy CategoryType = - Actions.ActOnStartCategoryInterface(atLoc, - nameId, nameLoc, - categoryId, categoryLoc, - ProtocolRefs.data(), - ProtocolRefs.size(), - ProtocolLocs.data(), - EndProtoLoc); - if (Tok.is(tok::l_brace)) + if (attrList) // categories don't support attributes. + Diag(Tok, diag::err_objc_no_attributes_on_category); + + DeclPtrTy CategoryType = + Actions.ActOnStartCategoryInterface(atLoc, + nameId, nameLoc, + categoryId, categoryLoc, + ProtocolRefs.data(), + ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc); + if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc); - ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); - return CategoryType; - } + ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); + return CategoryType; } // Parse a class interface. IdentifierInfo *superClassId = 0; @@ -211,7 +203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // Code completion of superclass names. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSuperclass(CurScope, nameId); + Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -242,7 +234,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); - return Err ? DeclPtrTy() : ClsType; + return ClsType; } /// The Objective-C property callback. This should be defined where @@ -787,6 +779,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::ObjCKeywordKind MethodImplKind) { ParsingDeclRAIIObject PD(*this); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + /*ReturnType=*/0, IDecl); + ConsumeToken(); + } + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; @@ -798,6 +796,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) MethodAttrs.reset(ParseGNUAttributes()); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + ReturnType, IDecl); + ConsumeToken(); + } + // Now parse the selector. SourceLocation selLoc; IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc); @@ -811,7 +815,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, return DeclPtrTy(); } - llvm::SmallVector<Declarator, 8> CargNames; + llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) @@ -822,7 +826,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - 0, CargNames, MethodAttrs.get(), + 0, + CParamInfo.data(), CParamInfo.size(), + MethodAttrs.get(), MethodImplKind); PD.complete(Result); return Result; @@ -885,7 +891,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // Parse the declarator. Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); - CargNames.push_back(ParmDecl); + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl); + CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), + Param, + 0)); + } // FIXME: Add support for optional parmameter list... @@ -901,7 +913,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - &ArgInfos[0], CargNames, + &ArgInfos[0], + CParamInfo.data(), CParamInfo.size(), MethodAttrs.get(), MethodImplKind, isVariadic); PD.complete(Result); @@ -1053,7 +1066,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, = P.Actions.ActOnIvar(P.CurScope, FD.D.getDeclSpec().getSourceRange().getBegin(), IDecl, FD.D, FD.BitfieldSize, visibility); - AllIvarDecls.push_back(Field); + if (Field) + AllIvarDecls.push_back(Field); return Field; } } Callback(*this, interfaceDecl, visibility, AllIvarDecls); @@ -1207,7 +1221,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId); + Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -1404,8 +1418,12 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { break; ConsumeToken(); // consume ',' } - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi)) { Diag(Tok, diag::err_expected_semi_after) << "@dynamic"; + SkipUntil(tok::semi); + } + else + ConsumeToken(); // consume ';' return DeclPtrTy(); } @@ -1422,7 +1440,8 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { return StmtError(); } } - ConsumeToken(); // consume ';' + // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope); } @@ -1482,7 +1501,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lbrace); return StmtError(); } - OwningStmtResult CatchStmts(Actions); + StmtVector CatchStmts(Actions); OwningStmtResult FinallyStmt(Actions); ParseScope TryScope(this, Scope::DeclScope); OwningStmtResult TryBody(ParseCompoundStatementBody()); @@ -1515,11 +1534,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); - // Inform the actions module about the parameter declarator, so it + // Inform the actions module about the declarator, so it // gets added to the current scope. - // FIXME. Probably can build a VarDecl and avoid setting DeclContext. - FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl); - Actions.ActOnObjCCatchParam(FirstPart); + FirstPart = Actions.ActOnObjCExceptionDecl(CurScope, ParmDecl); } else ConsumeToken(); // consume '...' @@ -1537,9 +1554,14 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lbrace); if (CatchBody.isInvalid()) CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); - CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, - RParenLoc, FirstPart, move(CatchBody), - move(CatchStmts)); + + OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, + RParenLoc, + FirstPart, + move(CatchBody)); + if (!Catch.isInvalid()) + CatchStmts.push_back(Catch.release()); + } else { Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after) << "@catch clause"; @@ -1568,7 +1590,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(atLoc, diag::err_missing_catch_finally); return StmtError(); } - return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts), + + return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), + move_arg(CatchStmts), move(FinallyStmt)); } @@ -1604,7 +1628,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { SourceLocation BraceLoc = Tok.getLocation(); // Enter a scope for the method body. - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, + Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); // Tell the actions module that we have entered a method definition with the // specified Declarator for the method. @@ -1683,39 +1708,191 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { } } +/// \brirg Parse the receiver of an Objective-C++ message send. +/// +/// This routine parses the receiver of a message send in +/// Objective-C++ either as a type or as an expression. Note that this +/// routine must not be called to parse a send to 'super', since it +/// has no way to return such a result. +/// +/// \param IsExpr Whether the receiver was parsed as an expression. +/// +/// \param TypeOrExpr If the receiver was parsed as an expression (\c +/// IsExpr is true), the parsed expression. If the receiver was parsed +/// as a type (\c IsExpr is false), the parsed type. +/// +/// \returns True if an error occurred during parsing or semantic +/// analysis, in which case the arguments do not have valid +/// values. Otherwise, returns false for a successful parse. +/// +/// objc-receiver: [C++] +/// 'super' [not parsed here] +/// expression +/// simple-type-specifier +/// typename-specifier + +bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { + if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) + TryAnnotateTypeOrScopeToken(); + + if (!isCXXSimpleTypeSpecifier()) { + // objc-receiver: + // expression + OwningExprResult Receiver = ParseExpression(); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // objc-receiver: + // typename-specifier + // simple-type-specifier + // expression (that starts with one of the above) + DeclSpec DS; + ParseCXXSimpleTypeSpecifier(DS); + + if (Tok.is(tok::l_paren)) { + // If we see an opening parentheses at this point, we are + // actually parsing an expression that starts with a + // function-style cast, e.g., + // + // postfix-expression: + // simple-type-specifier ( expression-list [opt] ) + // typename-specifier ( expression-list [opt] ) + // + // Parse the remainder of this case, then the (optional) + // postfix-expression suffix, followed by the (optional) + // right-hand side of the binary expression. We have an + // instance method. + OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS); + if (!Receiver.isInvalid()) + Receiver = ParsePostfixExpressionSuffix(move(Receiver)); + if (!Receiver.isInvalid()) + Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // We have a class message. Turn the simple-type-specifier or + // typename-specifier we parsed into a type and parse the + // remainder of the class message. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo); + if (Type.isInvalid()) + return true; + + IsExpr = false; + TypeOrExpr = Type.get(); + return false; +} + /// objc-message-expr: /// '[' objc-receiver objc-message-args ']' /// -/// objc-receiver: +/// objc-receiver: [C] +/// 'super' /// expression /// class-name /// type-name +/// Parser::OwningExprResult Parser::ParseObjCMessageExpression() { assert(Tok.is(tok::l_square) && "'[' expected"); SourceLocation LBracLoc = ConsumeBracket(); // consume '[' - // Parse receiver - if (isTokObjCMessageIdentifierReceiver()) { - IdentifierInfo *ReceiverName = Tok.getIdentifierInfo(); - if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) { - SourceLocation NameLoc = ConsumeToken(); - return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName, + if (getLang().CPlusPlus) { + // We completely separate the C and C++ cases because C++ requires + // more complicated (read: slower) parsing. + + // Handle send to super. + // FIXME: This doesn't benefit from the same typo-correction we + // get in Objective-C. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, ExprArg(Actions)); + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); } - } + if (IsExpr) + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + OwningExprResult(Actions, TypeOrExpr)); + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + TypeOrExpr, ExprArg(Actions)); + } else if (Tok.is(tok::identifier)) { + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + TypeTy *ReceiverType; + switch (Actions.getObjCMessageKind(CurScope, Name, NameLoc, + Name == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, + ExprArg(Actions)); + + case Action::ObjCClassMessage: + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + ConsumeToken(); // the type name + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through to parse an expression. + break; + } + } + + // Otherwise, an arbitrary expression can be the receiver of a send. OwningExprResult Res(ParseExpression()); if (Res.isInvalid()) { SkipUntil(tok::r_square); return move(Res); } - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - 0, move(Res)); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + move(Res)); } -/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse -/// the rest of a message expression. +/// \brief Parse the remainder of an Objective-C message following the +/// '[' objc-receiver. +/// +/// This routine handles sends to super, class messages (sent to a +/// class name), and instance messages (sent to an object), and the +/// target is represented by \p SuperLoc, \p ReceiverType, or \p +/// ReceiverExpr, respectively. Only one of these parameters may have +/// a valid value. +/// +/// \param LBracLoc The location of the opening '['. +/// +/// \param SuperLoc If this is a send to 'super', the location of the +/// 'super' keyword that indicates a send to the superclass. +/// +/// \param ReceiverType If this is a class message, the type of the +/// class we are sending a message to. +/// +/// \param ReceiverExpr If this is an instance message, the expression +/// used to compute the receiver object. /// /// objc-message-args: /// objc-selector @@ -1737,13 +1914,14 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { /// Parser::OwningExprResult Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, - SourceLocation NameLoc, - IdentifierInfo *ReceiverName, + SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr) { if (Tok.is(tok::code_completion)) { - if (ReceiverName) - Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, - 0, 0); + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, 0, 0); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, 0, 0); else Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), 0, 0); @@ -1789,8 +1967,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // Code completion after each argument. if (Tok.is(tok::code_completion)) { - if (ReceiverName) - Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, + KeyIdents.data(), + KeyIdents.size()); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, KeyIdents.data(), KeyIdents.size()); else @@ -1851,15 +2033,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.push_back(selIdent); Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); - // We've just parsed a keyword message. - if (ReceiverName) - return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel, - LBracLoc, NameLoc, SelectorLoc, - RBracLoc, - KeyExprs.take(), KeyExprs.size())); - return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel, - LBracLoc, SelectorLoc, RBracLoc, - KeyExprs.take(), KeyExprs.size())); + if (SuperLoc.isValid()) + return Actions.ActOnSuperMessage(CurScope, SuperLoc, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + else if (ReceiverType) + return Actions.ActOnClassMessage(CurScope, ReceiverType, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + return Actions.ActOnInstanceMessage(CurScope, move(ReceiverExpr), Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); } Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index b208c50..9b22270 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -643,6 +643,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { if (Tok.is(tok::kw_else)) { ElseLoc = ConsumeToken(); + ElseStmtLoc = Tok.getLocation(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do @@ -656,12 +657,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); - bool WithinElse = CurScope->isWithinElse(); - CurScope->setWithinElse(true); - ElseStmtLoc = Tok.getLocation(); + // Regardless of whether or not InnerScope actually pushed a scope, set the + // ElseScope flag for the innermost scope so we can diagnose use of the if + // condition variable in C++. + unsigned OldFlags = CurScope->getFlags(); + CurScope->setFlags(OldFlags | Scope::ElseScope); ElseStmt = ParseStatement(); - CurScope->setWithinElse(WithinElse); - + CurScope->setFlags(OldFlags); + // Pop the 'else' scope if needed. InnerScope.Exit(); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 516a9a6..a6c6d3f 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Template.h" using namespace clang; /// isCXXDeclarationStatement - C++-specialized function that disambiguates @@ -761,6 +762,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___vector: return TPResult::True(); + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind != TNK_Type_template) + return TPResult::False(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(&SS); + assert(Tok.is(tok::annot_typename)); + goto case_typename; + } + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. if (TryAnnotateTypeOrScopeToken()) @@ -801,6 +813,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_double: case tok::kw_void: case tok::annot_typename: + case_typename: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 489586c..6dbb99e 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -668,9 +668,15 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, // If we have a colon, then we're probably parsing a C++ // ctor-initializer. - if (Tok.is(tok::colon)) + if (Tok.is(tok::colon)) { ParseConstructorInitializer(Res); - else + + // Recover from error. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions)); + return Res; + } + } else Actions.ActOnDefaultCtorInitializers(Res); return ParseFunctionStatementBody(Res); @@ -1046,7 +1052,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) return true; - if (!SS.isSet()) + if (SS.isEmpty()) return false; // Push the current token back into the token stream (or revert it if it is diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index 7b78070..5fe0649 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -533,6 +533,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { std::string Expansion = EscapeText(TmpPP.getSpelling(Tok)); unsigned LineLen = Expansion.size(); + Token PrevPrevTok; Token PrevTok = Tok; // Okay, eat this token, getting the next one. TmpPP.Lex(Tok); @@ -553,13 +554,14 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // If the tokens were already space separated, or if they must be to avoid // them being implicitly pasted, add a space between them. if (Tok.hasLeadingSpace() || - ConcatInfo.AvoidConcat(PrevTok, Tok)) + ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) Expansion += ' '; // Escape any special characters in the token text. Expansion += EscapeText(TmpPP.getSpelling(Tok)); LineLen += Expansion.size(); + PrevPrevTok = PrevTok; PrevTok = Tok; TmpPP.Lex(Tok); } diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp index bf8ba70..376678a 100644 --- a/lib/Rewrite/Rewriter.cpp +++ b/lib/Rewrite/Rewriter.cpp @@ -20,6 +20,12 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const { + // FIXME: eliminate the copy by writing out each chunk at a time + os << std::string(begin(), end()); + return os; +} + void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { // Nothing to remove, exit early. if (Size == 0) return; @@ -222,5 +228,3 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { ReplaceText(From->getLocStart(), Size, Str); return false; } - - diff --git a/lib/Runtime/Makefile b/lib/Runtime/Makefile index 9a3c347..580215a 100644 --- a/lib/Runtime/Makefile +++ b/lib/Runtime/Makefile @@ -26,6 +26,7 @@ PROJ_resources_lib := $(PROJ_resources)/lib # Expect compiler-rt to be in llvm/projects/compiler-rt COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt +ifndef CLANG_NO_RUNTIME ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK) # Select the compiler-rt configuration to use, and install directory. @@ -97,3 +98,4 @@ install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%) clean-local:: CleanRuntimeLibraries endif +endif diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index d1f00ca..6ded0a3 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -25,7 +25,6 @@ #include "clang/Analysis/Analyses/ReachableCode.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Casting.h" -#include <queue> using namespace clang; @@ -75,7 +74,6 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; llvm::BitVector live(cfg->getNumBlockIDs()); unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), live); @@ -149,7 +147,8 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { bool NoReturnEdge = false; if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (B.succ_begin()[0] != &cfg->getExit()) { + if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) + == B.succ_end()) { HasAbnormalEdge = true; continue; } @@ -190,7 +189,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_NeverFallThroughOrReturn; bool funMode; - static CheckFallThroughDiagnostics MakeForFunction() { + static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = diag::warn_falloff_noreturn_function; @@ -200,8 +199,19 @@ struct CheckFallThroughDiagnostics { diag::warn_falloff_noreturn_function; D.diag_AlwaysFallThrough_ReturnsNonVoid = diag::warn_falloff_nonvoid_function; - D.diag_NeverFallThroughOrReturn = - diag::warn_suggest_noreturn_function; + + // Don't suggest that virtual functions be marked "noreturn", since they + // might be overridden by non-noreturn functions. + bool isVirtualMethod = false; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) + isVirtualMethod = Method->isVirtual(); + + if (!isVirtualMethod) + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_function; + else + D.diag_NeverFallThroughOrReturn = 0; + D.funMode = true; return D; } @@ -297,7 +307,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); break; @@ -325,8 +335,7 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { void clang::sema:: AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, - const Decl *D, QualType BlockTy, - const bool analyzeStaticInline) { + const Decl *D, QualType BlockTy) { assert(BlockTy.isNull() || isa<BlockDecl>(D)); @@ -336,12 +345,14 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // don't bother trying. // (2) The code already has problems; running the analysis just takes more // time. - if (S.getDiagnostics().hasErrorOccurred()) + Diagnostic &Diags = S.getDiagnostics(); + + if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; // Do not do any analysis for declarations in system headers if we are // going to just ignore them. - if (S.getDiagnostics().getSuppressSystemWarnings() && + if (Diags.getSuppressSystemWarnings() && S.SourceMgr.isInSystemHeader(D->getLocation())) return; @@ -350,17 +361,6 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // we'll do the analysis at instantiation time. if (FD->isDependentContext()) return; - - // Only analyze 'static inline' functions when explicitly asked. - if (!analyzeStaticInline && FD->isInlineSpecified() && - FD->getStorageClass() == FunctionDecl::Static) { - FD = FD->getCanonicalDecl(); - VisitFlag &visitFlag = VisitedFD[FD]; - if (visitFlag == Pending) - visitFlag = Visited; - else - return; - } } const Stmt *Body = D->getBody(); @@ -369,61 +369,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. AnalysisContext AC(D, false); - bool performedCheck = false; // Warning: check missing 'return' if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() - : CheckFallThroughDiagnostics::MakeForFunction()); + : CheckFallThroughDiagnostics::MakeForFunction(D)); CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); - performedCheck = true; } // Warning: check for unreachable code - if (P.enableCheckUnreachable) { + if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - performedCheck = true; - } - - // If this block or function calls a 'static inline' function, - // we should analyze those functions as well. - if (performedCheck) { - // The CFG should already be constructed, so this should not - // incur any extra cost. We might not have a CFG, however, for - // invalid code. - if (const CFG *cfg = AC.getCFG()) { - // All CallExprs are block-level expressions in the CFG. This means - // that walking the basic blocks in the CFG is more efficient - // than walking the entire AST to find all calls. - for (CFG::const_iterator I=cfg->begin(), E=cfg->end(); I!=E; ++I) { - const CFGBlock *B = *I; - for (CFGBlock::const_iterator BI=B->begin(), BE=B->end(); BI!=BE; ++BI) - if (const CallExpr *CE = dyn_cast<CallExpr>(*BI)) - if (const DeclRefExpr *DR = - dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenCasts())) - if (const FunctionDecl *calleeD = - dyn_cast<FunctionDecl>(DR->getDecl())) { - calleeD = calleeD->getCanonicalDecl(); - if (calleeD->isInlineSpecified() && - calleeD->getStorageClass() == FunctionDecl::Static) { - // Have we analyzed this static inline function before? - VisitFlag &visitFlag = VisitedFD[calleeD]; - if (visitFlag == NotVisited) { - // Mark the callee visited prior to analyzing it - // so we terminate in case of recursion. - if (calleeD->getBody()) { - visitFlag = Visited; - IssueWarnings(DefaultPolicy, calleeD, QualType(), true); - } - else { - // Delay warnings until we encounter the definition. - visitFlag = Pending; - } - } - } - } - } - } - } } diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h index b5db8af..dea19ba 100644 --- a/lib/Sema/AnalysisBasedWarnings.h +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -47,9 +47,7 @@ public: Policy getDefaultPolicy() { return DefaultPolicy; } - void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType(), - const bool analyzeStaticInline = false); - + void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType()); }; }} // end namespace clang::sema diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 5483a29..0ef9a15 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -86,7 +86,7 @@ CodeCompletionString::Chunk::Chunk(ChunkKind Kind, llvm::StringRef Text) break; case CK_Colon: - this->Text = ": "; + this->Text = ":"; break; case CK_SemiColon: @@ -425,7 +425,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << "COMPLETION: "; switch (Results[I].Kind) { case Result::RK_Declaration: - OS << Results[I].Declaration->getNameAsString() ; + OS << Results[I].Declaration; if (Results[I].Hidden) OS << " (Hidden)"; if (CodeCompletionString *CCS diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 1c761b9..0694294 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -155,8 +155,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { BuildScopeInformation(TryPart, Scopes.size()-1); // Jump from the catch to the finally or try is not valid. - for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC; - AC = AC->getNextCatchStmt()) { + for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *AC = AT->getCatchStmt(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, AC->getAtCatchLoc())); diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index f310c25..0961299 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -124,7 +124,6 @@ public: }; typedef UnresolvedSetImpl::iterator iterator; - typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, Sema::LookupNameKind LookupKind, @@ -136,7 +135,6 @@ public: Name(Name), NameLoc(NameLoc), LookupKind(LookupKind), - IsAcceptableFn(0), IDNS(0), Redecl(Redecl != Sema::NotForRedeclaration), HideTags(true), @@ -156,7 +154,6 @@ public: Name(Other.Name), NameLoc(Other.NameLoc), LookupKind(Other.LookupKind), - IsAcceptableFn(Other.IsAcceptableFn), IDNS(Other.IDNS), Redecl(Other.Redecl), HideTags(Other.HideTags), @@ -242,8 +239,7 @@ public: /// \brief Tests whether the given declaration is acceptable. bool isAcceptableDecl(NamedDecl *D) const { - assert(IsAcceptableFn); - return IsAcceptableFn(D, IDNS); + return D->isInIdentifierNamespace(IDNS); } /// \brief Returns the identifier namespace mask for this lookup. @@ -282,6 +278,18 @@ public: NamingClass = Record; } + /// \brief Returns the base object type associated with this lookup; + /// important for [class.protected]. Most lookups do not have an + /// associated base object. + QualType getBaseObjectType() const { + return BaseObjectType; + } + + /// \brief Sets the base object type for this lookup. + void setBaseObjectType(QualType T) { + BaseObjectType = T; + } + /// \brief Add a declaration to these results with its natural access. /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { @@ -331,6 +339,11 @@ public: } else { ResultKind = Found; resolveKind(); + + if (Paths && (ResultKind != Ambiguous)) { + deletePaths(Paths); + Paths = 0; + } } } @@ -550,6 +563,7 @@ private: UnresolvedSet<8> Decls; CXXBasePaths *Paths; CXXRecordDecl *NamingClass; + QualType BaseObjectType; // Parameters. Sema &SemaRef; @@ -557,7 +571,6 @@ private: SourceLocation NameLoc; SourceRange NameContextRange; Sema::LookupNameKind LookupKind; - ResultFilter IsAcceptableFn; // set by configure() unsigned IDNS; // set by configure() bool Redecl; diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 7cd3989..bb0bd9e 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -24,6 +24,26 @@ using namespace clang; +static void DumpRecordLayouts(ASTContext &C) { + for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); + I != E; ++I) { + const RecordType *RT = dyn_cast<RecordType>(*I); + if (!RT) + continue; + + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); + if (!RD || RD->isImplicit() || RD->isDependentType() || + RD->isInvalidDecl() || !RD->getDefinition()) + continue; + + // FIXME: Do we really need to hard code this? + if (RD->getQualifiedNameAsString() == "__va_list_tag") + continue; + + C.DumpRecordLayout(RD, llvm::errs()); + } +} + //===----------------------------------------------------------------------===// // Public interface to the file //===----------------------------------------------------------------------===// @@ -44,8 +64,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); - if (PP.EnterMainSourceFile()) - return; + PP.EnterMainSourceFile(); // Initialize the parser. P.Initialize(); @@ -82,6 +101,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, E = S.WeakTopLevelDecls().end(); I != E; ++I) Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); + // Dump record layouts, if requested. + if (PP.getLangOptions().DumpRecordLayouts) + DumpRecordLayouts(Ctx); + Consumer->HandleTranslationUnit(Ctx); if (ExternalSemaSource *ESS = diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index ccfbe1e..755af84 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -158,7 +158,8 @@ Sema::~Sema() { /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, - CastExpr::CastKind Kind, bool isLvalue) { + CastExpr::CastKind Kind, + bool isLvalue, CXXBaseSpecifierArray BasePath) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); @@ -177,14 +178,14 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, CheckImplicitConversion(Expr, Ty); if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { - if (ImpCast->getCastKind() == Kind) { + if (ImpCast->getCastKind() == Kind && BasePath.empty()) { ImpCast->setType(Ty); ImpCast->setLvalueCast(isLvalue); return; } } - Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); + Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, BasePath, isLvalue); } void Sema::DeleteExpr(ExprTy *E) { @@ -197,14 +198,7 @@ void Sema::DeleteStmt(StmtTy *S) { /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. -void Sema::ActOnEndOfTranslationUnit() { - - // Remove functions that turned out to be used. - UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), - UnusedStaticFuncs.end(), - std::mem_fun(&FunctionDecl::isUsed)), - UnusedStaticFuncs.end()); - +void Sema::ActOnEndOfTranslationUnit() { while (1) { // C++: Perform implicit template instantiations. // @@ -225,6 +219,12 @@ void Sema::ActOnEndOfTranslationUnit() { break; } + // Remove functions that turned out to be used. + UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), + UnusedStaticFuncs.end(), + std::mem_fun(&FunctionDecl::isUsed)), + UnusedStaticFuncs.end()); + // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic // order! Iterating over a densemap like this is bad. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0766b1e..f146c85 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -25,6 +25,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/FullExpr.h" #include "clang/Parse/Action.h" #include "clang/Sema/SemaDiagnostic.h" @@ -108,33 +109,33 @@ namespace clang { class TargetAttributesSema; class ADLResult; -/// \brief Retains information about a function, method, or block that is +/// \brief Retains information about a function, method, or block that is /// currently being parsed. struct FunctionScopeInfo { /// \brief Whether this scope information structure defined information for /// a block. bool IsBlockInfo; - - /// \brief Set true when a function, method contains a VLA or ObjC try block, + + /// \brief Set true when a function, method contains a VLA or ObjC try block, /// which introduce scopes that need to be checked for goto conditions. If a /// function does not contain this, then it need not have the jump checker run on it. bool NeedsScopeChecking; - + /// \brief The number of errors that had occurred before starting this /// function or block. unsigned NumErrorsAtStartOfFunction; - + /// LabelMap - This is a mapping from label identifiers to the LabelStmt for /// it (which acts like the label decl in some ways). Forward referenced /// labels have a LabelStmt created for them with a null location & SubStmt. llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap; - + /// SwitchStack - This is the current set of active switch statements in the /// block. - llvm::SmallVector<SwitchStmt*, 8> SwitchStack; - - FunctionScopeInfo(unsigned NumErrors) - : IsBlockInfo(false), NeedsScopeChecking(false), + llvm::SmallVector<SwitchStmt*, 8> SwitchStack; + + FunctionScopeInfo(unsigned NumErrors) + : IsBlockInfo(false), NeedsScopeChecking(false), NumErrorsAtStartOfFunction(NumErrors) { } virtual ~FunctionScopeInfo(); @@ -142,11 +143,11 @@ struct FunctionScopeInfo { /// \brief Clear out the information in this function scope, making it /// suitable for reuse. void Clear(unsigned NumErrors); - - static bool classof(const FunctionScopeInfo *FSI) { return true; } + + static bool classof(const FunctionScopeInfo *FSI) { return true; } }; - - + + /// \brief Retains information about a block that is currently being parsed. struct BlockScopeInfo : FunctionScopeInfo { llvm::SmallVector<ParmVarDecl*, 8> Params; @@ -164,11 +165,11 @@ struct BlockScopeInfo : FunctionScopeInfo { /// return types, if any, in the block body. QualType ReturnType; - BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), - hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) + BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) + : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false), + hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope) { - IsBlockInfo = true; + IsBlockInfo = true; } virtual ~BlockScopeInfo(); @@ -233,6 +234,30 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush) + : S(S), SavedContext(S.CurContext) { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + SavedContext = 0; + } + + ~ContextRAII() { + pop(); + } + }; + /// PackContext - Manages the stack for #pragma pack. An alignment /// of 0 indicates default alignment. void *PackContext; // Really a "PragmaPackStack*" @@ -240,14 +265,14 @@ public: /// \brief Stack containing information about each of the nested function, /// block, and method scopes that are currently active. llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes; - + /// \brief Cached function scope object used for the top function scope /// and when there is no function scope (in error cases). /// - /// This should never be accessed directly; rather, it's address will be + /// This should never be accessed directly; rather, it's address will be /// pushed into \c FunctionScopes when we want to re-use it. FunctionScopeInfo TopFunctionScope; - + /// ExprTemporaries - This is the stack of temporaries that are created by /// the current full expression. llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries; @@ -312,26 +337,17 @@ public: bool isMemberAccess() const { return IsMember; } - AccessedEntity(ASTContext &Context, - MemberNonce _, - CXXRecordDecl *NamingClass, - AccessSpecifier Access, - NamedDecl *Target) - : Access(Access), IsMember(true), - Target(Target), NamingClass(NamingClass), - Diag(0, Context.getDiagAllocator()) { - } - - AccessedEntity(ASTContext &Context, + AccessedEntity(ASTContext &Context, MemberNonce _, CXXRecordDecl *NamingClass, - DeclAccessPair FoundDecl) - : Access(FoundDecl.getAccess()), IsMember(true), + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : Access(FoundDecl.getAccess()), IsMember(true), Target(FoundDecl.getDecl()), NamingClass(NamingClass), - Diag(0, Context.getDiagAllocator()) { + BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) { } - AccessedEntity(ASTContext &Context, + AccessedEntity(ASTContext &Context, BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, @@ -353,6 +369,10 @@ public: CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); } CXXRecordDecl *getDerivedClass() const { return NamingClass; } + /// Retrieves the base object type, important when accessing + /// an instance member. + QualType getBaseObjectType() const { return BaseObjectType; } + /// Sets a diagnostic to be performed. The diagnostic is given /// four (additional) arguments: /// %0 - 0 if the entity was private, 1 if protected @@ -377,7 +397,8 @@ public: unsigned Access : 2; bool IsMember; NamedDecl *Target; - CXXRecordDecl *NamingClass; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; PartialDiagnostic Diag; }; @@ -484,14 +505,14 @@ public: /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. CXXRecordDecl *StdBadAlloc; - + /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// \brief The set of declarations that have been referenced within /// a potentially evaluated expression. - typedef std::vector<std::pair<SourceLocation, Decl *> > + typedef std::vector<std::pair<SourceLocation, Decl *> > PotentiallyReferencedDecls; /// \brief A set of diagnostics that may be emitted. @@ -522,8 +543,8 @@ public: PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, - unsigned NumTemporaries) - : Context(Context), NumTemporaries(NumTemporaries), + unsigned NumTemporaries) + : Context(Context), NumTemporaries(NumTemporaries), PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } void addReferencedDecl(SourceLocation Loc, Decl *Decl) { @@ -618,11 +639,11 @@ public: /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); - /// \brief Build a partial diagnostic. + /// \brief Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0) { return PartialDiagnostic(DiagID, Context.getDiagAllocator()); } - + virtual void DeleteExpr(ExprTy *E); virtual void DeleteStmt(StmtTy *S); @@ -646,13 +667,13 @@ public: void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); void PopFunctionOrBlockScope(); - + /// getLabelMap() - Return the current label map. If we're in a block, we /// return it. llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() { if (FunctionScopes.empty()) return TopFunctionScope.LabelMap; - + return FunctionScopes.back()->LabelMap; } @@ -661,24 +682,24 @@ public: llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() { if (FunctionScopes.empty()) return TopFunctionScope.SwitchStack; - + return FunctionScopes.back()->SwitchStack; } - /// \brief Determine whether the current function or block needs scope + /// \brief Determine whether the current function or block needs scope /// checking. bool &FunctionNeedsScopeChecking() { if (FunctionScopes.empty()) return TopFunctionScope.NeedsScopeChecking; - + return FunctionScopes.back()->NeedsScopeChecking; } - + bool hasAnyErrorsInThisFunction() const; - + /// \brief Retrieve the current block, if any. BlockScopeInfo *getCurBlock(); - + /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } @@ -708,7 +729,8 @@ public: QualType GetTypeForDeclarator(Declarator &D, Scope *S, TypeSourceInfo **TInfo = 0, TagDecl **OwnedDecl = 0); - TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo); /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo); DeclarationName GetNameForDeclarator(Declarator &D); @@ -745,7 +767,7 @@ public: const PartialDiagnostic &PD); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); - + QualType getQualifiedNameType(const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E); @@ -762,16 +784,16 @@ public: DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr); virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName = false, TypeTy *ObjectType = 0); virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); - virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, - const CXXScopeSpec *SS, + CXXScopeSpec *SS, TypeTy *&SuggestedType); - + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); } @@ -809,7 +831,12 @@ public: bool &OverloadableAttrRequired); void CheckMain(FunctionDecl *FD); virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); - virtual void ActOnObjCCatchParam(DeclPtrTy D); + ParmVarDecl *CheckParameter(DeclContext *DC, + TypeSourceInfo *TSInfo, QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + VarDecl::StorageClass StorageClass, + VarDecl::StorageClass StorageClassAsWritten); virtual void ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, ExprArg defarg); @@ -847,11 +874,21 @@ public: /// ParmVarDecl pointers. template<typename InputIterator> void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) { + if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == + Diagnostic::Ignored) + return; + + // Don't diagnose unused-parameter errors in template instantiations; we + // will already have done so in the template itself. + if (!ActiveTemplateInstantiations.empty()) + return; + for (; Param != ParamEnd; ++Param) { if (!(*Param)->isUsed() && (*Param)->getDeclName() && - !(*Param)->template hasAttr<UnusedAttr>()) + !(*Param)->template hasAttr<UnusedAttr>()) { Diag((*Param)->getLocation(), diag::warn_unused_parameter) << (*Param)->getDeclName(); + } } } @@ -877,7 +914,7 @@ public: const IdentifierInfo &Name); virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -911,12 +948,14 @@ public: Declarator *D = 0); enum CXXSpecialMember { - CXXDefaultConstructor = 0, + CXXInvalid = -1, + CXXConstructor = 0, CXXCopyConstructor = 1, CXXCopyAssignment = 2, CXXDestructor = 3 }; void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, DeclPtrTy IntfDecl, @@ -1034,7 +1073,7 @@ public: AA_Sending, AA_Casting }; - + /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are @@ -1058,9 +1097,7 @@ public: TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, - bool ForceRValue, - bool InOverloadResolution, - bool UserCast = false); + bool InOverloadResolution); bool IsStandardConversion(Expr *From, QualType ToType, bool InOverloadResolution, StandardConversionSequence& SCS); @@ -1072,24 +1109,27 @@ public: QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); + bool FunctionArgTypesAreEqual (FunctionProtoType* OldType, + FunctionProtoType* NewType); + bool CheckPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray& BasePath, bool IgnoreBaseAccess); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType); OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, OverloadCandidateSet& Conversions, - bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue, - bool UserCast = false); + bool AllowExplicit); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - + ImplicitConversionSequence::CompareKind CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, @@ -1107,18 +1147,13 @@ public: CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2); - ImplicitConversionSequence - TryCopyInitialization(Expr* From, QualType ToType, - bool SuppressUserConversions, bool ForceRValue, - bool InOverloadResolution); - OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, OwningExprResult Init); ImplicitConversionSequence TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, CXXRecordDecl *ActingContext); - bool PerformObjectArgumentInitialization(Expr *&From, + bool PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); @@ -1126,7 +1161,7 @@ public: ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); bool PerformContextuallyConvertToBool(Expr *&From); - bool PerformObjectMemberConversion(Expr *&From, + bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); @@ -1146,7 +1181,6 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, - bool ForceRValue = false, bool PartialOverloading = false); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, Expr **Args, unsigned NumArgs, @@ -1156,15 +1190,13 @@ public: QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversion = false, - bool ForceRValue = false); + bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -1172,15 +1204,13 @@ public: QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool ForceRValue = false); + bool SuppressUserConversions = false); void AddConversionCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -1197,11 +1227,6 @@ public: const FunctionProtoType *Proto, QualType ObjectTy, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet); - void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange = SourceRange()); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, Expr **Args, unsigned NumArgs, @@ -1254,18 +1279,18 @@ public: FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); Expr *FixOverloadedFunctionReference(Expr *E, - NamedDecl *FoundDecl, + DeclAccessPair FoundDecl, FunctionDecl *Fn); - OwningExprResult FixOverloadedFunctionReference(OwningExprResult, - NamedDecl *FoundDecl, + OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); - - OwningExprResult BuildOverloadedCallExpr(Expr *Fn, + + OwningExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -1305,7 +1330,7 @@ public: /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); - + /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); @@ -1374,9 +1399,7 @@ public: /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up the name of an Objective-C protocol. - LookupObjCProtocolName, - /// Look up the name of an Objective-C implementation - LookupObjCImplementationName + LookupObjCProtocolName }; /// \brief Specifies whether (or how) name lookup is being performed for a @@ -1400,6 +1423,7 @@ public: /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); @@ -1407,15 +1431,15 @@ public: bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); - bool LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, + bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); - ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II); + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); - + void ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, ADLResult &Functions); @@ -1425,10 +1449,34 @@ public: void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer); - bool CorrectTypo(LookupResult &R, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext = 0, - bool EnteringContext = false, - const ObjCObjectPointerType *OPT = 0); + /// \brief The context in which typo-correction occurs. + /// + /// The typo-correction context affects which keywords (if any) are + /// considered when trying to correct for typos. + enum CorrectTypoContext { + /// \brief An unknown context, where any keyword might be valid. + CTC_Unknown, + /// \brief A context where no keywords are used (e.g. we expect an actual + /// name). + CTC_NoKeywords, + /// \brief A context where we're correcting a type name. + CTC_Type, + /// \brief An expression context. + CTC_Expression, + /// \brief A type cast, or anything else that can be followed by a '<'. + CTC_CXXCasts, + /// \brief A member lookup context. + CTC_MemberLookup, + /// \brief The receiver of an Objective-C message send within an + /// Objective-C method where 'super' is a valid keyword. + CTC_ObjCMessageReceiver + }; + + DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext = 0, + bool EnteringContext = false, + CorrectTypoContext CTC = CTC_Unknown, + const ObjCObjectPointerType *OPT = 0); void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, AssociatedNamespaceSet &AssociatedNamespaces, @@ -1438,7 +1486,8 @@ public: //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, - SourceLocation RecoverLoc = SourceLocation()); + SourceLocation IdLoc, + bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); @@ -1482,7 +1531,7 @@ public: void ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); - + /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, @@ -1494,13 +1543,19 @@ public: void CollectImmediateProperties(ObjCContainerDecl *CDecl, llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// ProtocolConformsToSuperClass - Returns true if class has a super class + /// and it, or its nested super class conforms to the protocol. + bool ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl); + /// ProtocolConformsToProtocol - Returns true if 2nd Protocol (PDecl) is + /// qualified by the 1st. + bool ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl); + /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. - ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, + ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, IdentifierInfo *II); - - ObjCIvarDecl *SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII); /// Called by ActOnProperty to handle @property declarations in //// class extensions. @@ -1572,6 +1627,11 @@ public: /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); + + /// CollectIvarsToConstructOrDestruct - Collect those ivars which require + /// initialization. + void CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: @@ -1601,7 +1661,7 @@ public: FullExprArg CondVal, DeclPtrTy CondVar, StmtArg ThenVal, SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, + virtual OwningStmtResult ActOnStartOfSwitchStmt(FullExprArg Cond, DeclPtrTy CondVar); virtual void ActOnSwitchBodyError(SourceLocation SwitchLoc, StmtArg Switch, StmtArg Body); @@ -1619,7 +1679,7 @@ public: SourceLocation LParenLoc, StmtArg First, FullExprArg Second, DeclPtrTy SecondVar, - FullExprArg Third, + FullExprArg Third, SourceLocation RParenLoc, StmtArg Body); virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, @@ -1656,18 +1716,27 @@ public: SourceLocation RParenLoc, bool MSAsm = false); + + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, + IdentifierInfo *Name, SourceLocation NameLoc, + bool Invalid = false); + + virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D); + virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, - DeclPtrTy Parm, StmtArg Body, - StmtArg CatchList); + DeclPtrTy Parm, StmtArg Body); virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body); virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, - StmtArg Catch, StmtArg Finally); + MultiStmtArg Catch, + StmtArg Finally); + virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw); virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, Scope *CurScope); @@ -1717,17 +1786,17 @@ public: void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); - + // Primary Expressions. virtual SourceRange getExprRange(ExprTy *E) const; virtual OwningExprResult ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, bool HasTrailingLParen, bool IsAddressOfOperand); - bool DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, LookupResult &R); + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R); OwningExprResult LookupInObjCMethod(LookupResult &R, Scope *S, @@ -1739,7 +1808,7 @@ public: SourceLocation NameLoc, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); - + OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, const CXXScopeSpec *SS = 0); @@ -1761,7 +1830,7 @@ public: const LookupResult &R, bool HasTrailingLParen); - OwningExprResult BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, + OwningExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc); OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, @@ -1831,7 +1900,7 @@ public: QualType BaseType, SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, @@ -1843,11 +1912,12 @@ public: const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck = false); OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, bool &IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, DeclPtrTy ObjCImpDecl); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -1867,11 +1937,11 @@ public: virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Member, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen); - + virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, @@ -1954,6 +2024,11 @@ public: SourceLocation RPLoc); // "({..})" /// __builtin_offsetof(type, a.b[123][456].c) + OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, @@ -2011,7 +2086,7 @@ public: virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); @@ -2022,7 +2097,7 @@ public: SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); @@ -2043,7 +2118,7 @@ public: NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, @@ -2055,7 +2130,7 @@ public: AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -2078,28 +2153,21 @@ public: /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. - OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, - QualType DeclInitType, - CXXConstructorDecl *Constructor, - MultiExprArg Exprs, - bool RequiresZeroInit = false, - bool BaseInitialization = false); + OwningExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, MultiExprArg Exprs, + bool RequiresZeroInit = false, + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete); // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? - OwningExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, - QualType DeclInitType, - CXXConstructorDecl *Constructor, - bool Elidable, - MultiExprArg Exprs, - bool RequiresZeroInit = false, - bool BaseInitialization = false); - - OwningExprResult BuildCXXCastArgument(SourceLocation CastLoc, - QualType Ty, - CastExpr::CastKind Kind, - CXXMethodDecl *Method, - ExprArg Arg); + OwningExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, bool RequiresZeroInit = false, + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. @@ -2127,36 +2195,23 @@ public: CXXConstructorDecl *Constructor, unsigned TypeQuals); - /// DefineImplicitOverloadedAssign - Checks for feasibility of - /// defining implicit this overloaded assignment operator. - void DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl); - - /// getAssignOperatorMethod - Returns the default copy assignmment operator - /// for the class. - CXXMethodDecl *getAssignOperatorMethod(SourceLocation CurrentLocation, - ParmVarDecl *Decl, - CXXRecordDecl *ClassDecl); + /// \brief Defined and implicitly-declared copy assignment operator. + void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. OwningExprResult MaybeBindToTemporary(Expr *E); - CXXConstructorDecl * - TryInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, - InitializationKind Kind); - bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, - SourceLocation Loc, + SourceLocation Loc, ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); - + virtual TypeTy *getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, TypeTy *ObjectType, bool EnteringContext); @@ -2177,6 +2232,15 @@ public: SourceRange AngleBrackets, SourceRange Parens); + OwningExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + OwningExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + ExprArg Operand, + SourceLocation RParenLoc); + /// ActOnCXXTypeid - Parse typeid( something ). virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, @@ -2247,7 +2311,7 @@ public: QualType Argument, bool addMallocAttr = false); - bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator); /// ActOnCXXDelete - Parsed a C++ 'delete' expression @@ -2258,7 +2322,7 @@ public: virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); OwningExprResult CheckConditionVariable(VarDecl *ConditionVar); - + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support /// pseudo-functions. virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, @@ -2276,7 +2340,7 @@ public: OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, ExprArg MemExpr); - + OwningExprResult BuildPseudoDestructorExpr(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, @@ -2286,27 +2350,28 @@ public: SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType, bool HasTrailingLParen); - + virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName, bool HasTrailingLParen); - + /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is /// non-empty, will create a new CXXExprWithTemporaries expression. /// Otherwise, just returs the passed in expression. Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr); OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr); FullExpr CreateFullExpr(Expr *SubExpr); - + virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); - bool RequireCompleteDeclContext(const CXXScopeSpec &SS); + // Marks SS invalid if it represents an incomplete type. + bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, @@ -2323,13 +2388,13 @@ public: bool isAcceptableNestedNameSpecifier(NamedDecl *SD); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, + virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, TypeTy *ObjectType); - + CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -2339,7 +2404,7 @@ public: bool ErrorRecoveryLookup); virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -2347,11 +2412,11 @@ public: bool EnteringContext); virtual bool IsInvalidUnlessNestedName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext); - + /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier that involves a template-id, e.g., /// "foo::bar<int, float>::", and now we need to build a scope @@ -2374,7 +2439,7 @@ public: /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same @@ -2400,7 +2465,7 @@ public: unsigned NumStrings); Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, - QualType EncodedType, + TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, @@ -2432,8 +2497,7 @@ public: virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc); virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S, DeclPtrTy LinkageSpec, @@ -2455,7 +2519,7 @@ public: virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -2479,6 +2543,9 @@ public: bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors); + + void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as @@ -2494,28 +2561,28 @@ public: ClassesWithUnmarkedVirtualMembers; /// MaybeMarkVirtualMembersReferenced - If the passed in method is the - /// key function of the record decl, will mark virtual member functions as + /// key function of the record decl, will mark virtual member functions as /// referenced. void MaybeMarkVirtualMembersReferenced(SourceLocation Loc, CXXMethodDecl *MD); - + /// MarkVirtualMembersReferenced - Will mark all virtual members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); - /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes + /// ProcessPendingClassesWithUnmarkedVirtualMembers - Will process classes /// that might need to have their virtual members marked as referenced. /// Returns false if no work was done. bool ProcessPendingClassesWithUnmarkedVirtualMembers(); - - void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + void AddImplicitlyDeclaredMembersToClass(Scope *S, CXXRecordDecl *ClassDecl); virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, MemInitTy **MemInits, unsigned NumMemInits, bool AnyErrors); - void CheckCompletedCXXClass(CXXRecordDecl *Record); + void CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record); virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, @@ -2537,6 +2604,8 @@ public: ExprArg AssertExpr, ExprArg AssertMessageExpr); + FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc, + TypeSourceInfo *TSInfo); DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, @@ -2551,7 +2620,7 @@ public: void CheckConversionDeclarator(Declarator &D, QualType &R, FunctionDecl::StorageClass& SC); DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - + //===--------------------------------------------------------------------===// // C++ Derived Classes // @@ -2562,14 +2631,14 @@ public: bool Virtual, AccessSpecifier Access, QualType BaseType, SourceLocation BaseLoc); - - /// SetClassDeclAttributesFromBase - Copies class decl traits - /// (such as whether the class has a trivial constructor, + + /// SetClassDeclAttributesFromBase - Copies class decl traits + /// (such as whether the class has a trivial constructor, /// trivial destructor etc) from the given base class. void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, const CXXRecordDecl *BaseClass, bool BaseIsVirtual); - + virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, @@ -2583,15 +2652,21 @@ public: bool IsDerivedFrom(QualType Derived, QualType Base); bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); - + + // FIXME: I don't like this name. + void BuildBasePathArray(const CXXBasePaths &Paths, + CXXBaseSpecifierArray &BasePath); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, + CXXBaseSpecifierArray *BasePath = 0, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, - DeclarationName Name); + DeclarationName Name, + CXXBaseSpecifierArray *BasePath); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); @@ -2636,6 +2711,7 @@ public: DeclAccessPair FoundDecl); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, + const InitializedEntity &Entity, AccessSpecifier Access); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, @@ -2691,23 +2767,23 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - void LookupTemplateName(LookupResult &R, Scope *S, const CXXScopeSpec &SS, + void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext); virtual TemplateNameKind isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); - - virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + + virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); - + bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); @@ -2765,10 +2841,11 @@ public: const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, @@ -2776,7 +2853,7 @@ public: void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); - + QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs); @@ -2796,13 +2873,13 @@ public: LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo &TemplateArgs); - OwningExprResult BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, + OwningExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &TemplateArgs); virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext); @@ -2815,7 +2892,7 @@ public: virtual DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -2839,12 +2916,16 @@ public: TemplateSpecializationKind PrevTSK, SourceLocation PrevPointOfInstantiation, bool &SuppressNew); - + + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); - + virtual DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -2865,7 +2946,7 @@ public: SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); @@ -2874,8 +2955,8 @@ public: SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); - - TemplateArgumentLoc + + TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, @@ -2905,7 +2986,7 @@ public: SourceLocation RAngleLoc, TemplateArgumentListBuilder &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo &TemplateArgs, @@ -2918,23 +2999,23 @@ public: bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); - bool CheckTemplateArgumentPointerToMember(Expr *Arg, + bool CheckTemplateArgumentPointerToMember(Expr *Arg, TemplateArgument &Converted); bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, const TemplateArgumentLoc &Arg); - OwningExprResult + OwningExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); - OwningExprResult + OwningExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); - + /// \brief Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { @@ -2946,7 +3027,7 @@ public: /// template<typename T> struct X; /// \endcode TPL_TemplateMatch, - + /// \brief We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. @@ -2956,7 +3037,7 @@ public: /// template<template<int Value> class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, - + /// \brief We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. @@ -2968,7 +3049,7 @@ public: /// \endcode TPL_TemplateTemplateArgumentMatch }; - + bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, @@ -3001,12 +3082,15 @@ public: ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TypeTy *Ty); - QualType CheckTypenameType(NestedNameSpecifier *NNS, + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range); - QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, - DeclarationName Name); + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name); + bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, @@ -3016,7 +3100,7 @@ public: getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); - + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of @@ -3205,27 +3289,28 @@ public: const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag); - + ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); - + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl<bool> &Used); void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVectorImpl<bool> &Deduced); - + //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = 0, - bool RelativeToPrimary = false); + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = 0); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { @@ -3257,12 +3342,12 @@ public: /// Entity is either a ClassTemplatePartialSpecializationDecl or /// a FunctionTemplateDecl. DeducedTemplateArgumentSubstitution, - + /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, - + /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking @@ -3274,7 +3359,7 @@ public: /// \brief The template in which we are performing the instantiation, /// for substitutions of prior template arguments. TemplateDecl *Template; - + /// \brief The entity that is being instantiated. uintptr_t Entity; @@ -3291,13 +3376,13 @@ public: SourceRange InstantiationRange; ActiveTemplateInstantiation() - : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), + : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), NumTemplateArgs(0) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; - + friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) @@ -3314,9 +3399,9 @@ public: case DefaultTemplateArgumentChecking: if (X.Template != Y.Template) return false; - + // Fall through - + case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: @@ -3347,7 +3432,7 @@ public: /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. unsigned NonInstantiationEntries; - + /// \brief The last template from which a template instantiation /// error or warning was produced. /// @@ -3422,7 +3507,7 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); - + /// \brief Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -3431,8 +3516,8 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, SourceRange InstantiationRange); - - + + /// \brief Note that we have finished instantiating this template. void Clear(); @@ -3510,7 +3595,7 @@ public: /// instantiated ParmVarDecl for 'x'. llvm::DenseMap<const Decl *, Decl *> LocalDecls; - /// \brief The outer scope, in which contains local variable + /// \brief The outer scope, which contains local variable /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; @@ -3518,54 +3603,36 @@ public: /// \brief Whether we have already exited this scope. bool Exited; - /// \brief Whether this scope is temporary, meaning that we should - /// remove any additions we make once we exit this - /// scope. Temporary scopes are always combined with their outer - /// scopes. - bool Temporary; - - /// \brief List of the declarations that we have added into this - /// temporary scope. They will be removed when we exit the - /// temporary scope. - llvm::SmallVector<const Decl *, 4> AddedTemporaryDecls; - + /// \brief Whether to combine this scope with the outer scope, such that + /// lookup will search our outer scope. + bool CombineWithOuterScope; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false, - bool Temporary = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false), Temporary(Temporary) { - if (!CombineWithOuterScope && !Temporary) - SemaRef.CurrentInstantiationScope = this; - else - assert(SemaRef.CurrentInstantiationScope && - "No outer instantiation scope?"); + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false), CombineWithOuterScope(CombineWithOuterScope) + { + SemaRef.CurrentInstantiationScope = this; } ~LocalInstantiationScope() { - if (!Exited) { - SemaRef.CurrentInstantiationScope = Outer; - for (unsigned I = 0, N = AddedTemporaryDecls.size(); I != N; ++I) - LocalDecls.erase(AddedTemporaryDecls[I]); - } + Exit(); } /// \brief Exit this local instantiation scope early. void Exit() { + if (Exited) + return; + SemaRef.CurrentInstantiationScope = Outer; - LocalDecls.clear(); Exited = true; } - Decl *getInstantiationOf(const Decl *D) { - Decl *Result = LocalDecls[D]; - assert((Result || D->isInvalidDecl()) && - "declaration was not instantiated in this scope!"); - return Result; - } + Decl *getInstantiationOf(const Decl *D); VarDecl *getInstantiationOf(const VarDecl *Var) { return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var))); @@ -3579,16 +3646,8 @@ public: const NonTypeTemplateParmDecl *Var) { return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); } - - void InstantiatedLocal(const Decl *D, Decl *Inst) { - Decl *&Stored = LocalDecls[D]; - assert((!Stored || Stored == Inst) && "Already instantiated this local"); - if (Temporary && !Stored) - AddedTemporaryDecls.push_back(D); - - Stored = Inst; - } + void InstantiatedLocal(const Decl *D, Decl *Inst); }; /// \brief The current instantiation scope used to store local @@ -3634,6 +3693,12 @@ public: const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity); + ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs); OwningExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); @@ -3701,8 +3766,6 @@ public: DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); - bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params); - // Objective-C declarations. virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, @@ -3823,7 +3886,7 @@ public: // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, - llvm::SmallVectorImpl<Declarator> &Cdecls, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic = false); @@ -3836,28 +3899,66 @@ public: ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, ObjCInterfaceDecl *ClassDecl); - virtual OwningExprResult ActOnClassPropertyRefExpr( - IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation &receiverNameLoc, - SourceLocation &propertyNameLoc); - - // ActOnClassMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnClassMessage( - Scope *S, - IdentifierInfo *receivingClassName, Selector Sel, SourceLocation lbrac, - SourceLocation receiverLoc, SourceLocation selectorLoc,SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); - - // ActOnInstanceMessage - used for both unary and keyword messages. - // ArgExprs is optional - if it is present, the number of expressions - // is obtained from NumArgs. - virtual ExprResult ActOnInstanceMessage( - ExprTy *receiver, Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, - ExprTy **ArgExprs, unsigned NumArgs); + OwningExprResult + HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, + DeclarationName MemberName, + SourceLocation MemberLoc); + + virtual OwningExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc); + + virtual ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType); + + virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + OwningExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + virtual OwningExprResult ActOnClassMessage(Scope *S, + TypeTy *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + OwningExprResult BuildInstanceMessage(ExprArg Receiver, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + + virtual OwningExprResult ActOnInstanceMessage(Scope *S, + ExprArg Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args); + /// ActOnPragmaPack - Called on well formed #pragma pack(...). virtual void ActOnPragmaPack(PragmaPackKind Kind, @@ -3900,7 +4001,9 @@ public: /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind, - bool isLvalue = false); + bool isLvalue = false, + CXXBaseSpecifierArray BasePath = + CXXBaseSpecifierArray()); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). @@ -3985,11 +4088,11 @@ public: /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, - + /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two - /// levels differ e.g. char ** -> const char **, but we accept them as an - /// extension. + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that @@ -4013,14 +4116,15 @@ public: /// represent it in the AST. Incompatible }; - + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, AssignmentAction Action); + Expr *SrcExpr, AssignmentAction Action, + bool *Complained = 0); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. @@ -4056,12 +4160,10 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, - bool AllowExplicit = false, - bool Elidable = false); + bool AllowExplicit = false); bool PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, - bool Elidable, ImplicitConversionSequence& ICS); bool PerformImplicitConversion(Expr *&From, QualType ToType, const ImplicitConversionSequence& ICS, @@ -4106,12 +4208,12 @@ public: Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType FindCompositePointerType(Expr *&E1, Expr *&E2, + QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType = 0); QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, SourceLocation questionLoc); - + /// type checking for vector binary operators. inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); inline QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, @@ -4120,7 +4222,7 @@ public: /// type checking unary operators (subroutines of ActOnUnaryOp). /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, - bool isInc); + bool isInc, bool isPrefix); QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); @@ -4162,19 +4264,10 @@ public: QualType T1, QualType T2, bool& DerivedToBase); - bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType, - SourceLocation DeclLoc, - bool SuppressUserConversions, - bool AllowExplicit, - bool ForceRValue, - ImplicitConversionSequence *ICS = 0, - bool IgnoreBaseAccess = false); - /// CheckCastTypes - Check type constraints for casting between types under /// C semantics, or forward to CXXCheckCStyleCast in C++. bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, - CXXMethodDecl *& ConversionDecl, + CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath, bool FunctionalStyle = false); // CheckVectorCast - check type constraints for vectors. @@ -4195,8 +4288,9 @@ public: /// CXXCheckCStyleCast - Check constraints of a C-style or function-style /// cast under C++ semantics. bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, bool FunctionalStyle, - CXXMethodDecl *&ConversionDecl); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, + bool FunctionalStyle); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. @@ -4253,7 +4347,7 @@ public: /// \name Code completion //@{ - virtual void CodeCompleteOrdinaryName(Scope *S, + virtual void CodeCompleteOrdinaryName(Scope *S, CodeCompletionContext CompletionContext); virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, SourceLocation OpLoc, @@ -4262,14 +4356,14 @@ public: virtual void CodeCompleteCase(Scope *S); virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, ExprTy **Args, unsigned NumArgs); - virtual void CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, + virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext); virtual void CodeCompleteUsing(Scope *S); virtual void CodeCompleteUsingDirective(Scope *S); virtual void CodeCompleteNamespaceDecl(Scope *S); virtual void CodeCompleteNamespaceAliasDecl(Scope *S); virtual void CodeCompleteOperatorName(Scope *S); - + virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, bool InInterface); virtual void CodeCompleteObjCAtVisibility(Scope *S); @@ -4283,9 +4377,11 @@ public: DeclPtrTy *Methods, unsigned NumMethods); - virtual void CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc, - IdentifierInfo **SelIdents, + virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); + virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, + IdentifierInfo **SelIdents, unsigned NumSelIdents); virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, @@ -4294,20 +4390,27 @@ public: unsigned NumProtocols); virtual void CodeCompleteObjCProtocolDecl(Scope *S); virtual void CodeCompleteObjCInterfaceDecl(Scope *S); - virtual void CodeCompleteObjCSuperclass(Scope *S, - IdentifierInfo *ClassName); + virtual void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); virtual void CodeCompleteObjCImplementationDecl(Scope *S); - virtual void CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName); - virtual void CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName); - virtual void CodeCompleteObjCPropertyDefinition(Scope *S, + virtual void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + virtual void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + virtual void CodeCompleteObjCPropertyDefinition(Scope *S, DeclPtrTy ObjCImpDecl); - virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName, DeclPtrTy ObjCImpDecl); + virtual void CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnType, + DeclPtrTy IDecl); //@} - + //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system @@ -4327,7 +4430,6 @@ private: bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); - bool SemaBuiltinStackAddress(CallExpr *TheCall); public: // Used by C++ template instantiation. @@ -4338,7 +4440,8 @@ private: bool SemaBuiltinObjectSize(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinAtomicOverloaded(CallExpr *TheCall); - bool SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall); + bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result); bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index f628884..444ee79 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "SemaInit.h" #include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -22,6 +23,13 @@ using namespace clang; +/// A copy of Sema's enum without AR_delayed. +enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent +}; + /// SetMemberAccessSpecifier - Set the access specifier of a member. /// Returns true on error (when the previous member decl access specifier /// is different from the new member decl access specifier). @@ -51,6 +59,20 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, return false; } +static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { + DeclContext *DC = D->getDeclContext(); + + // This can only happen at top: enum decls only "publish" their + // immediate members. + if (isa<EnumDecl>(DC)) + DC = cast<EnumDecl>(DC)->getDeclContext(); + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); + while (DeclaringClass->isAnonymousStructOrUnion()) + DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); + return DeclaringClass; +} + namespace { struct EffectiveContext { EffectiveContext() : Inner(0), Dependent(false) {} @@ -109,22 +131,168 @@ struct EffectiveContext { llvm::SmallVector<CXXRecordDecl*, 4> Records; bool Dependent; }; + +/// Like Sema's AccessedEntity, but kindly lets us scribble all over +/// it. +struct AccessTarget : public Sema::AccessedEntity { + AccessTarget(const Sema::AccessedEntity &Entity) + : AccessedEntity(Entity) { + initialize(); + } + + AccessTarget(ASTContext &Context, + MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : AccessedEntity(Context, Member, NamingClass, FoundDecl, BaseObjectType) { + initialize(); + } + + AccessTarget(ASTContext &Context, + BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : AccessedEntity(Context, Base, BaseClass, DerivedClass, Access) { + initialize(); + } + + bool hasInstanceContext() const { + return HasInstanceContext; + } + + class SavedInstanceContext { + public: + ~SavedInstanceContext() { + Target.HasInstanceContext = Has; + } + + private: + friend struct AccessTarget; + explicit SavedInstanceContext(AccessTarget &Target) + : Target(Target), Has(Target.HasInstanceContext) {} + AccessTarget &Target; + bool Has; + }; + + SavedInstanceContext saveInstanceContext() { + return SavedInstanceContext(*this); + } + + void suppressInstanceContext() { + HasInstanceContext = false; + } + + const CXXRecordDecl *resolveInstanceContext(Sema &S) const { + assert(HasInstanceContext); + if (CalculatedInstanceContext) + return InstanceContext; + + CalculatedInstanceContext = true; + DeclContext *IC = S.computeDeclContext(getBaseObjectType()); + InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() : 0); + return InstanceContext; + } + + const CXXRecordDecl *getDeclaringClass() const { + return DeclaringClass; + } + +private: + void initialize() { + HasInstanceContext = (isMemberAccess() && + !getBaseObjectType().isNull() && + getTargetDecl()->isCXXInstanceMember()); + CalculatedInstanceContext = false; + InstanceContext = 0; + + if (isMemberAccess()) + DeclaringClass = FindDeclaringClass(getTargetDecl()); + else + DeclaringClass = getBaseClass(); + DeclaringClass = DeclaringClass->getCanonicalDecl(); + } + + bool HasInstanceContext : 1; + mutable bool CalculatedInstanceContext : 1; + mutable const CXXRecordDecl *InstanceContext; + const CXXRecordDecl *DeclaringClass; +}; + } -static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { - DeclContext *DC = D->getDeclContext(); +/// Checks whether one class might instantiate to the other. +static bool MightInstantiateTo(const CXXRecordDecl *From, + const CXXRecordDecl *To) { + // Declaration names are always preserved by instantiation. + if (From->getDeclName() != To->getDeclName()) + return false; - // This can only happen at top: enum decls only "publish" their - // immediate members. - if (isa<EnumDecl>(DC)) - DC = cast<EnumDecl>(DC)->getDeclContext(); + const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); + const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); + if (FromDC == ToDC) return true; + if (FromDC->isFileContext() || ToDC->isFileContext()) return false; - CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); - while (DeclaringClass->isAnonymousStructOrUnion()) - DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); - return DeclaringClass; + // Be conservative. + return true; } +/// Checks whether one class is derived from another, inclusively. +/// Properly indicates when it couldn't be determined due to +/// dependence. +/// +/// This should probably be donated to AST or at least Sema. +static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, + const CXXRecordDecl *Target) { + assert(Derived->getCanonicalDecl() == Derived); + assert(Target->getCanonicalDecl() == Target); + + if (Derived == Target) return AR_accessible; + + bool CheckDependent = Derived->isDependentContext(); + if (CheckDependent && MightInstantiateTo(Derived, Target)) + return AR_dependent; + + AccessResult OnFailure = AR_inaccessible; + llvm::SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack + + while (true) { + for (CXXRecordDecl::base_class_const_iterator + I = Derived->bases_begin(), E = Derived->bases_end(); I != E; ++I) { + + const CXXRecordDecl *RD; + + QualType T = I->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + RD = cast<CXXRecordDecl>(RT->getDecl()); + } else if (const InjectedClassNameType *IT + = T->getAs<InjectedClassNameType>()) { + RD = IT->getDecl(); + } else { + assert(T->isDependentType() && "non-dependent base wasn't a record?"); + OnFailure = AR_dependent; + continue; + } + + RD = RD->getCanonicalDecl(); + if (RD == Target) return AR_accessible; + if (CheckDependent && MightInstantiateTo(RD, Target)) + OnFailure = AR_dependent; + + Queue.push_back(RD); + } + + if (Queue.empty()) break; + + Derived = Queue.back(); + Queue.pop_back(); + } + + return OnFailure; +} + + static bool MightInstantiateTo(Sema &S, DeclContext *Context, DeclContext *Friend) { if (Friend == Context) @@ -204,11 +372,11 @@ static bool MightInstantiateTo(Sema &S, Friend->getTemplatedDecl()); } -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *Friend) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Friend) { if (EC.includesClass(Friend)) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent()) { CanQualType FriendTy @@ -219,32 +387,32 @@ static Sema::AccessResult MatchesFriend(Sema &S, CanQualType ContextTy = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); if (MightInstantiateTo(S, ContextTy, FriendTy)) - return Sema::AR_dependent; + return AR_dependent; } } - return Sema::AR_inaccessible; + return AR_inaccessible; } -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - CanQualType Friend) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + CanQualType Friend) { if (const RecordType *RT = Friend->getAs<RecordType>()) return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); // TODO: we can do better than this if (Friend->isDependentType()) - return Sema::AR_dependent; + return AR_dependent; - return Sema::AR_inaccessible; + return AR_inaccessible; } /// Determines whether the given friend class template matches /// anything in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - ClassTemplateDecl *Friend) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + ClassTemplateDecl *Friend) { + AccessResult OnFailure = AR_inaccessible; // Check whether the friend is the template of a class in the // context chain. @@ -268,7 +436,7 @@ static Sema::AccessResult MatchesFriend(Sema &S, // It's a match. if (Friend == CTD->getCanonicalDecl()) - return Sema::AR_accessible; + return AR_accessible; // If the context isn't dependent, it can't be a dependent match. if (!EC.isDependent()) @@ -286,7 +454,7 @@ static Sema::AccessResult MatchesFriend(Sema &S, continue; // Otherwise, it's a dependent match. - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -294,18 +462,18 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend function matches anything in /// the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FunctionDecl *Friend) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionDecl *Friend) { + AccessResult OnFailure = AR_inaccessible; for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { if (Friend == *I) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -313,12 +481,12 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend function template matches /// anything in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FunctionTemplateDecl *Friend) { - if (EC.Functions.empty()) return Sema::AR_inaccessible; +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FunctionTemplateDecl *Friend) { + if (EC.Functions.empty()) return AR_inaccessible; - Sema::AccessResult OnFailure = Sema::AR_inaccessible; + AccessResult OnFailure = AR_inaccessible; for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { @@ -332,10 +500,10 @@ static Sema::AccessResult MatchesFriend(Sema &S, FTD = FTD->getCanonicalDecl(); if (Friend == FTD) - return Sema::AR_accessible; + return AR_accessible; if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) - OnFailure = Sema::AR_dependent; + OnFailure = AR_dependent; } return OnFailure; @@ -343,9 +511,9 @@ static Sema::AccessResult MatchesFriend(Sema &S, /// Determines whether the given friend declaration matches anything /// in the effective context. -static Sema::AccessResult MatchesFriend(Sema &S, - const EffectiveContext &EC, - FriendDecl *FriendD) { +static AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *FriendD) { if (TypeSourceInfo *T = FriendD->getFriendType()) return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); @@ -367,10 +535,10 @@ static Sema::AccessResult MatchesFriend(Sema &S, return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); } -static Sema::AccessResult GetFriendKind(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *Class) { - Sema::AccessResult OnFailure = Sema::AR_inaccessible; +static AccessResult GetFriendKind(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Class) { + AccessResult OnFailure = AR_inaccessible; // Okay, check friends. for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), @@ -378,18 +546,15 @@ static Sema::AccessResult GetFriendKind(Sema &S, FriendDecl *Friend = *I; switch (MatchesFriend(S, EC, Friend)) { - case Sema::AR_accessible: - return Sema::AR_accessible; + case AR_accessible: + return AR_accessible; - case Sema::AR_inaccessible: - break; + case AR_inaccessible: + continue; - case Sema::AR_dependent: - OnFailure = Sema::AR_dependent; + case AR_dependent: + OnFailure = AR_dependent; break; - - case Sema::AR_delayed: - llvm_unreachable("cannot get delayed answer from MatchesFriend"); } } @@ -397,16 +562,19 @@ static Sema::AccessResult GetFriendKind(Sema &S, return OnFailure; } -static Sema::AccessResult HasAccess(Sema &S, - const EffectiveContext &EC, - const CXXRecordDecl *NamingClass, - AccessSpecifier Access) { +static AccessResult HasAccess(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *NamingClass, + AccessSpecifier Access, + const AccessTarget &Target) { assert(NamingClass->getCanonicalDecl() == NamingClass && "declaration should be canonicalized before being passed here"); - if (Access == AS_public) return Sema::AR_accessible; + if (Access == AS_public) return AR_accessible; assert(Access == AS_private || Access == AS_protected); + AccessResult OnFailure = AR_inaccessible; + for (EffectiveContext::record_iterator I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { // All the declarations in EC have been canonicalized, so pointer @@ -414,16 +582,78 @@ static Sema::AccessResult HasAccess(Sema &S, const CXXRecordDecl *ECRecord = *I; // [B2] and [M2] - if (ECRecord == NamingClass) - return Sema::AR_accessible; + if (Access == AS_private) { + if (ECRecord == NamingClass) + return AR_accessible; + + if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) + OnFailure = AR_dependent; // [B3] and [M3] - if (Access == AS_protected && - ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass))) - return Sema::AR_accessible; + } else { + assert(Access == AS_protected); + switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { + case AR_accessible: break; + case AR_inaccessible: continue; + case AR_dependent: OnFailure = AR_dependent; continue; + } + + if (!Target.hasInstanceContext()) + return AR_accessible; + + const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); + if (!InstanceContext) { + OnFailure = AR_dependent; + continue; + } + + // C++ [class.protected]p1: + // An additional access check beyond those described earlier in + // [class.access] is applied when a non-static data member or + // non-static member function is a protected member of its naming + // class. As described earlier, access to a protected member is + // granted because the reference occurs in a friend or member of + // some class C. If the access is to form a pointer to member, + // the nested-name-specifier shall name C or a class derived from + // C. All other accesses involve a (possibly implicit) object + // expression. In this case, the class of the object expression + // shall be C or a class derived from C. + // + // We interpret this as a restriction on [M3]. Most of the + // conditions are encoded by not having any instance context. + switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { + case AR_accessible: return AR_accessible; + case AR_inaccessible: continue; + case AR_dependent: OnFailure = AR_dependent; continue; + } + } } - return GetFriendKind(S, EC, NamingClass); + if (!NamingClass->hasFriends()) + return OnFailure; + + // Don't consider friends if we're under the [class.protected] + // restriction, above. + if (Access == AS_protected && Target.hasInstanceContext()) { + const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); + if (!InstanceContext) return AR_dependent; + + switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) { + case AR_accessible: break; + case AR_inaccessible: return OnFailure; + case AR_dependent: return AR_dependent; + } + } + + switch (GetFriendKind(S, EC, NamingClass)) { + case AR_accessible: return AR_accessible; + case AR_inaccessible: return OnFailure; + case AR_dependent: return AR_dependent; + } + + // Silence bogus warnings + llvm_unreachable("impossible friendship kind"); + return OnFailure; } /// Finds the best path from the naming class to the declaring class, @@ -479,17 +709,21 @@ static Sema::AccessResult HasAccess(Sema &S, /// /// B is an accessible base of N at R iff ACAB(1) = public. /// -/// \param FinalAccess the access of the "final step", or AS_none if +/// \param FinalAccess the access of the "final step", or AS_public if /// there is no final step. /// \return null if friendship is dependent static CXXBasePath *FindBestPath(Sema &S, const EffectiveContext &EC, - CXXRecordDecl *Derived, - CXXRecordDecl *Base, + AccessTarget &Target, AccessSpecifier FinalAccess, CXXBasePaths &Paths) { // Derive the paths to the desired base. - bool isDerived = Derived->isDerivedFrom(Base, Paths); + const CXXRecordDecl *Derived = Target.getNamingClass(); + const CXXRecordDecl *Base = Target.getDeclaringClass(); + + // FIXME: fail correctly when there are dependent paths. + bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), + Paths); assert(isDerived && "derived class not actually derived from base"); (void) isDerived; @@ -502,6 +736,7 @@ static CXXBasePath *FindBestPath(Sema &S, // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { + AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); // Walk through the path backwards. AccessSpecifier PathAccess = FinalAccess; @@ -519,16 +754,23 @@ static CXXBasePath *FindBestPath(Sema &S, break; } + const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); + AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); PathAccess = std::max(PathAccess, BaseAccess); - switch (HasAccess(S, EC, I->Class, PathAccess)) { - case Sema::AR_inaccessible: break; - case Sema::AR_accessible: PathAccess = AS_public; break; - case Sema::AR_dependent: + + switch (HasAccess(S, EC, NC, PathAccess, Target)) { + case AR_inaccessible: break; + case AR_accessible: + PathAccess = AS_public; + + // Future tests are not against members and so do not have + // instance context. + Target.suppressInstanceContext(); + break; + case AR_dependent: AnyDependent = true; goto Next; - case Sema::AR_delayed: - llvm_unreachable("friend resolution is never delayed"); break; } } @@ -561,46 +803,36 @@ static CXXBasePath *FindBestPath(Sema &S, /// to become inaccessible. static void DiagnoseAccessPath(Sema &S, const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { AccessSpecifier Access = Entity.getAccess(); - CXXRecordDecl *NamingClass = Entity.getNamingClass(); + const CXXRecordDecl *NamingClass = Entity.getNamingClass(); NamingClass = NamingClass->getCanonicalDecl(); - NamedDecl *D; - CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - D = Entity.getTargetDecl(); - DeclaringClass = FindDeclaringClass(D); - } else { - D = 0; - DeclaringClass = Entity.getBaseClass(); - } - DeclaringClass = DeclaringClass->getCanonicalDecl(); + NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); // Easy case: the decl's natural access determined its path access. // We have to check against AS_private here in case Access is AS_none, // indicating a non-public member of a private base class. if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { - switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) { - case Sema::AR_inaccessible: { + switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) { + case AR_inaccessible: { S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) << /*FIXME: not implicitly*/ 0; return; } - case Sema::AR_accessible: break; + case AR_accessible: break; - case Sema::AR_dependent: - case Sema::AR_delayed: - llvm_unreachable("dependent/delayed not allowed"); + case AR_dependent: + llvm_unreachable("can't diagnose dependent access failures"); return; } } CXXBasePaths Paths; - CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, - AS_public, Paths); + CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths); CXXBasePath::iterator I = Path.end(), E = Path.begin(); while (I != E) { @@ -615,12 +847,10 @@ static void DiagnoseAccessPath(Sema &S, continue; switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_accessible: continue; - case Sema::AR_inaccessible: break; - - case Sema::AR_dependent: - case Sema::AR_delayed: - llvm_unreachable("dependent friendship, should not be diagnosing"); + case AR_accessible: continue; + case AR_inaccessible: break; + case AR_dependent: + llvm_unreachable("can't diagnose dependent access failures"); } // Check whether this base specifier is the tighest point @@ -649,17 +879,10 @@ static void DiagnoseAccessPath(Sema &S, static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { const CXXRecordDecl *NamingClass = Entity.getNamingClass(); - NamedDecl *D; - const CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - D = Entity.getTargetDecl(); - DeclaringClass = FindDeclaringClass(D); - } else { - D = 0; - DeclaringClass = Entity.getBaseClass(); - } + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); + NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0); S.Diag(Loc, Entity.getDiag()) << (Entity.getAccess() == AS_protected) @@ -671,9 +894,9 @@ static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, /// Determines whether the accessed entity is accessible. Public members /// have been weeded out by this point. -static Sema::AccessResult IsAccessible(Sema &S, - const EffectiveContext &EC, - const Sema::AccessedEntity &Entity) { +static AccessResult IsAccessible(Sema &S, + const EffectiveContext &EC, + AccessTarget &Entity) { // Determine the actual naming class. CXXRecordDecl *NamingClass = Entity.getNamingClass(); while (NamingClass->isAnonymousStructOrUnion()) @@ -686,10 +909,10 @@ static Sema::AccessResult IsAccessible(Sema &S, // Before we try to recalculate access paths, try to white-list // accesses which just trade in on the final step, i.e. accesses // which don't require [M4] or [B4]. These are by far the most - // common forms of access. + // common forms of privileged access. if (UnprivilegedAccess != AS_none) { - switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) { - case Sema::AR_dependent: + switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { + case AR_dependent: // This is actually an interesting policy decision. We don't // *have* to delay immediately here: we can do the full access // calculation in the hope that friendship on some intermediate @@ -697,23 +920,14 @@ static Sema::AccessResult IsAccessible(Sema &S, // But that's not cheap, and odds are very good (note: assertion // made without data) that the friend declaration will determine // access. - return Sema::AR_dependent; + return AR_dependent; - case Sema::AR_accessible: return Sema::AR_accessible; - case Sema::AR_inaccessible: break; - case Sema::AR_delayed: - llvm_unreachable("friendship never subject to contextual delay"); + case AR_accessible: return AR_accessible; + case AR_inaccessible: break; } } - // Determine the declaring class. - CXXRecordDecl *DeclaringClass; - if (Entity.isMemberAccess()) { - DeclaringClass = FindDeclaringClass(Entity.getTargetDecl()); - } else { - DeclaringClass = Entity.getBaseClass(); - } - DeclaringClass = DeclaringClass->getCanonicalDecl(); + AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); // We lower member accesses to base accesses by pretending that the // member is a base class of its declaring class. @@ -723,43 +937,44 @@ static Sema::AccessResult IsAccessible(Sema &S, // Determine if the declaration is accessible from EC when named // in its declaring class. NamedDecl *Target = Entity.getTargetDecl(); + const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); FinalAccess = Target->getAccess(); - switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) { - case Sema::AR_accessible: FinalAccess = AS_public; break; - case Sema::AR_inaccessible: break; - case Sema::AR_dependent: return Sema::AR_dependent; // see above - case Sema::AR_delayed: llvm_unreachable("friend status is never delayed"); + switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { + case AR_accessible: + FinalAccess = AS_public; + break; + case AR_inaccessible: break; + case AR_dependent: return AR_dependent; // see above } if (DeclaringClass == NamingClass) - return (FinalAccess == AS_public - ? Sema::AR_accessible - : Sema::AR_inaccessible); + return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); + + Entity.suppressInstanceContext(); } else { FinalAccess = AS_public; } - assert(DeclaringClass != NamingClass); + assert(Entity.getDeclaringClass() != NamingClass); // Append the declaration's access if applicable. CXXBasePaths Paths; - CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass, - FinalAccess, Paths); + CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); if (!Path) - return Sema::AR_dependent; + return AR_dependent; assert(Path->Access <= UnprivilegedAccess && "access along best path worse than direct?"); if (Path->Access == AS_public) - return Sema::AR_accessible; - return Sema::AR_inaccessible; + return AR_accessible; + return AR_inaccessible; } -static void DelayAccess(Sema &S, - const EffectiveContext &EC, - SourceLocation Loc, - const Sema::AccessedEntity &Entity) { +static void DelayDependentAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + const AccessTarget &Entity) { assert(EC.isDependent() && "delaying non-dependent access"); DeclContext *DC = EC.getInnerContext(); assert(DC->isDependentContext() && "delaying non-dependent access"); @@ -769,48 +984,38 @@ static void DelayAccess(Sema &S, Entity.getAccess(), Entity.getTargetDecl(), Entity.getNamingClass(), + Entity.getBaseObjectType(), Entity.getDiag()); } /// Checks access to an entity from the given effective context. -static Sema::AccessResult CheckEffectiveAccess(Sema &S, - const EffectiveContext &EC, - SourceLocation Loc, - const Sema::AccessedEntity &Entity) { +static AccessResult CheckEffectiveAccess(Sema &S, + const EffectiveContext &EC, + SourceLocation Loc, + AccessTarget &Entity) { assert(Entity.getAccess() != AS_public && "called for public access!"); switch (IsAccessible(S, EC, Entity)) { - case Sema::AR_dependent: - DelayAccess(S, EC, Loc, Entity); - return Sema::AR_dependent; - - case Sema::AR_delayed: - llvm_unreachable("IsAccessible cannot contextually delay"); + case AR_dependent: + DelayDependentAccess(S, EC, Loc, Entity); + return AR_dependent; - case Sema::AR_inaccessible: + case AR_inaccessible: if (!Entity.isQuiet()) DiagnoseBadAccess(S, Loc, EC, Entity); - return Sema::AR_inaccessible; - - case Sema::AR_accessible: - break; - } + return AR_inaccessible; - // We only consider the natural access of the declaration when - // deciding whether to do the protected check. - if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) { - NamedDecl *D = Entity.getTargetDecl(); - if (isa<FieldDecl>(D) || - (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) { - // FIXME: implement [class.protected] - } + case AR_accessible: + return AR_accessible; } - return Sema::AR_accessible; + // silence unnecessary warning + llvm_unreachable("invalid access result"); + return AR_accessible; } static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, - const Sema::AccessedEntity &Entity) { + AccessTarget &Entity) { // If the access path is public, it's accessible everywhere. if (Entity.getAccess() == AS_public) return Sema::AR_accessible; @@ -825,16 +1030,31 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, return Sema::AR_delayed; } - return CheckEffectiveAccess(S, EffectiveContext(S.CurContext), - Loc, Entity); + EffectiveContext EC(S.CurContext); + switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { + case AR_accessible: return Sema::AR_accessible; + case AR_inaccessible: return Sema::AR_inaccessible; + case AR_dependent: return Sema::AR_dependent; + } + llvm_unreachable("falling off end"); + return Sema::AR_accessible; } void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { // Pretend we did this from the context of the newly-parsed - // declaration. - EffectiveContext EC(Ctx->getDeclContext()); - - if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData())) + // declaration. If that declaration itself forms a declaration context, + // include it in the effective context so that parameters and return types of + // befriended functions have that function's access priveledges. + DeclContext *DC = Ctx->getDeclContext(); + if (isa<FunctionDecl>(Ctx)) + DC = cast<DeclContext>(Ctx); + else if (FunctionTemplateDecl *FnTpl = dyn_cast<FunctionTemplateDecl>(Ctx)) + DC = cast<DeclContext>(FnTpl->getTemplatedDecl()); + EffectiveContext EC(DC); + + AccessTarget Target(DD.getAccessData()); + + if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) DD.Triggered = true; } @@ -851,19 +1071,28 @@ void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, if (!TargetD) return; if (DD.isAccessToMember()) { - AccessedEntity Entity(Context, - AccessedEntity::Member, - cast<CXXRecordDecl>(NamingD), - Access, - cast<NamedDecl>(TargetD)); + CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); + NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); + QualType BaseObjectType = DD.getAccessBaseObjectType(); + if (!BaseObjectType.isNull()) { + BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, + DeclarationName()); + if (BaseObjectType.isNull()) return; + } + + AccessTarget Entity(Context, + AccessTarget::Member, + NamingClass, + DeclAccessPair::make(TargetDecl, Access), + BaseObjectType); Entity.setDiag(DD.getDiagnostic()); CheckAccess(*this, Loc, Entity); } else { - AccessedEntity Entity(Context, - AccessedEntity::Base, - cast<CXXRecordDecl>(TargetD), - cast<CXXRecordDecl>(NamingD), - Access); + AccessTarget Entity(Context, + AccessTarget::Base, + cast<CXXRecordDecl>(TargetD), + cast<CXXRecordDecl>(NamingD), + Access); Entity.setDiag(DD.getDiagnostic()); CheckAccess(*this, Loc, Entity); } @@ -876,8 +1105,8 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), - Found); + AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), + Found, QualType()); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -891,8 +1120,12 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(), - Found); + QualType BaseType = E->getBaseType(); + if (E->isArrow()) + BaseType = BaseType->getAs<PointerType>()->getPointeeType(); + + AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), + Found, BaseType); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -910,8 +1143,9 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Dtor, Access)); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Dtor, Access), + QualType()); Entity.setDiag(PDiag); // TODO: avoid copy return CheckAccess(*this, Loc, Entity); @@ -920,17 +1154,39 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, + const InitializedEntity &Entity, AccessSpecifier Access) { if (!getLangOptions().AccessControl || Access == AS_public) return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Constructor, Access)); - Entity.setDiag(diag::err_access_ctor); + AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Constructor, Access), + QualType()); + switch (Entity.getKind()) { + default: + AccessEntity.setDiag(diag::err_access_ctor); + break; - return CheckAccess(*this, UseLoc, Entity); + case InitializedEntity::EK_Base: + AccessEntity.setDiag(PDiag(diag::err_access_base) + << Entity.isInheritedVirtualBase() + << Entity.getBaseSpecifier()->getType() + << getSpecialMember(Constructor)); + break; + + case InitializedEntity::EK_Member: { + const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); + AccessEntity.setDiag(PDiag(diag::err_access_field) + << Field->getType() + << getSpecialMember(Constructor)); + break; + } + + } + + return CheckAccess(*this, UseLoc, AccessEntity); } /// Checks direct (i.e. non-inherited) access to an arbitrary class @@ -944,8 +1200,9 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, - DeclAccessPair::make(Target, Access)); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Target, Access), + QualType()); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); } @@ -961,7 +1218,8 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + QualType()); Entity.setDiag(diag::err_access) << PlacementRange; @@ -982,7 +1240,8 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + ObjectExpr->getType()); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -998,24 +1257,16 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, return AR_accessible; OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); - NestedNameSpecifier *Qualifier = Ovl->getQualifier(); - assert(Qualifier && "address of overloaded member without qualifier"); + CXXRecordDecl *NamingClass = Ovl->getNamingClass(); - CXXScopeSpec SS; - SS.setScopeRep(Qualifier); - SS.setRange(Ovl->getQualifierRange()); - DeclContext *DC = computeDeclContext(SS); - assert(DC && DC->isRecord() && "scope did not resolve to record"); - CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC); - - AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + Context.getTypeDeclType(NamingClass)); Entity.setDiag(diag::err_access) << Ovl->getSourceRange(); return CheckAccess(*this, Ovl->getNameLoc(), Entity); } - /// Checks access for a hierarchy conversion. /// /// \param IsBaseToDerived whether this is a base-to-derived conversion (true) @@ -1042,13 +1293,20 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl()); DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl()); - AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD, - Path.Access); + AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, + Path.Access); if (DiagID) Entity.setDiag(DiagID) << Derived << Base; - if (ForceUnprivileged) - return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity); + if (ForceUnprivileged) { + switch (CheckEffectiveAccess(*this, EffectiveContext(), + AccessLoc, Entity)) { + case ::AR_accessible: return Sema::AR_accessible; + case ::AR_inaccessible: return Sema::AR_inaccessible; + case ::AR_dependent: return Sema::AR_dependent; + } + llvm_unreachable("unexpected result from CheckEffectiveAccess"); + } return CheckAccess(*this, AccessLoc, Entity); } @@ -1060,9 +1318,9 @@ void Sema::CheckLookupAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { - AccessedEntity Entity(Context, AccessedEntity::Member, - R.getNamingClass(), - I.getPair()); + AccessTarget Entity(Context, AccessedEntity::Member, + R.getNamingClass(), I.getPair(), + R.getBaseObjectType()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 11c8e6d..ba7e1ff 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -47,11 +47,12 @@ static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CXXBaseSpecifierArray &BasePath); static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); @@ -69,39 +70,43 @@ static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); static TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, unsigned &msg); static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, - QualType DestType, bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastExpr::CastKind &Kind); + QualType DestType, bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind); + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, - QualType SrcType, - QualType DestType,bool CStyle, - const SourceRange &OpRange, - unsigned &msg, - CastExpr::CastKind &Kind); + QualType SrcType, + QualType DestType,bool CStyle, + const SourceRange &OpRange, + unsigned &msg, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath); + static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CastExpr::CastKind &Kind); static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl); + CXXBaseSpecifierArray &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, @@ -153,10 +158,12 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXBaseSpecifierArray BasePath; if (!TypeDependent) - CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); + CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, BasePath, DestTInfo, + OpLoc)); } case tok::kw_reinterpret_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -164,28 +171,18 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, CXXBaseSpecifierArray(), + DestTInfo, OpLoc)); } case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (!TypeDependent) { - CXXMethodDecl *Method = 0; - - CheckStaticCast(*this, Ex, DestType, OpRange, Kind, Method); - - if (Method) { - OwningExprResult CastArg - = BuildCXXCastArgument(OpLoc, DestType.getNonReferenceType(), - Kind, Method, Owned(Ex)); - if (CastArg.isInvalid()) - return ExprError(); - - Ex = CastArg.takeAs<Expr>(); - } - } + CXXBaseSpecifierArray BasePath; + if (!TypeDependent) + CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath); return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestTInfo, OpLoc)); + Kind, Ex, BasePath, + DestTInfo, OpLoc)); } } @@ -290,7 +287,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, - const SourceRange &DestRange, CastExpr::CastKind &Kind) { + const SourceRange &DestRange, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); @@ -384,10 +382,12 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // C++ 5.2.7p5 // Upcasts are resolved statically. if (DestRecord && Self.IsDerivedFrom(SrcPointee, DestPointee)) { - Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, - OpRange.getBegin(), OpRange); + if (Self.CheckDerivedToBaseConversion(SrcPointee, DestPointee, + OpRange.getBegin(), OpRange, + &BasePath)) + return; + Kind = CastExpr::CK_DerivedToBase; - // Diagnostic already emitted on error. return; } @@ -448,7 +448,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CXXBaseSpecifierArray &BasePath) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". @@ -462,8 +462,7 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, - Kind, ConversionDecl) - != TC_Success && msg != 0) + Kind, BasePath) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static << SrcExpr->getType() << DestType << OpRange; } @@ -475,7 +474,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CXXBaseSpecifierArray &BasePath) { // The order the tests is not entirely arbitrary. There is one conversion // that can be handled in two different ways. Given: // struct A {}; @@ -497,7 +496,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // See the function for details. // DR 427 specifies that this is to be applied before paragraph 2. tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange, - msg, Kind); + msg, Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -512,7 +511,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // C++ 5.2.9p2: An expression e can be explicitly converted to a type T // [...] if the declaration "T t(e);" is well-formed, [...]. tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg, - Kind, ConversionDecl); + Kind); if (tcr != TC_NotApplicable) return tcr; @@ -548,7 +547,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // Reverse pointer upcast. C++ 4.10p3 specifies pointer upcast. // C++ 5.2.9p8 additionally disallows a cast path through virtual inheritance. tcr = TryStaticPointerDowncast(Self, SrcType, DestType, CStyle, OpRange, msg, - Kind); + Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -556,7 +555,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // conversion. C++ 5.2.9p9 has additional information. // DR54's access restrictions apply here also. tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle, - OpRange, msg, Kind); + OpRange, msg, Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -630,7 +629,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be // cast to type "reference to cv2 D", where D is a class derived from B, // if a valid standard conversion from "pointer to D" to "pointer to B" @@ -656,14 +656,16 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, return TryStaticDowncast(Self, Self.Context.getCanonicalType(SrcExpr->getType()), Self.Context.getCanonicalType(DestPointee), CStyle, - OpRange, SrcExpr->getType(), DestType, msg, Kind); + OpRange, SrcExpr->getType(), DestType, msg, Kind, + BasePath); } /// Tests whether a conversion according to C++ 5.2.9p8 is valid. TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class // type, can be converted to an rvalue of type "pointer to cv2 D", where D // is a class derived from B, if a valid standard conversion from "pointer @@ -686,7 +688,8 @@ TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, return TryStaticDowncast(Self, Self.Context.getCanonicalType(SrcPointer->getPointeeType()), Self.Context.getCanonicalType(DestPointer->getPointeeType()), - CStyle, OpRange, SrcType, DestType, msg, Kind); + CStyle, OpRange, SrcType, DestType, msg, Kind, + BasePath); } /// TryStaticDowncast - Common functionality of TryStaticReferenceDowncast and @@ -696,7 +699,7 @@ TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind) { + CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath) { // We can only work with complete types. But don't complain if it doesn't work if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) || Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0))) @@ -707,7 +710,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_NotApplicable; } - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(DestType, SrcType, Paths)) { return TC_NotApplicable; @@ -787,6 +790,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, return TC_Failed; } + Self.BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_BaseToDerived; return TC_Success; } @@ -802,22 +806,25 @@ TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind) { + unsigned &msg, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath) { const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); if (!DestMemPtr) return TC_NotApplicable; bool WasOverloadedFunction = false; DeclAccessPair FoundOverload; - if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, - FoundOverload)) { - CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); - SrcType = Self.Context.getMemberPointerType(Fn->getType(), - Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); - WasOverloadedFunction = true; + if (SrcExpr->getType() == Self.Context.OverloadTy) { + if (FunctionDecl *Fn + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + FoundOverload)) { + CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); + SrcType = Self.Context.getMemberPointerType(Fn->getType(), + Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); + WasOverloadedFunction = true; + } } - + const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>(); if (!SrcMemPtr) { msg = diag::err_bad_static_cast_member_pointer_nonmp; @@ -832,7 +839,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TC_NotApplicable; @@ -886,6 +893,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } } + Self.BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_DerivedToBaseMemberPointer; return TC_Success; } @@ -898,8 +906,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXMethodDecl *&ConversionDecl) { + CastExpr::CastKind &Kind) { if (DestType->isRecordType()) { if (Self.RequireCompleteType(OpRange.getBegin(), DestType, diag::err_bad_dynamic_cast_incomplete)) { @@ -907,71 +914,35 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return TC_Failed; } } - - if (DestType->isReferenceType()) { - // All reference bindings insert implicit casts above that do the actual - // casting. - Kind = CastExpr::CK_NoOp; - - // At this point of CheckStaticCast, if the destination is a reference, - // this has to work. There is no other way that works. - // On the other hand, if we're checking a C-style cast, we've still got - // the reinterpret_cast way. - InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); - InitializationKind InitKind = InitializationKind::CreateCast(OpRange, - CStyle); - InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); - if (InitSeq.getKind() == InitializationSequence::FailedSequence && CStyle) - return TC_NotApplicable; - - Sema::OwningExprResult Result - = InitSeq.Perform(Self, Entity, InitKind, - Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); - if (Result.isInvalid()) { - msg = 0; - return TC_Failed; - } - - SrcExpr = Result.takeAs<Expr>(); - return TC_Success; - } - - if (DestType->isRecordType()) { - if (CXXConstructorDecl *Constructor - = Self.TryInitializationByConstructor(DestType, &SrcExpr, 1, - OpRange.getBegin(), - InitializationKind::CreateDirect(OpRange.getBegin(), - OpRange.getBegin(), - OpRange.getEnd()))) { - ConversionDecl = Constructor; - Kind = CastExpr::CK_ConstructorConversion; - return TC_Success; - } - + + // At this point of CheckStaticCast, if the destination is a reference, + // this has to work. There is no other way that works. + // On the other hand, if we're checking a C-style cast, we've still got + // the reinterpret_cast way. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); + InitializationKind InitKind + = InitializationKind::CreateCast(/*FIXME:*/OpRange, + CStyle); + InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + if (InitSeq.getKind() == InitializationSequence::FailedSequence && + (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; + + Sema::OwningExprResult Result + = InitSeq.Perform(Self, Entity, InitKind, + Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); + if (Result.isInvalid()) { + msg = 0; + return TC_Failed; } - - // FIXME: To get a proper error from invalid conversions here, we need to - // reimplement more of this. - // FIXME: This does not actually perform the conversion, and thus does not - // check for ambiguity or access. - ImplicitConversionSequence ICS = - Self.TryImplicitConversion(SrcExpr, DestType, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false, - /*one of user provided casts*/true); - - if (ICS.isBad()) - return TC_NotApplicable; - - // The conversion is possible, so commit to it. - Kind = CastExpr::CK_NoOp; - msg = 0; - return Self.PerformImplicitConversion(SrcExpr, DestType, ICS, Sema::AA_Casting, - /*IgnoreBaseAccess*/CStyle) ? - TC_Failed : TC_Success; + + if (InitSeq.isConstructorInitialization()) + Kind = CastExpr::CK_ConstructorConversion; + else + Kind = CastExpr::CK_NoOp; + + SrcExpr = Result.takeAs<Expr>(); + return TC_Success; } /// TryConstCast - See if a const_cast from source to destination is allowed, @@ -1234,9 +1205,11 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Success; } -bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, bool FunctionalStyle, - CXXMethodDecl *&ConversionDecl) { +bool +Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, + CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, + bool FunctionalStyle) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". @@ -1271,8 +1244,8 @@ bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, - Kind, ConversionDecl); + tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind, + BasePath); if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index c90f75e..c0ec9e9 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -24,61 +24,17 @@ using namespace clang; /// \brief Find the current instantiation that associated with the given type. -static CXXRecordDecl * -getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, - QualType T) { +static CXXRecordDecl *getCurrentInstantiationOf(QualType T) { if (T.isNull()) return 0; - - T = Context.getCanonicalType(T).getUnqualifiedType(); - - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { - // If we've hit a namespace or the global scope, then the - // nested-name-specifier can't refer to the current instantiation. - if (Ctx->isFileContext()) - return 0; - - // Skip non-class contexts. - CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); - if (!Record) - continue; - - // If this record type is not dependent, - if (!Record->isDependentType()) - return 0; - - // C++ [temp.dep.type]p1: - // - // In the definition of a class template, a nested class of a - // class template, a member of a class template, or a member of a - // nested class of a class template, a name refers to the current - // instantiation if it is - // -- the injected-class-name (9) of the class template or - // nested class, - // -- in the definition of a primary class template, the name - // of the class template followed by the template argument - // list of the primary template (as described below) - // enclosed in <>, - // -- in the definition of a nested class of a class template, - // the name of the nested class referenced as a member of - // the current instantiation, or - // -- in the definition of a partial specialization, the name - // of the class template followed by the template argument - // list of the partial specialization enclosed in <>. If - // the nth template parameter is a parameter pack, the nth - // template argument is a pack expansion (14.6.3) whose - // pattern is the name of the parameter pack. - // (FIXME: parameter packs) - // - // All of these options come down to having the - // nested-name-specifier type that is equivalent to the - // injected-class-name of one of the types that is currently in - // our context. - if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) - return Record; - } - - return 0; + + const Type *Ty = T->getCanonicalTypeInternal().getTypePtr(); + if (isa<RecordType>(Ty)) + return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl()); + else if (isa<InjectedClassNameType>(Ty)) + return cast<InjectedClassNameType>(Ty)->getDecl(); + else + return 0; } /// \brief Compute the DeclContext that is associated with the given type. @@ -92,7 +48,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { if (const TagType *Tag = T->getAs<TagType>()) return Tag->getDecl(); - return ::getCurrentInstantiationOf(Context, CurContext, T); + return ::getCurrentInstantiationOf(T); } /// \brief Compute the DeclContext that is associated with the given @@ -218,7 +174,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { return 0; QualType T = QualType(NNS->getAsType(), 0); - return ::getCurrentInstantiationOf(Context, CurContext, T); + return ::getCurrentInstantiationOf(T); } /// \brief Require that the context specified by SS be complete. @@ -230,11 +186,10 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { /// that is currently being defined. Or, if we have a type that names /// a class template specialization that is not a complete type, we /// will attempt to instantiate that class template. -bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { - if (!SS.isSet() || SS.isInvalid()) - return false; +bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, + DeclContext *DC) { + assert(DC != 0 && "given null context"); - DeclContext *DC = computeDeclContext(SS, true); if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { // If this is a dependent type, then we consider it complete. if (Tag->isDependentContext()) @@ -247,10 +202,13 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { return false; // The type must be complete. - return RequireCompleteType(SS.getRange().getBegin(), - Context.getTypeDeclType(Tag), - PDiag(diag::err_incomplete_nested_name_spec) - << SS.getRange()); + if (RequireCompleteType(SS.getRange().getBegin(), + Context.getTypeDeclType(Tag), + PDiag(diag::err_incomplete_nested_name_spec) + << SS.getRange())) { + SS.setScopeRep(0); // Mark the ScopeSpec invalid. + return true; + } } return false; @@ -322,7 +280,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return 0; } -bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, +bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, TypeTy *ObjectTypePtr) { @@ -353,7 +311,8 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(SS, LookupCtx)) return false; LookupQualifiedName(Found, LookupCtx); @@ -384,7 +343,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, /// scope if it *knows* that the result is correct. It should not return in a /// dependent context, for example. Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -423,7 +382,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // nested-name-specifier. // The declaration context must be complete. - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(SS, LookupCtx)) return 0; LookupQualifiedName(Found, LookupCtx); @@ -480,7 +440,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // We haven't found anything, and we're not recovering from a // different kind of error, so look for typos. DeclarationName Name = Found.getLookupName(); - if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && + if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext, + CTC_NoKeywords) && Found.isSingleResult() && isAcceptableNestedNameSpecifier(Found.getAsSingle<NamedDecl>())) { if (LookupCtx) @@ -593,7 +554,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. /// Returns a CXXScopeTy* object representing the C++ scope. Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, @@ -611,7 +572,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// conservatively correct to always return false from this method. /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. -bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, +bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, IdentifierInfo &II, TypeTy *ObjectType, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), @@ -676,7 +637,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. -bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { +bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); if (SS.isInvalid()) return true; @@ -686,10 +647,15 @@ bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { // Before we enter a declarator's context, we need to make sure that // it is a complete declaration context. - if (!DC->isDependentContext() && RequireCompleteDeclContext(SS)) + if (!DC->isDependentContext() && RequireCompleteDeclContext(SS, DC)) return true; EnterDeclaratorContext(S, DC); + + // Rebuild the nested name specifier for the new scope. + if (DC->isDependentContext()) + RebuildNestedNameSpecifierInCurrentInstantiation(SS); + return false; } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f2520fc..7029711 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -26,6 +26,7 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" +#include "clang/Basic/TargetBuiltins.h" #include <limits> using namespace clang; @@ -155,14 +156,18 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return ExprError(); break; case Builtin::BI__builtin_return_address: - case Builtin::BI__builtin_frame_address: - if (SemaBuiltinStackAddress(TheCall)) + case Builtin::BI__builtin_frame_address: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 0, Result)) return ExprError(); break; - case Builtin::BI__builtin_eh_return_data_regno: - if (SemaBuiltinEHReturnDataRegNo(TheCall)) + } + case Builtin::BI__builtin_eh_return_data_regno: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 0, Result)) return ExprError(); break; + } case Builtin::BI__builtin_shufflevector: return SemaBuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since @@ -196,6 +201,15 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinAtomicOverloaded(TheCall)) return ExprError(); break; + + // Target specific builtins start here. + case X86::BI__builtin_ia32_palignr128: + case X86::BI__builtin_ia32_palignr: { + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, 2, Result)) + return ExprError(); + break; + } } return move(TheCallResult); @@ -270,8 +284,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Ensure that we have at least one argument to do type inference from. if (TheCall->getNumArgs() < 1) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << TheCall->getCallee()->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1 << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); // Inspect the first argument of the atomic builtin. This should always be // a pointer type, whose element is an integral scalar or pointer type. @@ -367,8 +383,10 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // Now that we know how many fixed arguments we expect, first check that we // have at least that many. if (TheCall->getNumArgs() < 1+NumFixed) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 << TheCall->getCallee()->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 << 1+NumFixed << TheCall->getNumArgs() + << TheCall->getCallee()->getSourceRange(); // Get the decl for the concrete builtin from this, we can tell what the @@ -405,9 +423,8 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXMethodDecl *ConversionDecl = 0; - if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, - ConversionDecl)) + CXXBaseSpecifierArray BasePath; + if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath)) return true; // Okay, we have something that *can* be converted to the right type. Check @@ -416,7 +433,7 @@ bool Sema::SemaBuiltinAtomicOverloaded(CallExpr *TheCall) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - ImpCastExprToType(Arg, ValType, Kind, /*isLvalue=*/false); + ImpCastExprToType(Arg, ValType, Kind); TheCall->setArg(i+1, Arg); } @@ -476,15 +493,17 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { if (TheCall->getNumArgs() > 2) { Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << Fn->getSourceRange() + << 0 /*function call*/ << 2 << TheCall->getNumArgs() + << Fn->getSourceRange() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); return true; } if (TheCall->getNumArgs() < 2) { - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } // Determine whether the current function is variadic or not. @@ -492,15 +511,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { bool isVariadic; if (CurBlock) isVariadic = CurBlock->isVariadic; - else if (getCurFunctionDecl()) { - if (FunctionProtoType* FTP = - dyn_cast<FunctionProtoType>(getCurFunctionDecl()->getType())) - isVariadic = FTP->isVariadic(); - else - isVariadic = false; - } else { + else if (FunctionDecl *FD = getCurFunctionDecl()) + isVariadic = FD->isVariadic(); + else isVariadic = getCurMethodDecl()->isVariadic(); - } if (!isVariadic) { Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); @@ -538,11 +552,11 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + << 0 << 2 << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > 2) return Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ + << 0 /*function call*/ << 2 << TheCall->getNumArgs() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); @@ -580,11 +594,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (TheCall->getNumArgs() < NumArgs) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/; + << 0 << NumArgs << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > NumArgs) return Diag(TheCall->getArg(NumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ + << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); @@ -602,25 +616,14 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { return false; } -bool Sema::SemaBuiltinStackAddress(CallExpr *TheCall) { - // The signature for these builtins is exact; the only thing we need - // to check is that the argument is a constant. - SourceLocation Loc; - if (!TheCall->getArg(0)->isTypeDependent() && - !TheCall->getArg(0)->isValueDependent() && - !TheCall->getArg(0)->isIntegerConstantExpr(Context, &Loc)) - return Diag(Loc, diag::err_stack_const_level) << TheCall->getSourceRange(); - - return false; -} - /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 3) return ExprError(Diag(TheCall->getLocEnd(), - diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << 3 << TheCall->getNumArgs() + << TheCall->getSourceRange()); unsigned numElements = std::numeric_limits<unsigned>::max(); if (!TheCall->getArg(0)->isTypeDependent() && @@ -647,10 +650,14 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < numElements+2) return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + << 0 /*function call*/ + << numElements+2 << TheCall->getNumArgs() + << TheCall->getSourceRange()); return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << TheCall->getSourceRange()); + << 0 /*function call*/ + << numElements+2 << TheCall->getNumArgs() + << TheCall->getSourceRange()); } } @@ -659,11 +666,9 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->getArg(i)->isValueDependent()) continue; - llvm::APSInt Result(32); - if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) - return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_nonconstant_argument) - << TheCall->getArg(i)->getSourceRange()); + llvm::APSInt Result; + if (SemaBuiltinConstantArg(TheCall, i, Result)) + return ExprError(); if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) return ExprError(Diag(TheCall->getLocStart(), @@ -691,30 +696,19 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) - return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args) - << 0 /*function call*/ << TheCall->getSourceRange(); + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << 3 << NumArgs + << TheCall->getSourceRange(); // Argument 0 is checked for us and the remaining arguments must be // constant integers. for (unsigned i = 1; i != NumArgs; ++i) { Expr *Arg = TheCall->getArg(i); - if (Arg->isTypeDependent()) - continue; - - if (!Arg->getType()->isIntegralType()) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_type) - << Arg->getSourceRange(); - - ImpCastExprToType(Arg, Context.IntTy, CastExpr::CK_IntegralCast); - TheCall->setArg(i, Arg); - - if (Arg->isValueDependent()) - continue; - + llvm::APSInt Result; - if (!Arg->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_prefetch_invalid_arg_ice) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); + if (SemaBuiltinConstantArg(TheCall, i, Result)) + return true; // FIXME: gcc issues a warning and rewrites these to 0. These // seems especially odd for the third argument since the default @@ -733,42 +727,35 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { return false; } -/// SemaBuiltinEHReturnDataRegNo - Handle __builtin_eh_return_data_regno, the -/// operand must be an integer constant. -bool Sema::SemaBuiltinEHReturnDataRegNo(CallExpr *TheCall) { - llvm::APSInt Result; - if (!TheCall->getArg(0)->isIntegerConstantExpr(Result, Context)) - return Diag(TheCall->getLocStart(), diag::err_expr_not_ice) - << TheCall->getArg(0)->getSourceRange(); - +/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr +/// TheCall is a constant expression. +bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result) { + Expr *Arg = TheCall->getArg(ArgNum); + DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); + FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl()); + + if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; + + if (!Arg->isIntegerConstantExpr(Result, Context)) + return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type) + << FDecl->getDeclName() << Arg->getSourceRange(); + return false; } - /// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, /// int type). This simply type checks that type is one of the defined /// constants (0-3). // For compatability check 0-3, llvm only handles 0 and 2. bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { - Expr *Arg = TheCall->getArg(1); - if (Arg->isTypeDependent()) - return false; - - QualType ArgType = Arg->getType(); - const BuiltinType *BT = ArgType->getAs<BuiltinType>(); - llvm::APSInt Result(32); - if (!BT || BT->getKind() != BuiltinType::Int) - return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); - - if (Arg->isValueDependent()) - return false; - - if (!Arg->isIntegerConstantExpr(Result, Context)) { - return Diag(TheCall->getLocStart(), diag::err_object_size_invalid_argument) - << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); - } + llvm::APSInt Result; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + Expr *Arg = TheCall->getArg(1); if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) { return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -781,11 +768,13 @@ bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { /// This checks that val is a constant 1. bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(1); - if (Arg->isTypeDependent() || Arg->isValueDependent()) - return false; + llvm::APSInt Result; - llvm::APSInt Result(32); - if (!Arg->isIntegerConstantExpr(Result, Context) || Result != 1) + // TODO: This is less than ideal. Overload this to take a value. + if (SemaBuiltinConstantArg(TheCall, 1, Result)) + return true; + + if (Result != 1) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); @@ -1885,6 +1874,17 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // Left shift gets black-listed based on a judgement call. case BinaryOperator::Shl: + // ...except that we want to treat '1 << (blah)' as logically + // positive. It's an important idiom. + if (IntegerLiteral *I + = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) { + if (I->getValue() == 1) { + IntRange R = IntRange::forType(C, E->getType()); + return IntRange(R.Width, /*NonNegative*/ true); + } + } + // fallthrough + case BinaryOperator::ShlAssign: return IntRange::forType(C, E->getType()); @@ -1945,6 +1945,10 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return GetExprRange(C, UO->getSubExpr(), MaxWidth); } } + + if (dyn_cast<OffsetOfExpr>(E)) { + IntRange::forType(C, E->getType()); + } FieldDecl *BitField = E->getBitField(); if (BitField) { diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index df14aa7..c075d16 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -13,12 +13,14 @@ #include "Sema.h" #include "Lookup.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" #include <list> #include <map> #include <vector> @@ -413,6 +415,9 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, return false; } + + if (Filter == &ResultBuilder::IsNestedNameSpecifier) + AsNestedNameSpecifier = true; // ... then it must be interesting! return true; @@ -502,7 +507,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { } for (; I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if (I->first->getIdentifierNamespace() == Decl::IDNS_Tag && + if (I->first->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -627,7 +632,7 @@ void ResultBuilder::ExitScope() { bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) - IDNS |= Decl::IDNS_Tag; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; else if (SemaRef.getLangOptions().ObjC1 && isa<ObjCIvarDecl>(ND)) return true; @@ -639,7 +644,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const { bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { unsigned IDNS = Decl::IDNS_Ordinary; if (SemaRef.getLangOptions().CPlusPlus) - IDNS |= Decl::IDNS_Tag; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Namespace; return (ND->getIdentifierNamespace() & IDNS) && !isa<ValueDecl>(ND) && !isa<FunctionTemplateDecl>(ND); @@ -882,7 +887,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddPlaceholderChunk("identifier"); Pattern->AddChunk(CodeCompletionString::CK_Equal); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Using directives @@ -892,7 +896,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("namespace"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // asm(string-literal) @@ -901,7 +904,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("string-literal"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Explicit template instantiation @@ -909,7 +911,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("template"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("declaration"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -926,7 +927,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("using"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("qualified-id"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // using typename qualified-id; (only in a dependent context) @@ -937,7 +937,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("typename"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("qualified-id"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1090,7 +1089,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_LeftParen); Pattern->AddPlaceholderChunk("expression"); Pattern->AddChunk(CodeCompletionString::CK_RightParen); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // for ( for-init-statement ; condition ; expression ) { statements } @@ -1116,7 +1114,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // continue ; Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("continue"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1124,7 +1121,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, // break ; Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("break"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -1145,7 +1141,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); } - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // goto identifier ; @@ -1153,7 +1148,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTypedTextChunk("goto"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // Using directives @@ -1163,7 +1157,6 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Pattern->AddTextChunk("namespace"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); } @@ -2075,10 +2068,6 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, Results.ExitScope(); - // Add macros - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); - // Hand off the results found for code completion. HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2108,13 +2097,17 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { return; } - ResultBuilder Results(*this, Filter); - Results.allowNestedNameSpecifiers(); + ResultBuilder Results(*this); CodeCompletionDeclConsumer Consumer(Results, CurContext); + + // First pass: look for tags. + Results.setFilter(Filter); LookupVisibleDecls(S, LookupTagName, Consumer); + + // Second pass: look for nested name specifiers. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2192,7 +2185,7 @@ void Sema::CodeCompleteCase(Scope *S) { CurContext, 0, false); } Results.ExitScope(); - + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); @@ -2258,7 +2251,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: access? AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none), Args, NumArgs, CandidateSet, - false, false, /*PartialOverloading*/ true); + false, /*PartialOverloading*/true); } } @@ -2276,14 +2269,13 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } } - if (Results.empty()) - CodeCompleteOrdinaryName(S, CCC_Expression); - else + CodeCompleteOrdinaryName(S, CCC_Expression); + if (!Results.empty()) CodeCompleter->ProcessOverloadCandidates(*this, NumArgs, Results.data(), Results.size()); } -void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, +void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext) { if (!SS.getScopeRep() || !CodeCompleter) return; @@ -2294,7 +2286,7 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, // Try to instantiate any non-dependent declaration contexts before // we look in them. - if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS)) + if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) return; ResultBuilder Results(*this); @@ -2307,8 +2299,6 @@ void Sema::CodeCompleteQualifiedId(Scope *S, const CXXScopeSpec &SS, if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2329,8 +2319,6 @@ void Sema::CodeCompleteUsing(Scope *S) { LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2345,8 +2333,6 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2381,8 +2367,6 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { Results.ExitScope(); } - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2394,8 +2378,6 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); LookupVisibleDecls(S, LookupOrdinaryName, Consumer); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2422,8 +2404,6 @@ void Sema::CodeCompleteOperatorName(Scope *S) { AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); - if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -2484,7 +2464,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,class)); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("identifier"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // @interface name @@ -2593,7 +2572,6 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { Pattern->AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt,throw)); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("expression"); - Pattern->AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Pattern)); // @synchronized ( expression ) { statements } @@ -2908,70 +2886,198 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, IdentifierInfo *FName, - SourceLocation FNameLoc, +/// \brief When we have an expression with type "id", we may assume +/// that it has some more-specific class type based on knowledge of +/// common uses of Objective-C. This routine returns that class type, +/// or NULL if no better result could be determined. +static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { + ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E); + if (!Msg) + return 0; + + Selector Sel = Msg->getSelector(); + if (Sel.isNull()) + return 0; + + IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); + if (!Id) + return 0; + + ObjCMethodDecl *Method = Msg->getMethodDecl(); + if (!Method) + return 0; + + // Determine the class that we're sending the message to. + ObjCInterfaceDecl *IFace = 0; + switch (Msg->getReceiverKind()) { + case ObjCMessageExpr::Class: + if (const ObjCInterfaceType *IFaceType + = Msg->getClassReceiver()->getAs<ObjCInterfaceType>()) + IFace = IFaceType->getDecl(); + break; + + case ObjCMessageExpr::Instance: { + QualType T = Msg->getInstanceReceiver()->getType(); + if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>()) + IFace = Ptr->getInterfaceDecl(); + break; + } + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + break; + } + + if (!IFace) + return 0; + + ObjCInterfaceDecl *Super = IFace->getSuperClass(); + if (Method->isInstanceMethod()) + return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName()) + .Case("retain", IFace) + .Case("autorelease", IFace) + .Case("copy", IFace) + .Case("copyWithZone", IFace) + .Case("mutableCopy", IFace) + .Case("mutableCopyWithZone", IFace) + .Case("awakeFromCoder", IFace) + .Case("replacementObjectFromCoder", IFace) + .Case("class", IFace) + .Case("classForCoder", IFace) + .Case("superclass", Super) + .Default(0); + + return llvm::StringSwitch<ObjCInterfaceDecl *>(Id->getName()) + .Case("new", IFace) + .Case("alloc", IFace) + .Case("allocWithZone", IFace) + .Case("class", IFace) + .Case("superclass", Super) + .Default(0); +} + +void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, IdentifierInfo **SelIdents, unsigned NumSelIdents) { - typedef CodeCompleteConsumer::Result Result; ObjCInterfaceDecl *CDecl = 0; + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { + // Figure out which interface we're in. + CDecl = CurMethod->getClassInterface(); + if (!CDecl) + return; + + // Find the superclass of this class. + CDecl = CDecl->getSuperClass(); + if (!CDecl) + return; - if (FName->isStr("super")) { - // We're sending a message to "super". - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { - // Figure out which interface we're in. - CDecl = CurMethod->getClassInterface(); - if (!CDecl) - return; - - // Find the superclass of this class. - CDecl = CDecl->getSuperClass(); - if (!CDecl) - return; + if (CurMethod->isInstanceMethod()) { + // We are inside an instance method, which means that the message + // send [super ...] is actually calling an instance method on the + // current object. Build the super expression and handle this like + // an instance method. + QualType SuperTy = Context.getObjCInterfaceType(CDecl); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + OwningExprResult Super + = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy)); + return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), + SelIdents, NumSelIdents); + } - if (CurMethod->isInstanceMethod()) { - // We are inside an instance method, which means that the message - // send [super ...] is actually calling an instance method on the - // current object. Build the super expression and handle this like - // an instance method. - QualType SuperTy = Context.getObjCInterfaceType(CDecl); - SuperTy = Context.getObjCObjectPointerType(SuperTy); - OwningExprResult Super - = Owned(new (Context) ObjCSuperExpr(FNameLoc, SuperTy)); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), - SelIdents, NumSelIdents); - } + // Fall through to send to the superclass in CDecl. + } else { + // "super" may be the name of a type or variable. Figure out which + // it is. + IdentifierInfo *Super = &Context.Idents.get("super"); + NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, + LookupOrdinaryName); + if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) { + // "super" names an interface. Use it. + } else if (TypeDecl *TD = dyn_cast_or_null<TypeDecl>(ND)) { + if (const ObjCInterfaceType *Iface + = Context.getTypeDeclType(TD)->getAs<ObjCInterfaceType>()) + CDecl = Iface->getDecl(); + } else if (ND && isa<UnresolvedUsingTypenameDecl>(ND)) { + // "super" names an unresolved type; we can't be more specific. + } else { + // Assume that "super" names some kind of value and parse that way. + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(Super, SuperLoc); + OwningExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false); + return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), + SelIdents, NumSelIdents); + } - // Okay, we're calling a factory method in our superclass. - } + // Fall through } + TypeTy *Receiver = 0; + if (CDecl) + Receiver = Context.getObjCInterfaceType(CDecl).getAsOpaquePtr(); + return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, + NumSelIdents); +} + +void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + typedef CodeCompleteConsumer::Result Result; + ObjCInterfaceDecl *CDecl = 0; + // If the given name refers to an interface type, retrieve the // corresponding declaration. - if (!CDecl) - if (TypeTy *Ty = getTypeName(*FName, FNameLoc, S, 0, false)) { - QualType T = GetTypeFromParser(Ty, 0); - if (!T.isNull()) - if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) - CDecl = Interface->getDecl(); - } - - if (!CDecl && FName->isStr("super")) { - // "super" may be the name of a variable, in which case we are - // probably calling an instance method. - CXXScopeSpec SS; - UnqualifiedId id; - id.setIdentifier(FName, FNameLoc); - OwningExprResult Super = ActOnIdExpression(S, SS, id, false, false); - return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), - SelIdents, NumSelIdents); + if (Receiver) { + QualType T = GetTypeFromParser(Receiver, 0); + if (!T.isNull()) + if (const ObjCInterfaceType *Interface = T->getAs<ObjCInterfaceType>()) + CDecl = Interface->getDecl(); } // Add all of the factory methods in this Objective-C class, its protocols, // superclasses, categories, implementation, etc. ResultBuilder Results(*this); Results.EnterNewScope(); - AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, - Results); + + if (CDecl) + AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, + Results); + else { + // We're messaging "id" as a type; provide all class/factory methods. + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || FactoryMethodPool.count(Sel) || + InstanceMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/false); + } + } + + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + M = FactoryMethodPool.begin(), + MEnd = FactoryMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); // This also suppresses remaining diagnostics. @@ -2990,15 +3096,17 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, DefaultFunctionArrayLvalueConversion(RecExpr); QualType ReceiverType = RecExpr->getType(); - if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType()) { - // FIXME: We're messaging 'id'. Do we actually want to look up every method - // in the universe? - return; - } - // Build the set of methods we can see. ResultBuilder Results(*this); Results.EnterNewScope(); + + // If we're messaging an expression with type "id" or "Class", check + // whether we know something special about the receiver that allows + // us to assume a more-specific receiver type. + if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType()) + if (ObjCInterfaceDecl *IFace = GetAssumedMessageSendExprType(RecExpr)) + ReceiverType = Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(IFace)); // Handle messages to Class. This really isn't a message to an instance // method, so we treat it the same way we would treat a message send to a @@ -3035,7 +3143,44 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, AddObjCMethods(*I, true, MK_Any, SelIdents, NumSelIdents, CurContext, Results); } - + // Handle messages to "id". + else if (ReceiverType->isObjCIdType()) { + // We're messaging "id", so provide all instance methods we know + // about as code-completion results. + + // If we have an external source, load the entire class method + // pool from the PCH file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumKnownSelectors(); I != N; + ++I) { + Selector Sel = ExternalSource->GetSelector(I); + if (Sel.isNull() || InstanceMethodPool.count(Sel) || + FactoryMethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel, /*isInstance=*/true); + } + } + + for (llvm::DenseMap<Selector, ObjCMethodList>::iterator + M = InstanceMethodPool.begin(), + MEnd = InstanceMethodPool.end(); + M != MEnd; + ++M) { + for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + MethList = MethList->Next) { + if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, + NumSelIdents)) + continue; + + Result R(MethList->Method, 0); + R.StartParameter = NumSelIdents; + R.AllParametersAreInformative = false; + Results.MaybeAddResult(R, CurContext); + } + } + } + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } @@ -3076,7 +3221,8 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, // Tell the result set to ignore all of the protocols we have // already seen. for (unsigned I = 0; I != NumProtocols; ++I) - if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first)) + if (ObjCProtocolDecl *Protocol = LookupProtocol(Protocols[I].first, + Protocols[I].second)) Results.Ignore(Protocol); // Add all protocols. @@ -3140,13 +3286,14 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } -void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName) { +void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { ResultBuilder Results(*this); Results.EnterNewScope(); // Make sure that we ignore the class we're currently defining. NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (CurClass && isa<ObjCInterfaceDecl>(CurClass)) Results.Ignore(CurClass); @@ -3171,7 +3318,8 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { } void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { typedef CodeCompleteConsumer::Result Result; ResultBuilder Results(*this); @@ -3180,7 +3328,7 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, // interface. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)) for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category; Category = Category->getNextClassCategory()) @@ -3201,17 +3349,18 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, } void Sema::CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName) { + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc) { typedef CodeCompleteConsumer::Result Result; // Find the corresponding interface. If we couldn't find the interface, the // program itself is ill-formed. However, we'll try to be helpful still by // providing the list of all of the categories we know about. NamedDecl *CurClass - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName); ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass); if (!Class) - return CodeCompleteObjCInterfaceCategory(S, ClassName); + return CodeCompleteObjCInterfaceCategory(S, ClassName, ClassNameLoc); ResultBuilder Results(*this); @@ -3306,3 +3455,224 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); } + +typedef llvm::DenseMap<Selector, ObjCMethodDecl *> KnownMethodsMap; + +/// \brief Find all of the methods that reside in the given container +/// (and its superclasses, protocols, etc.) that meet the given +/// criteria. Insert those methods into the map of known methods, +/// indexed by selector so they can be easily found. +static void FindImplementableMethods(ASTContext &Context, + ObjCContainerDecl *Container, + bool WantInstanceMethods, + QualType ReturnType, + bool IsInImplementation, + KnownMethodsMap &KnownMethods) { + if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = IFace->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + + // If we're not in the implementation of a class, also visit the + // superclass. + if (!IsInImplementation && IFace->getSuperClass()) + FindImplementableMethods(Context, IFace->getSuperClass(), + WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + + // Add methods from any class extensions (but not from categories; + // those should go into category implementations). + for (ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat; + Cat = Cat->getNextClassCategory()) { + if (!Cat->IsClassExtension()) + continue; + + FindImplementableMethods(Context, Cat, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + } + + if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = Category->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + + if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { + // Recurse into protocols. + const ObjCList<ObjCProtocolDecl> &Protocols + = Protocol->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); + I != E; ++I) + FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, + IsInImplementation, KnownMethods); + } + + // Add methods in this container. This operation occurs last because + // we want the methods from this container to override any methods + // we've previously seen with the same selector. + for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), + MEnd = Container->meth_end(); + M != MEnd; ++M) { + if ((*M)->isInstanceMethod() == WantInstanceMethods) { + if (!ReturnType.isNull() && + !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType())) + continue; + + KnownMethods[(*M)->getSelector()] = *M; + } + } +} + +void Sema::CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + TypeTy *ReturnTy, + DeclPtrTy IDecl) { + // Determine the return type of the method we're declaring, if + // provided. + QualType ReturnType = GetTypeFromParser(ReturnTy); + + // Determine where we should start searching for methods, and where we + ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0; + bool IsInImplementation = false; + if (Decl *D = IDecl.getAs<Decl>()) { + if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D)) { + SearchDecl = Impl->getClassInterface(); + CurrentDecl = Impl; + IsInImplementation = true; + } else if (ObjCCategoryImplDecl *CatImpl + = dyn_cast<ObjCCategoryImplDecl>(D)) { + SearchDecl = CatImpl->getCategoryDecl(); + CurrentDecl = CatImpl; + IsInImplementation = true; + } else { + SearchDecl = dyn_cast<ObjCContainerDecl>(D); + CurrentDecl = SearchDecl; + } + } + + if (!SearchDecl && S) { + if (DeclContext *DC = static_cast<DeclContext *>(S->getEntity())) { + SearchDecl = dyn_cast<ObjCContainerDecl>(DC); + CurrentDecl = SearchDecl; + } + } + + if (!SearchDecl || !CurrentDecl) { + HandleCodeCompleteResults(this, CodeCompleter, 0, 0); + return; + } + + // Find all of the methods that we could declare/implement here. + KnownMethodsMap KnownMethods; + FindImplementableMethods(Context, SearchDecl, IsInstanceMethod, + ReturnType, IsInImplementation, KnownMethods); + + // Erase any methods that have already been declared or + // implemented here. + for (ObjCContainerDecl::method_iterator M = CurrentDecl->meth_begin(), + MEnd = CurrentDecl->meth_end(); + M != MEnd; ++M) { + if ((*M)->isInstanceMethod() != IsInstanceMethod) + continue; + + KnownMethodsMap::iterator Pos = KnownMethods.find((*M)->getSelector()); + if (Pos != KnownMethods.end()) + KnownMethods.erase(Pos); + } + + // Add declarations or definitions for each of the known methods. + typedef CodeCompleteConsumer::Result Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + PrintingPolicy Policy(Context.PrintingPolicy); + Policy.AnonymousTagLocations = false; + for (KnownMethodsMap::iterator M = KnownMethods.begin(), + MEnd = KnownMethods.end(); + M != MEnd; ++M) { + ObjCMethodDecl *Method = M->second; + CodeCompletionString *Pattern = new CodeCompletionString; + + // If the result type was not already provided, add it to the + // pattern as (type). + if (ReturnType.isNull()) { + std::string TypeStr; + Method->getResultType().getAsStringInternal(TypeStr, Policy); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddTextChunk(TypeStr); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + } + + Selector Sel = Method->getSelector(); + + // Add the first part of the selector to the pattern. + Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + + // Add parameters to the pattern. + unsigned I = 0; + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; (void)++P, ++I) { + // Add the part of the selector name. + if (I == 0) + Pattern->AddChunk(CodeCompletionString::CK_Colon); + else if (I < Sel.getNumArgs()) { + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(1)->getName()); + Pattern->AddChunk(CodeCompletionString::CK_Colon); + } else + break; + + // Add the parameter type. + std::string TypeStr; + (*P)->getOriginalType().getAsStringInternal(TypeStr, Policy); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddTextChunk(TypeStr); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + + if (IdentifierInfo *Id = (*P)->getIdentifier()) + Pattern->AddTextChunk(Id->getName()); + } + + if (Method->isVariadic()) { + if (Method->param_size() > 0) + Pattern->AddChunk(CodeCompletionString::CK_Comma); + Pattern->AddTextChunk("..."); + } + + if (IsInImplementation) { + // We will be defining the method here, so add a compound statement. + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddChunk(CodeCompletionString::CK_LeftBrace); + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + if (!Method->getResultType()->isVoidType()) { + // If the result type is not void, add a return clause. + Pattern->AddTextChunk("return"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("expression"); + Pattern->AddChunk(CodeCompletionString::CK_SemiColon); + } else + Pattern->AddPlaceholderChunk("statements"); + + Pattern->AddChunk(CodeCompletionString::CK_VerticalSpace); + Pattern->AddChunk(CodeCompletionString::CK_RightBrace); + } + + Results.AddResult(Result(Pattern)); + } + + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); +} diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 541c271..0e839a9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -61,7 +61,7 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName, TypeTy *ObjectTypePtr) { // Determine where we will perform name lookup. @@ -70,7 +70,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); - } else if (SS && SS->isSet()) { + } else if (SS && SS->isNotEmpty()) { LookupCtx = computeDeclContext(*SS, false); if (!LookupCtx) { @@ -89,16 +89,16 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We know from the grammar that this name refers to a type, so build a // DependentNameType node to describe the type. - // FIXME: Record somewhere that this DependentNameType node has no "typename" - // keyword associated with it. - return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(), + return CheckTypenameType(ETK_None, + (NestedNameSpecifier *)SS->getScopeRep(), II, SS->getRange()).getAsOpaquePtr(); } return 0; } - if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!LookupCtx->isDependentContext() && + RequireCompleteDeclContext(*SS, LookupCtx)) return 0; } @@ -236,7 +236,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, - const CXXScopeSpec *SS, + CXXScopeSpec *SS, TypeTy *&SuggestedType) { // We don't have anything to suggest (yet). SuggestedType = 0; @@ -246,31 +246,53 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, LookupResult Lookup(*this, &II, IILoc, LookupOrdinaryName, NotForRedeclaration); - // FIXME: It would be nice if we could correct for typos in built-in - // names, such as "itn" for "int". - - if (CorrectTypo(Lookup, S, SS) && Lookup.isSingleResult()) { - NamedDecl *Result = Lookup.getAsSingle<NamedDecl>(); - if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) && - !Result->isInvalidDecl()) { - // We found a similarly-named type or interface; suggest that. - if (!SS || !SS->isSet()) - Diag(IILoc, diag::err_unknown_typename_suggest) - << &II << Lookup.getLookupName() - << FixItHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); - else if (DeclContext *DC = computeDeclContext(*SS, false)) - Diag(IILoc, diag::err_unknown_nested_typename_suggest) - << &II << DC << Lookup.getLookupName() << SS->getRange() - << FixItHint::CreateReplacement(SourceRange(IILoc), - Result->getNameAsString()); - else - llvm_unreachable("could not have corrected a typo here"); + if (DeclarationName Corrected = CorrectTypo(Lookup, S, SS, 0, 0, CTC_Type)) { + if (NamedDecl *Result = Lookup.getAsSingle<NamedDecl>()) { + if ((isa<TypeDecl>(Result) || isa<ObjCInterfaceDecl>(Result)) && + !Result->isInvalidDecl()) { + // We found a similarly-named type or interface; suggest that. + if (!SS || !SS->isSet()) + Diag(IILoc, diag::err_unknown_typename_suggest) + << &II << Lookup.getLookupName() + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); + else if (DeclContext *DC = computeDeclContext(*SS, false)) + Diag(IILoc, diag::err_unknown_nested_typename_suggest) + << &II << DC << Lookup.getLookupName() << SS->getRange() + << FixItHint::CreateReplacement(SourceRange(IILoc), + Result->getNameAsString()); + else + llvm_unreachable("could not have corrected a typo here"); - Diag(Result->getLocation(), diag::note_previous_decl) - << Result->getDeclName(); - - SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + Diag(Result->getLocation(), diag::note_previous_decl) + << Result->getDeclName(); + + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + return true; + } + } else if (Lookup.empty()) { + // We corrected to a keyword. + // FIXME: Actually recover with the keyword we suggest, and emit a fix-it. + Diag(IILoc, diag::err_unknown_typename_suggest) + << &II << Corrected; + return true; + } + } + + if (getLangOptions().CPlusPlus) { + // See if II is a class template that the user forgot to pass arguments to. + UnqualifiedId Name; + Name.setIdentifier(&II, IILoc); + CXXScopeSpec EmptySS; + TemplateTy TemplateResult; + if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult) + == TNK_Type_template) { + TemplateName TplName = TemplateResult.getAsVal<TemplateName>(); + Diag(IILoc, diag::err_template_missing_args) << TplName; + if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { + Diag(TplDecl->getLocation(), diag::note_template_decl_here) + << TplDecl->getTemplateParameters()->getSourceRange(); + } return true; } } @@ -522,6 +544,11 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; } + // If we failed to complete the type for some reason, don't + // diagnose the variable. + if (Ty->isIncompleteType()) + return false; + if (const TagType *TT = Ty->getAs<TagType>()) { const TagDecl *Tag = TT->getDecl(); if (Tag->hasAttr<UnusedAttr>()) @@ -558,40 +585,48 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // Diagnose unused variables in this scope. if (ShouldDiagnoseUnusedDecl(D) && - S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) - Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName(); - + S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) { + if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable()) + Diag(D->getLocation(), diag::warn_unused_exception_param) + << D->getDeclName(); + else + Diag(D->getLocation(), diag::warn_unused_variable) + << D->getDeclName(); + } // Remove this name from our lexical scope. IdResolver.RemoveDecl(D); } } -/// getObjCInterfaceDecl - Look up a for a class declaration in the scope. -/// return 0 if one not found. +/// \brief Look for an Objective-C class in the translation unit. /// -/// \param Id the name of the Objective-C class we're looking for. If +/// \param Id The name of the Objective-C class we're looking for. If /// typo-correction fixes this name, the Id will be updated /// to the fixed name. /// -/// \param RecoverLoc if provided, this routine will attempt to -/// recover from a typo in the name of an existing Objective-C class -/// and, if successful, will return the lookup that results from -/// typo-correction. +/// \param IdLoc The location of the name in the translation unit. +/// +/// \param TypoCorrection If true, this routine will attempt typo correction +/// if there is no class with the given name. +/// +/// \returns The declaration of the named Objective-C class, or NULL if the +/// class could not be found. ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, - SourceLocation RecoverLoc) { + SourceLocation IdLoc, + bool TypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in // creation from this context. - NamedDecl *IDecl = LookupSingleName(TUScope, Id, LookupOrdinaryName); + NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName); - if (!IDecl && !RecoverLoc.isInvalid()) { + if (!IDecl && TypoCorrection) { // Perform typo correction at the given location, but only if we // find an Objective-C class name. - LookupResult R(*this, Id, RecoverLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0) && + LookupResult R(*this, Id, IdLoc, LookupOrdinaryName); + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { - Diag(RecoverLoc, diag::err_undef_interface_suggest) + Diag(IdLoc, diag::err_undef_interface_suggest) << Id << IDecl->getDeclName() - << FixItHint::CreateReplacement(RecoverLoc, IDecl->getNameAsString()); + << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString()); Diag(IDecl->getLocation(), diag::note_previous_decl) << IDecl->getDeclName(); @@ -639,7 +674,8 @@ void Sema::InitBuiltinVaListType() { return; IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, LookupOrdinaryName); + NamedDecl *VaDecl = LookupSingleName(TUScope, VaIdent, SourceLocation(), + LookupOrdinaryName, ForRedeclaration); TypedefDecl *VaTypedef = cast<TypedefDecl>(VaDecl); Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); } @@ -691,7 +727,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), Loc, II, R, /*TInfo=*/0, - FunctionDecl::Extern, false, + FunctionDecl::Extern, + FunctionDecl::None, false, /*hasPrototype=*/true); New->setImplicit(); @@ -702,7 +739,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, - VarDecl::None, 0)); + VarDecl::None, VarDecl::None, 0)); New->setParams(Params.data(), Params.size()); } @@ -897,13 +934,12 @@ struct GNUCompatibleParamWarning { /// getSpecialMember - get the special member enum for a method. -static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, - const CXXMethodDecl *MD) { +Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { - if (Ctor->isDefaultConstructor()) - return Sema::CXXDefaultConstructor; if (Ctor->isCopyConstructor()) return Sema::CXXCopyConstructor; + + return Sema::CXXConstructor; } if (isa<CXXDestructorDecl>(MD)) @@ -1040,10 +1076,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } const CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old); - const CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); + CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New); if (OldMethod && NewMethod) { - if (!NewMethod->getFriendObjectKind() && - NewMethod->getLexicalDeclContext()->isRecord()) { + // Preserve triviality. + NewMethod->setTrivial(OldMethod->isTrivial()); + + bool isFriend = NewMethod->getFriendObjectKind(); + + if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) { // -- Member function declarations with the same name and the // same parameter types cannot be overloaded if any of them // is a static member function declaration. @@ -1069,14 +1109,19 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Diag(New->getLocation(), NewDiag); Diag(Old->getLocation(), PrevDiag) << Old << Old->getType(); - } else { - if (OldMethod->isImplicit()) { + + // Complain if this is an explicit declaration of a special + // member that was initially declared implicitly. + // + // As an exception, it's okay to befriend such methods in order + // to permit the implicit constructor/destructor/operator calls. + } else if (OldMethod->isImplicit()) { + if (isFriend) { + NewMethod->setImplicit(); + } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) - << New << getSpecialMember(Context, OldMethod); - - Diag(OldMethod->getLocation(), - diag::note_previous_implicit_declaration); + << New << getSpecialMember(OldMethod); return true; } } @@ -1125,7 +1170,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, *ParamType, /*TInfo=*/0, - VarDecl::None, 0); + VarDecl::None, VarDecl::None, + 0); Param->setImplicit(); Params.push_back(Param); } @@ -1441,7 +1487,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { Record->getDeclContext()->isRecord()) return BuildAnonymousStructOrUnion(S, DS, Record); - Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); } @@ -1463,9 +1509,8 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return DeclPtrTy::make(Tag); } - Diag(DS.getSourceRange().getBegin(), diag::err_no_declarators) + Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); - return DeclPtrTy(); } return DeclPtrTy::make(Tag); @@ -1558,6 +1603,64 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, return Invalid; } +/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to +/// a VarDecl::StorageClass. Any error reporting is up to the caller: +/// illegal input values are mapped to VarDecl::None. +/// If the input declaration context is a linkage specification +/// with no braces, then Extern is mapped to None. +static VarDecl::StorageClass +StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec, + DeclContext *DC) { + switch (StorageClassSpec) { + case DeclSpec::SCS_unspecified: return VarDecl::None; + case DeclSpec::SCS_extern: + // If the current context is a C++ linkage specification + // having no braces, then the keyword "extern" is properly part + // of the linkage specification itself, rather than being + // the written storage class specifier. + return (DC && isa<LinkageSpecDecl>(DC) && + !cast<LinkageSpecDecl>(DC)->hasBraces()) + ? VarDecl::None : VarDecl::Extern; + case DeclSpec::SCS_static: return VarDecl::Static; + case DeclSpec::SCS_auto: return VarDecl::Auto; + case DeclSpec::SCS_register: return VarDecl::Register; + case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern; + // Illegal SCSs map to None: error reporting is up to the caller. + case DeclSpec::SCS_mutable: // Fall through. + case DeclSpec::SCS_typedef: return VarDecl::None; + } + llvm_unreachable("unknown storage class specifier"); +} + +/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to +/// a FunctionDecl::StorageClass. Any error reporting is up to the caller: +/// illegal input values are mapped to FunctionDecl::None. +/// If the input declaration context is a linkage specification +/// with no braces, then Extern is mapped to None. +static FunctionDecl::StorageClass +StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, + DeclContext *DC) { + switch (StorageClassSpec) { + case DeclSpec::SCS_unspecified: return FunctionDecl::None; + case DeclSpec::SCS_extern: + // If the current context is a C++ linkage specification + // having no braces, then the keyword "extern" is properly part + // of the linkage specification itself, rather than being + // the written storage class specifier. + return (DC && isa<LinkageSpecDecl>(DC) && + !cast<LinkageSpecDecl>(DC)->hasBraces()) + ? FunctionDecl::None : FunctionDecl::Extern; + case DeclSpec::SCS_static: return FunctionDecl::Static; + case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern; + // Illegal SCSs map to None: error reporting is up to the caller. + case DeclSpec::SCS_auto: // Fall through. + case DeclSpec::SCS_mutable: // Fall through. + case DeclSpec::SCS_register: // Fall through. + case DeclSpec::SCS_typedef: return FunctionDecl::None; + } + llvm_unreachable("unknown storage class specifier"); +} + /// ActOnAnonymousStructOrUnion - Handle the declaration of an /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a GNU C extension; anonymous structures @@ -1675,32 +1778,31 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, TInfo, /*BitWidth=*/0, /*Mutable=*/false); Anon->setAccess(AS_public); - if (getLangOptions().CPlusPlus) + if (getLangOptions().CPlusPlus) { FieldCollector->Add(cast<FieldDecl>(Anon)); + if (!cast<CXXRecordDecl>(Record)->isEmpty()) + cast<CXXRecordDecl>(OwningClass)->setEmpty(false); + } } else { - VarDecl::StorageClass SC; - switch (DS.getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; - case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; - case DeclSpec::SCS_static: SC = VarDecl::Static; break; - case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; - case DeclSpec::SCS_register: SC = VarDecl::Register; break; - case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; - case DeclSpec::SCS_mutable: + DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); + assert(SCSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(Record->getLocation(), diag::err_mutable_nonmember); Invalid = true; SC = VarDecl::None; - break; } + SCSpec = DS.getStorageClassSpecAsWritten(); + VarDecl::StorageClass SCAsWritten + = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), - TInfo, - SC); + TInfo, SC, SCAsWritten); } Anon->setImplicit(); @@ -1708,7 +1810,7 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // context. We'll be referencing this object when we refer to one of // its members. Owner->addDecl(Anon); - + // Inject the members of the anonymous struct/union into the owning // context and into the identifier resolver chain for name lookup // purposes. @@ -1829,6 +1931,71 @@ static bool isNearlyMatchingFunction(ASTContext &Context, return true; } +/// NeedsRebuildingInCurrentInstantiation - Checks whether the given +/// declarator needs to be rebuilt in the current instantiation. +/// Any bits of declarator which appear before the name are valid for +/// consideration here. That's specifically the type in the decl spec +/// and the base type in any member-pointer chunks. +static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, + DeclarationName Name) { + // The types we specifically need to rebuild are: + // - typenames, typeofs, and decltypes + // - types which will become injected class names + // Of course, we also need to rebuild any type referencing such a + // type. It's safest to just say "dependent", but we call out a + // few cases here. + + DeclSpec &DS = D.getMutableDeclSpec(); + switch (DS.getTypeSpecType()) { + case DeclSpec::TST_typename: + case DeclSpec::TST_typeofType: + case DeclSpec::TST_typeofExpr: + case DeclSpec::TST_decltype: { + // Grab the type from the parser. + TypeSourceInfo *TSI = 0; + QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI); + if (T.isNull() || !T->isDependentType()) break; + + // Make sure there's a type source info. This isn't really much + // of a waste; most dependent types should have type source info + // attached already. + if (!TSI) + TSI = S.Context.getTrivialTypeSourceInfo(T, DS.getTypeSpecTypeLoc()); + + // Rebuild the type in the current instantiation. + TSI = S.RebuildTypeInCurrentInstantiation(TSI, D.getIdentifierLoc(), Name); + if (!TSI) return true; + + // Store the new type back in the decl spec. + QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI); + DS.UpdateTypeRep(LocType.getAsOpaquePtr()); + break; + } + + default: + // Nothing to do for these decl specs. + break; + } + + // It doesn't matter what order we do this in. + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + DeclaratorChunk &Chunk = D.getTypeObject(I); + + // The only type information in the declarator which can come + // before the declaration name is the base type of a member + // pointer. + if (Chunk.Kind != DeclaratorChunk::MemberPointer) + continue; + + // Rebuild the scope specifier in-place. + CXXScopeSpec &SS = Chunk.Mem.Scope(); + if (S.RebuildNestedNameSpecifierInCurrentInstantiation(SS)) + return true; + } + + return false; +} + Sema::DeclPtrTy Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, @@ -1851,35 +2018,47 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); - // If this is an out-of-line definition of a member of a class template - // or class template partial specialization, we may need to rebuild the - // type specifier in the declarator. See RebuildTypeInCurrentInstantiation() - // for more information. - // FIXME: cope with decltype(expr) and typeof(expr) once the rebuilder can - // handle expressions properly. - DeclSpec &DS = const_cast<DeclSpec&>(D.getDeclSpec()); - if (D.getCXXScopeSpec().isSet() && !D.getCXXScopeSpec().isInvalid() && - isDependentScopeSpecifier(D.getCXXScopeSpec()) && - (DS.getTypeSpecType() == DeclSpec::TST_typename || - DS.getTypeSpecType() == DeclSpec::TST_typeofType || - DS.getTypeSpecType() == DeclSpec::TST_typeofExpr || - DS.getTypeSpecType() == DeclSpec::TST_decltype)) { - if (DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), true)) { - // FIXME: Preserve type source info. - QualType T = GetTypeFromParser(DS.getTypeRep()); - - DeclContext *SavedContext = CurContext; - CurContext = DC; - T = RebuildTypeInCurrentInstantiation(T, D.getIdentifierLoc(), Name); - CurContext = SavedContext; - - if (T.isNull()) - return DeclPtrTy(); - DS.UpdateTypeRep(T.getAsOpaquePtr()); + DeclContext *DC = CurContext; + if (D.getCXXScopeSpec().isInvalid()) + D.setInvalidType(); + else if (D.getCXXScopeSpec().isSet()) { + bool EnteringContext = !D.getDeclSpec().isFriendSpecified(); + DC = computeDeclContext(D.getCXXScopeSpec(), EnteringContext); + if (!DC) { + // If we could not compute the declaration context, it's because the + // declaration context is dependent but does not refer to a class, + // class template, or class template partial specialization. Complain + // and return early, to avoid the coming semantic disaster. + Diag(D.getIdentifierLoc(), + diag::err_template_qualified_declarator_no_match) + << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() + << D.getCXXScopeSpec().getRange(); + return DeclPtrTy(); + } + + bool IsDependentContext = DC->isDependentContext(); + + if (!IsDependentContext && + RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) + return DeclPtrTy(); + + if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { + Diag(D.getIdentifierLoc(), + diag::err_member_def_undefined_record) + << Name << DC << D.getCXXScopeSpec().getRange(); + D.setInvalidType(); + } + + // Check whether we need to rebuild the type of the given + // declaration in the current instantiation. + if (EnteringContext && IsDependentContext && + TemplateParamLists.size() != 0) { + ContextRAII SavedContext(*this, DC); + if (RebuildDeclaratorInCurrentInstantiation(*this, D, Name)) + D.setInvalidType(); } } - DeclContext *DC; NamedDecl *New; TypeSourceInfo *TInfo = 0; @@ -1889,10 +2068,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, ForRedeclaration); // See if this is a redefinition of a variable in the same scope. - if (D.getCXXScopeSpec().isInvalid()) { - DC = CurContext; - D.setInvalidType(); - } else if (!D.getCXXScopeSpec().isSet()) { + if (!D.getCXXScopeSpec().isSet()) { bool IsLinkageLookup = false; // If the declaration we're planning to build will be a function @@ -1913,34 +2089,8 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (IsLinkageLookup) Previous.clear(LookupRedeclarationWithLinkage); - DC = CurContext; LookupName(Previous, S, /* CreateBuiltins = */ IsLinkageLookup); } else { // Something like "int foo::x;" - DC = computeDeclContext(D.getCXXScopeSpec(), true); - - if (!DC) { - // If we could not compute the declaration context, it's because the - // declaration context is dependent but does not refer to a class, - // class template, or class template partial specialization. Complain - // and return early, to avoid the coming semantic disaster. - Diag(D.getIdentifierLoc(), - diag::err_template_qualified_declarator_no_match) - << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() - << D.getCXXScopeSpec().getRange(); - return DeclPtrTy(); - } - - if (!DC->isDependentContext() && - RequireCompleteDeclContext(D.getCXXScopeSpec())) - return DeclPtrTy(); - - if (isa<CXXRecordDecl>(DC) && !cast<CXXRecordDecl>(DC)->hasDefinition()) { - Diag(D.getIdentifierLoc(), - diag::err_member_def_undefined_record) - << Name << DC << D.getCXXScopeSpec().getRange(); - D.setInvalidType(); - } - LookupQualifiedName(Previous, DC); // Don't consider using declarations as previous declarations for @@ -2298,24 +2448,20 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (getLangOptions().CPlusPlus) CheckExtraCXXDefaultArguments(D); - VarDecl *NewVD; - VarDecl::StorageClass SC; - switch (D.getDeclSpec().getStorageClassSpec()) { - default: assert(0 && "Unknown storage class!"); - case DeclSpec::SCS_unspecified: SC = VarDecl::None; break; - case DeclSpec::SCS_extern: SC = VarDecl::Extern; break; - case DeclSpec::SCS_static: SC = VarDecl::Static; break; - case DeclSpec::SCS_auto: SC = VarDecl::Auto; break; - case DeclSpec::SCS_register: SC = VarDecl::Register; break; - case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; - case DeclSpec::SCS_mutable: + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); + assert(SCSpec != DeclSpec::SCS_typedef && + "Parser allowed 'typedef' as storage class VarDecl."); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); D.setInvalidType(); SC = VarDecl::None; - break; } + SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + VarDecl::StorageClass SCAsWritten + = StorageClassSpecToVarDeclStorageClass(SCSpec, DC); IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { @@ -2367,6 +2513,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + /*never a friend*/ false, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // There is no such thing as a variable template. @@ -2388,8 +2535,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC); + VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), + II, R, TInfo, SC, SCAsWritten); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -2767,6 +2914,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool isExplicit = D.getDeclSpec().isExplicitSpecified(); + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); + FunctionDecl::StorageClass SCAsWritten + = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC); + // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. @@ -2827,7 +2978,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, isInline, + Name, R, TInfo, SC, SCAsWritten, isInline, /*hasPrototype=*/true); D.setInvalidType(); } @@ -2876,7 +3027,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), D.getIdentifierLoc(), Name, R, TInfo, - isStatic, isInline); + isStatic, SCAsWritten, isInline); isVirtualOkay = !isStatic; } else { @@ -2893,7 +3044,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, isInline, HasPrototype); + Name, R, TInfo, SC, SCAsWritten, isInline, + HasPrototype); } if (D.isInvalidType()) @@ -2917,6 +3069,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + isFriend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a function template @@ -2935,7 +3088,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a function template specialization. isFunctionTemplateSpecialization = true; - // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);". + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend && isFunctionTemplateSpecialization) { // We want to remove the "template<>", found here. SourceRange RemoveRange = TemplateParams->getSourceRange(); @@ -3015,10 +3168,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); - } else { - NewFD->setObjectOfFriendDecl(false); } - + NewFD->setObjectOfFriendDecl(false); NewFD->setAccess(AS_public); } @@ -3072,6 +3223,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); + + if (Param->isInvalidDecl()) + NewFD->setInvalidDecl(); } } @@ -3091,6 +3245,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(), 0, *AI, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); Param->setImplicit(); Params.push_back(Param); @@ -3139,24 +3294,39 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } + } else if (isFriend && isFunctionTemplateSpecialization) { + // This combination is only possible in a recovery case; the user + // wrote something like: + // template <> friend void foo(int); + // which we're recovering from as if the user had written: + // friend void foo<>(int); + // Go ahead and fake up a template id. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); + } + + // If it's a friend (and only if it's a friend), it's possible + // that either the specialized function type or the specialized + // template is dependent, and therefore matching will fail. In + // this case, don't check the specialization yet. + if (isFunctionTemplateSpecialization && isFriend && + (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + assert(HasExplicitTemplateArgs && + "friend function specialization without template args"); + if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } else if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { + if (CheckMemberSpecialization(NewFD, Previous)) + NewFD->setInvalidDecl(); } - if (isFunctionTemplateSpecialization) { - if (isFriend && NewFD->getType()->isDependentType()) { - // FIXME: When we see a friend of a function template - // specialization with a dependent type, we can't match it now; - // for now, we just drop it, until we have a reasonable way to - // represent the parsed-but-not-matched friend function template - // specialization in the AST. - return 0; - } else if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) - NewFD->setInvalidDecl(); - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && - CheckMemberSpecialization(NewFD, Previous)) - NewFD->setInvalidDecl(); - // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, @@ -3166,17 +3336,25 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); + NamedDecl *PrincipalDecl = (FunctionTemplate + ? cast<NamedDecl>(FunctionTemplate) + : NewFD); + if (isFriend && Redeclaration) { - AccessSpecifier Access = NewFD->getPreviousDeclaration()->getAccess(); - if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(true); - FunctionTemplate->setAccess(Access); - } else { - NewFD->setObjectOfFriendDecl(true); - } + AccessSpecifier Access = AS_public; + if (!NewFD->isInvalidDecl()) + Access = NewFD->getPreviousDeclaration()->getAccess(); + NewFD->setAccess(Access); + if (FunctionTemplate) FunctionTemplate->setAccess(Access); + + PrincipalDecl->setObjectOfFriendDecl(true); } + if (NewFD->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); + // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { @@ -3286,7 +3464,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: Also include static functions declared but not defined. if (!NewFD->isInvalidDecl() && IsFunctionDefinition && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage - && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>()) + && !NewFD->isUsed() && !NewFD->hasAttr<UnusedAttr>() + && !NewFD->hasAttr<ConstructorAttr>() + && !NewFD->hasAttr<DestructorAttr>()) UnusedStaticFuncs.push_back(NewFD); return NewFD; @@ -3761,7 +3941,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { } } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClass() == VarDecl::Extern) + if (VDecl->getStorageClass() == VarDecl::Extern && + (!getLangOptions().CPlusPlus || + !Context.getBaseElementType(VDecl->getType()).isConstQualified())) Diag(VDecl->getLocation(), diag::warn_extern_init); if (!VDecl->isInvalidDecl()) { InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); @@ -4030,8 +4212,10 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. VarDecl::StorageClass StorageClass = VarDecl::None; + VarDecl::StorageClass StorageClassAsWritten = VarDecl::None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { StorageClass = VarDecl::Register; + StorageClassAsWritten = VarDecl::Register; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); @@ -4084,55 +4268,24 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { } } - // Parameters can not be abstract class types. - // For record types, this is done by the AbstractClassUsageDiagnoser once - // the class has been completely parsed. - if (!CurContext->isRecord() && - RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, - diag::err_abstract_type_in_decl, - AbstractParamType)) - D.setInvalidType(true); - - QualType T = adjustParameterType(parmDeclType); - // Temporarily put parameter variables in the translation unit, not // the enclosing context. This prevents them from accidentally // looking like class members in C++. - DeclContext *DC = Context.getTranslationUnitDecl(); - - ParmVarDecl *New - = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II, - T, TInfo, StorageClass, 0); + ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), + TInfo, parmDeclType, II, + D.getIdentifierLoc(), + StorageClass, StorageClassAsWritten); if (D.isInvalidType()) - New->setInvalidDecl(); - - // Parameter declarators cannot be interface types. All ObjC objects are - // passed by reference. - if (T->isObjCInterfaceType()) { - Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; - New->setInvalidDecl(); - } - + New->setInvalidDecl(); + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) << D.getCXXScopeSpec().getRange(); New->setInvalidDecl(); } - - // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage - // duration shall not be qualified by an address-space qualifier." - // Since all parameters have automatic store duration, they can not have - // an address space. - if (T.getAddressSpace() != 0) { - Diag(D.getIdentifierLoc(), - diag::err_arg_with_address_space); - New->setInvalidDecl(); - } - - + // Add the parameter declaration into this scope. S->AddDecl(DeclPtrTy::make(New)); if (II) @@ -4146,9 +4299,43 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { return DeclPtrTy::make(New); } -void Sema::ActOnObjCCatchParam(DeclPtrTy D) { - ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>()); - Param->setDeclContext(CurContext); +ParmVarDecl *Sema::CheckParameter(DeclContext *DC, + TypeSourceInfo *TSInfo, QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + VarDecl::StorageClass StorageClass, + VarDecl::StorageClass StorageClassAsWritten) { + ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name, + adjustParameterType(T), TSInfo, + StorageClass, StorageClassAsWritten, + 0); + + // Parameters can not be abstract class types. + // For record types, this is done by the AbstractClassUsageDiagnoser once + // the class has been completely parsed. + if (!CurContext->isRecord() && + RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl, + AbstractParamType)) + New->setInvalidDecl(); + + // Parameter declarators cannot be interface types. All ObjC objects are + // passed by reference. + if (T->isObjCInterfaceType()) { + Diag(NameLoc, + diag::err_object_cannot_be_passed_returned_by_value) << 1 << T; + New->setInvalidDecl(); + } + + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // duration shall not be qualified by an address-space qualifier." + // Since all parameters have automatic store duration, they can not have + // an address space. + if (T.getAddressSpace() != 0) { + Diag(NameLoc, diag::err_arg_with_address_space); + New->setInvalidDecl(); + } + + return New; } void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, @@ -4692,7 +4879,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, MultiTemplateParamsArg TemplateParameterLists, @@ -4711,6 +4898,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may @@ -4761,12 +4949,18 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, IsDependent = true; return DeclPtrTy(); } + } else { + DC = computeDeclContext(SS, true); + if (!DC) { + Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) + << SS.getRange(); + return DeclPtrTy(); + } } - if (RequireCompleteDeclContext(SS)) + if (RequireCompleteDeclContext(SS, DC)) return DeclPtrTy::make((Decl *)0); - DC = computeDeclContext(SS, true); SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); @@ -4891,17 +5085,10 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // class or function, the friend class or function is a member of // the innermost enclosing namespace. SearchDC = SearchDC->getEnclosingNamespaceContext(); - - // Look up through our scopes until we find one with an entity which - // matches our declaration context. - while (S->getEntity() && - ((DeclContext *)S->getEntity())->getPrimaryContext() != SearchDC) { - S = S->getParent(); - assert(S && "No enclosing scope matching the enclosing namespace."); - } } - // In C++, look for a shadow friend decl. + // In C++, we need to do a redeclaration lookup to properly + // diagnose some problems. if (getLangOptions().CPlusPlus) { Previous.setRedeclarationKind(ForRedeclaration); LookupQualifiedName(Previous, SearchDC); @@ -4909,8 +5096,32 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (!Previous.empty()) { - assert(Previous.isSingleResult()); - NamedDecl *PrevDecl = Previous.getFoundDecl(); + NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl(); + + // It's okay to have a tag decl in the same scope as a typedef + // which hides a tag decl in the same scope. Finding this + // insanity with a redeclaration lookup can only actually happen + // in C++. + // + // This is also okay for elaborated-type-specifiers, which is + // technically forbidden by the current standard but which is + // okay according to the likely resolution of an open issue; + // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 + if (getLangOptions().CPlusPlus) { + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) { + if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { + TagDecl *Tag = TT->getDecl(); + if (Tag->getDeclName() == Name && + Tag->getDeclContext()->getLookupContext() + ->Equals(TD->getDeclContext()->getLookupContext())) { + PrevDecl = Tag; + Previous.clear(); + Previous.addDecl(Tag); + } + } + } + } + if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { // If this is a use of a previous tag, or if the tag is already declared // in the same scope (so that the definition/declaration completes or @@ -5002,23 +5213,61 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // If we get here, we're going to create a new Decl. If PrevDecl // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. + + + // Otherwise, PrevDecl is not a tag, but was found with tag + // lookup. This is only actually possible in C++, where a few + // things like templates still live in the tag namespace. } else { - // PrevDecl is a namespace, template, or anything else - // that lives in the IDNS_Tag identifier namespace. - if (TUK == TUK_Reference || TUK == TUK_Friend || - isDeclInScope(PrevDecl, SearchDC, S)) { - // The tag name clashes with a namespace name, issue an error and - // recover by making this tag be anonymous. + assert(getLangOptions().CPlusPlus); + + // Use a better diagnostic if an elaborated-type-specifier + // found the wrong kind of type on the first + // (non-redeclaration) lookup. + if ((TUK == TUK_Reference || TUK == TUK_Friend) && + !Previous.isForRedeclaration()) { + unsigned Kind = 0; + if (isa<TypedefDecl>(PrevDecl)) Kind = 1; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; + Diag(PrevDecl->getLocation(), diag::note_declared_at); + Invalid = true; + + // Otherwise, only diagnose if the declaration is in scope. + } else if (!isDeclInScope(PrevDecl, SearchDC, S)) { + // do nothing + + // Diagnose implicit declarations introduced by elaborated types. + } else if (TUK == TUK_Reference || TUK == TUK_Friend) { + unsigned Kind = 0; + if (isa<TypedefDecl>(PrevDecl)) Kind = 1; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; + Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; + Invalid = true; + + // Otherwise it's a declaration. Call out a particularly common + // case here. + } else if (isa<TypedefDecl>(PrevDecl)) { + Diag(NameLoc, diag::err_tag_definition_of_typedef) + << Name + << cast<TypedefDecl>(PrevDecl)->getUnderlyingType(); + Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; + Invalid = true; + + // Otherwise, diagnose. + } else { + // The tag name clashes with something else in the target scope, + // issue an error and recover by making this tag be anonymous. Diag(NameLoc, diag::err_redefinition_different_kind) << Name; Diag(PrevDecl->getLocation(), diag::note_previous_definition); Name = 0; - Previous.clear(); Invalid = true; - } else { - // The existing declaration isn't relevant to us; we're in a - // new scope, so clear out the previous declaration. - Previous.clear(); } + + // The existing declaration isn't relevant to us; we're in a + // new scope, so clear out the previous declaration. + Previous.clear(); } } @@ -5089,28 +5338,6 @@ CreateNewDecl: New->addAttr(::new (Context) PragmaPackAttr(Alignment * 8)); } - if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) { - // C++ [dcl.typedef]p3: - // [...] Similarly, in a given scope, a class or enumeration - // shall not be declared with the same name as a typedef-name - // that is declared in that scope and refers to a type other - // than the class or enumeration itself. - LookupResult Lookup(*this, Name, NameLoc, LookupOrdinaryName, - ForRedeclaration); - LookupName(Lookup, S); - TypedefDecl *PrevTypedef = Lookup.getAsSingle<TypedefDecl>(); - NamedDecl *PrevTypedefNamed = PrevTypedef; - if (PrevTypedef && isDeclInScope(PrevTypedefNamed, SearchDC, S) && - Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) != - Context.getCanonicalType(Context.getTypeDeclType(New))) { - Diag(Loc, diag::err_tag_definition_of_typedef) - << Context.getTypeDeclType(New) - << PrevTypedef->getUnderlyingType(); - Diag(PrevTypedef->getLocation(), diag::note_previous_definition); - Invalid = true; - } - } - // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) @@ -5175,7 +5402,7 @@ CreateNewDecl: void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); - + // Enter the tag context. PushDeclContext(S, Tag); } @@ -5321,11 +5548,23 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, if (!FieldTy->isDependentType()) { uint64_t TypeSize = Context.getTypeSize(FieldTy); if (Value.getZExtValue() > TypeSize) { + if (!getLangOptions().CPlusPlus) { + if (FieldName) + return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)Value.getZExtValue() + << (unsigned)TypeSize; + + return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) + << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; + } + if (FieldName) - return Diag(FieldLoc, diag::err_bitfield_width_exceeds_type_size) - << FieldName << (unsigned)TypeSize; - return Diag(FieldLoc, diag::err_anon_bitfield_width_exceeds_type_size) - << (unsigned)TypeSize; + Diag(FieldLoc, diag::warn_bitfield_width_exceeds_type_size) + << FieldName << (unsigned)Value.getZExtValue() + << (unsigned)TypeSize; + else + Diag(FieldLoc, diag::warn_anon_bitfield_width_exceeds_type_size) + << (unsigned)Value.getZExtValue() << (unsigned)TypeSize; } } @@ -5363,7 +5602,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { @@ -5506,21 +5745,17 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // because otherwise we'll never get complaints about // copy constructors. - const CXXSpecialMember invalid = (CXXSpecialMember) -1; - - CXXSpecialMember member; + CXXSpecialMember member = CXXInvalid; if (!RDecl->hasTrivialCopyConstructor()) member = CXXCopyConstructor; else if (!RDecl->hasTrivialConstructor()) - member = CXXDefaultConstructor; + member = CXXConstructor; else if (!RDecl->hasTrivialCopyAssignment()) member = CXXCopyAssignment; else if (!RDecl->hasTrivialDestructor()) member = CXXDestructor; - else - member = invalid; - if (member != invalid) { + if (member != CXXInvalid) { Diag(Loc, diag::err_illegal_union_member) << Name << member; DiagnoseNontrivial(RT, member); NewFD->setInvalidDecl(); @@ -5562,14 +5797,16 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { // Check whether the member was user-declared. switch (member) { - case CXXDefaultConstructor: + case CXXInvalid: + break; + + case CXXConstructor: if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce;++ci){ const FunctionDecl *body = 0; ci->getBody(body); - if (!body || - !cast<CXXConstructorDecl>(body)->isImplicitlyDefined(Context)) { + if (!body || !cast<CXXConstructorDecl>(body)->isImplicitlyDefined()) { SourceLocation CtorLoc = ci->getLocation(); Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; return; @@ -5637,7 +5874,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { bool (CXXRecordDecl::*hasTrivial)() const; switch (member) { - case CXXDefaultConstructor: + case CXXConstructor: hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break; case CXXCopyConstructor: hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break; @@ -5727,10 +5964,13 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // validate II. } - + if (T->isReferenceType()) { + Diag(Loc, diag::err_ivar_reference_type); + D.setInvalidType(); + } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. - if (T->isVariablyModifiedType()) { + else if (T->isVariablyModifiedType()) { Diag(Loc, diag::err_typecheck_ivar_variable_size); D.setInvalidType(); } @@ -5747,8 +5987,16 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // Case of ivar declared in an implementation. Context is that of its class. EnclosingContext = IMPDecl->getClassInterface(); assert(EnclosingContext && "Implementation has no class interface!"); - } else + } else { + if (ObjCCategoryDecl *CDecl = + dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { + if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) { + Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); + return DeclPtrTy(); + } + } EnclosingContext = EnclosingDecl; + } // Construct the decl. ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, @@ -5756,7 +6004,7 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, TInfo, ac, (Expr *)BitfieldWidth); if (II) { - NamedDecl *PrevDecl = LookupSingleName(S, II, LookupMemberName, + NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, ForRedeclaration); if (PrevDecl && isDeclInScope(PrevDecl, EnclosingContext, S) && !isa<TagDecl>(PrevDecl)) { @@ -5926,16 +6174,14 @@ void Sema::ActOnFields(Scope* S, CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); } else if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { - if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) - Diag(LBrac, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); - else { - // FIXME. Class extension does not have a LocEnd field. - // CDecl->setLocEnd(RBrac); - // Add ivar's to class extension's DeclContext. - for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { - ClsFields[i]->setLexicalDeclContext(CDecl); - CDecl->addDecl(ClsFields[i]); - } + // case of ivars in class extension; all other cases have been + // reported as errors elsewhere. + // FIXME. Class extension does not have a LocEnd field. + // CDecl->setLocEnd(RBrac); + // Add ivar's to class extension's DeclContext. + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + ClsFields[i]->setLexicalDeclContext(CDecl); + CDecl->addDecl(ClsFields[i]); } } } @@ -5950,7 +6196,7 @@ static bool isRepresentableIntegerValue(ASTContext &Context, llvm::APSInt &Value, QualType T) { assert(T->isIntegralType() && "Integral type required!"); - unsigned BitWidth = Context.getTypeSize(T); + unsigned BitWidth = Context.getIntWidth(T); if (Value.isUnsigned() || Value.isNonNegative()) return Value.getActiveBits() < BitWidth; @@ -6083,7 +6329,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); - EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); ++EnumVal; // If we're not in C++, diagnose the overflow of enumerator values, @@ -6105,7 +6351,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!EltTy->isDependentType()) { // Make the enumerator value match the signedness and size of the // enumerator's type. - EnumVal.zextOrTrunc(Context.getTypeSize(EltTy)); + EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerType()); } @@ -6131,7 +6377,7 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. - NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName, + NamedDecl *PrevDecl = LookupSingleName(S, Id, IdLoc, LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. @@ -6357,6 +6603,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, CastExpr::CK_IntegralCast, ECD->getInitExpr(), + CXXBaseSpecifierArray(), /*isLvalue=*/false)); if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an @@ -6383,7 +6630,7 @@ Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { - Decl *PrevDecl = LookupSingleName(TUScope, Name, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { PrevDecl->addAttr(::new (Context) WeakAttr()); @@ -6399,7 +6646,8 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc, SourceLocation AliasNameLoc) { - Decl *PrevDecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); + Decl *PrevDecl = LookupSingleName(TUScope, AliasName, AliasNameLoc, + LookupOrdinaryName); WeakInfo W = WeakInfo(Name, NameLoc); if (PrevDecl) { diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index cc24735..90aa9c1 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -118,7 +118,7 @@ static bool isFunctionOrMethodVariadic(const Decl *d) { const FunctionProtoType *proto = cast<FunctionProtoType>(FnTy); return proto->isVariadic(); } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(d)) - return BD->IsVariadic(); + return BD->isVariadic(); else { return cast<ObjCMethodDecl>(d)->isVariadic(); } @@ -490,16 +490,9 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // NOTE: We don't add the attribute to a FunctionDecl because the noreturn - // trait will be part of the function's type. - - // Don't apply as a decl attribute to ValueDecl. - // FIXME: probably ought to diagnose this. - if (isa<ValueDecl>(d)) - return; - - if (HandleCommonNoReturnAttr(d, Attr, S)) - d->addAttr(::new (S.Context) NoReturnAttr()); + /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */ + assert(Attr.isInvalid() == false); + d->addAttr(::new (S.Context) NoReturnAttr()); } static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, @@ -900,9 +893,12 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // We ignore weak import on properties and methods return; } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; + // Don't issue the warning for darwin as target; yet, ignore the attribute. + if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin || + !isa<ObjCInterfaceDecl>(D)) + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 2 /*variable and function*/; + return; } // Merge should handle any subsequent violations. @@ -1022,8 +1018,11 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // Look up the function + // FIXME: Lookup probably isn't looking in the right place + // FIXME: The lookup source location should be in the attribute, not the + // start of the attribute. NamedDecl *CleanupDecl - = S.LookupSingleName(S.TUScope, Attr.getParameterName(), + = S.LookupSingleName(S.TUScope, Attr.getParameterName(), Attr.getLoc(), Sema::LookupOrdinaryName); if (!CleanupDecl) { S.Diag(Attr.getLoc(), diag::err_attribute_cleanup_arg_not_found) << @@ -1643,6 +1642,27 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) GNUInlineAttr()); } +static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Diagnostic is emitted elsewhere: here we store the (valid) Attr + // in the Decl node for syntactic reasoning, e.g., pretty-printing. + assert(Attr.isInvalid() == false); + + switch (Attr.getKind()) { + case AttributeList::AT_fastcall: + d->addAttr(::new (S.Context) FastCallAttr()); + return; + case AttributeList::AT_stdcall: + d->addAttr(::new (S.Context) StdCallAttr()); + return; + case AttributeList::AT_cdecl: + d->addAttr(::new (S.Context) CDeclAttr()); + return; + default: + llvm_unreachable("unexpected attribute kind"); + return; + } +} + static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -1843,6 +1863,9 @@ static bool isKnownDeclSpecAttr(const AttributeList &Attr) { /// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) { + if (Attr.isInvalid()) + return; + if (Attr.isDeclspecAttribute() && !isKnownDeclSpecAttr(Attr)) // FIXME: Try to deal with other __declspec attributes! return; @@ -1927,7 +1950,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_stdcall: case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: - // These are all treated as type attributes. + HandleCallConvAttr(D, Attr, S); break; default: // Ask target about the attribute. @@ -1972,7 +1995,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), - VD->getStorageClass()); + VD->getStorageClass(), + VD->getStorageClassAsWritten()); if (VD->getQualifier()) { VarDecl *NewVD = cast<VarDecl>(NewD); NewVD->setQualifierInfo(VD->getQualifier(), VD->getQualifierRange()); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 39e3739..6259b85a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -16,12 +16,13 @@ #include "Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" @@ -297,13 +298,15 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { << OldParam->getDefaultArgRange(); Invalid = true; } else if (OldParam->hasDefaultArg()) { - // Merge the old default argument into the new parameter + // Merge the old default argument into the new parameter. + // It's important to use getInit() here; getDefaultArg() + // strips off any top-level CXXExprWithTemporaries. NewParam->setHasInheritedDefaultArg(); if (OldParam->hasUninstantiatedDefaultArg()) NewParam->setUninstantiatedDefaultArg( OldParam->getUninstantiatedDefaultArg()); else - NewParam->setDefaultArg(OldParam->getDefaultArg()); + NewParam->setDefaultArg(OldParam->getInit()); } else if (NewParam->hasDefaultArg()) { if (New->getDescribedFunctionTemplate()) { // Paragraph 4, quoted above, only applies to non-template functions. @@ -710,6 +713,29 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { return DerivedRD->isDerivedFrom(BaseRD, Paths); } +void Sema::BuildBasePathArray(const CXXBasePaths &Paths, + CXXBaseSpecifierArray &BasePathArray) { + assert(BasePathArray.empty() && "Base path array must be empty!"); + assert(Paths.isRecordingPaths() && "Must record paths!"); + + const CXXBasePath &Path = Paths.front(); + + // We first go backward and check if we have a virtual base. + // FIXME: It would be better if CXXBasePath had the base specifier for + // the nearest virtual base. + unsigned Start = 0; + for (unsigned I = Path.size(); I != 0; --I) { + if (Path[I - 1].Base->isVirtual()) { + Start = I - 1; + break; + } + } + + // Now add all bases. + for (unsigned I = Start, E = Path.size(); I != E; ++I) + BasePathArray.push_back(Path[I].Base); +} + /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base /// conversion (where Derived and Base are class types) is /// well-formed, meaning that the conversion is unambiguous (and @@ -723,7 +749,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, - DeclarationName Name) { + DeclarationName Name, + CXXBaseSpecifierArray *BasePath) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to @@ -736,17 +763,23 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) { - if (!InaccessibleBaseID) - return false; - - // Check that the base class can be accessed. - switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), - InaccessibleBaseID)) { - case AR_accessible: return false; - case AR_inaccessible: return true; - case AR_dependent: return false; - case AR_delayed: return false; + if (InaccessibleBaseID) { + // Check that the base class can be accessed. + switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(), + InaccessibleBaseID)) { + case AR_inaccessible: + return true; + case AR_accessible: + case AR_dependent: + case AR_delayed: + break; + } } + + // Build a base path if necessary. + if (BasePath) + BuildBasePathArray(Paths, *BasePath); + return false; } // We know that the derived-to-base conversion is ambiguous, and @@ -775,12 +808,14 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, + CXXBaseSpecifierArray *BasePath, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, IgnoreAccess ? 0 : diag::err_upcast_to_inaccessible_base, diag::err_ambiguous_derived_to_base_conv, - Loc, Range, DeclarationName()); + Loc, Range, DeclarationName(), + BasePath); } @@ -1013,7 +1048,7 @@ static bool FindBaseInitializer(Sema &SemaRef, Sema::MemInitResult Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, TypeTy *TemplateTypeTy, SourceLocation IdLoc, @@ -1076,6 +1111,9 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + // We don't want access-control diagnostics here. + R.suppressDiagnostics(); + if (SS.isSet() && isDependentScopeSpecifier(SS)) { bool NotUnknownSpecialization = false; DeclContext *DC = computeDeclContext(SS, false); @@ -1085,7 +1123,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!NotUnknownSpecialization) { // When the scope specifier can refer to a member of an unknown // specialization, we take it as a type name. - BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), + BaseType = CheckTypenameType(ETK_None, + (NestedNameSpecifier *)SS.getScopeRep(), *MemberOrBase, SS.getRange()); if (BaseType.isNull()) return true; @@ -1096,7 +1135,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, // If no results were found, try to correct typos. if (R.empty() && BaseType.isNull() && - CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { + CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && + R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { // We have found a non-static data member with a similar @@ -1236,7 +1276,6 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, QualType FieldType = Member->getType(); if (const ArrayType *Array = Context.getAsArrayType(FieldType)) FieldType = Array->getElementType(); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); if (FieldType->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. @@ -1334,6 +1373,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, ExprTemporaries.end()); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + /*IsVirtual=*/false, LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); @@ -1369,7 +1409,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // mem-initializer is ill-formed. if (!DirectBaseSpec && !VirtualBaseSpec) return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << ClassDecl->getNameAsCString() + << BaseType << Context.getTypeDeclType(ClassDecl) << BaseTInfo->getTypeLoc().getSourceRange(); CXXBaseSpecifier *BaseSpec @@ -1379,7 +1419,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // Initialize the base. InitializedEntity BaseEntity = - InitializedEntity::InitializeBase(Context, BaseSpec); + InitializedEntity::InitializeBase(Context, BaseSpec, VirtualBaseSpec); InitializationKind Kind = InitializationKind::CreateDirect(BaseLoc, LParenLoc, RParenLoc); @@ -1414,23 +1454,199 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, Init.takeAs<Expr>(), RParenLoc); } return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, + BaseSpec->isVirtual(), LParenLoc, BaseInit.takeAs<Expr>(), RParenLoc); } +/// ImplicitInitializerKind - How an implicit base or member initializer should +/// initialize its base or member. +enum ImplicitInitializerKind { + IIK_Default, + IIK_Copy, + IIK_Move +}; + +static bool +BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + CXXBaseSpecifier *BaseSpec, + bool IsInheritedVirtualBase, + CXXBaseOrMemberInitializer *&CXXBaseInit) { + InitializedEntity InitEntity + = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, + IsInheritedVirtualBase); + + Sema::OwningExprResult BaseInit(SemaRef); + + switch (ImplicitInitKind) { + case IIK_Default: { + InitializationKind InitKind + = InitializationKind::CreateDefault(Constructor->getLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + break; + } + + case IIK_Copy: { + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *CopyCtorArg = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + Constructor->getLocation(), ParamType, 0); + + // Cast to the base class to avoid ambiguities. + QualType ArgTy = + SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), + ParamType.getQualifiers()); + SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, + CXXBaseSpecifierArray(BaseSpec)); + + InitializationKind InitKind + = InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, + (void**)&CopyCtorArg, 1)); + break; + } + + case IIK_Move: + assert(false && "Unhandled initializer kind!"); + } + + BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + if (BaseInit.isInvalid()) + return true; + + CXXBaseInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + SemaRef.Context.getTrivialTypeSourceInfo(BaseSpec->getType(), + SourceLocation()), + BaseSpec->isVirtual(), + SourceLocation(), + BaseInit.takeAs<Expr>(), + SourceLocation()); + + return false; +} + +static bool +BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, + ImplicitInitializerKind ImplicitInitKind, + FieldDecl *Field, + CXXBaseOrMemberInitializer *&CXXMemberInit) { + if (ImplicitInitKind == IIK_Copy) { + // FIXME: We should not return early here, but will do so until + // we know how to handle copy initialization of arrays. + CXXMemberInit = 0; + return false; + + ParmVarDecl *Param = Constructor->getParamDecl(0); + QualType ParamType = Param->getType().getNonReferenceType(); + + Expr *MemberExprBase = + DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + SourceLocation(), ParamType, 0); + + + Expr *CopyCtorArg = + MemberExpr::Create(SemaRef.Context, MemberExprBase, /*IsArrow=*/false, + 0, SourceRange(), Field, + DeclAccessPair::make(Field, Field->getAccess()), + SourceLocation(), 0, + Field->getType().getNonReferenceType()); + + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDirect(Constructor->getLocation(), + SourceLocation(), SourceLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, + &CopyCtorArg, 1); + + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArg, 1), 0); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = 0; + return false; + } + + assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!"); + + QualType FieldBaseElementType = + SemaRef.Context.getBaseElementType(Field->getType()); + + if (FieldBaseElementType->isRecordType()) { + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(Constructor->getLocation()); + + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, + Sema::MultiExprArg(SemaRef, 0, 0)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + if (MemberInit.isInvalid()) + return true; + + CXXMemberInit = + new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + return false; + } + + if (FieldBaseElementType->isReferenceType()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 0 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + if (FieldBaseElementType.isConstQualified()) { + SemaRef.Diag(Constructor->getLocation(), + diag::err_uninitialized_member_in_ctor) + << (int)Constructor->isImplicit() + << SemaRef.Context.getTagDeclType(Constructor->getParent()) + << 1 << Field->getDeclName(); + SemaRef.Diag(Field->getLocation(), diag::note_declared_at); + return true; + } + + // Nothing to initialize. + CXXMemberInit = 0; + return false; +} + bool Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, CXXBaseOrMemberInitializer **Initializers, unsigned NumInitializers, bool AnyErrors) { - if (Constructor->isDependentContext()) { + if (Constructor->getDeclContext()->isDependentContext()) { // Just store the initializers as written, they will be checked during // instantiation. if (NumInitializers > 0) { @@ -1445,6 +1661,12 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, return false; } + ImplicitInitializerKind ImplicitInitKind = IIK_Default; + + // FIXME: Handle implicit move constructors. + if (Constructor->isImplicit() && Constructor->isCopyConstructor()) + ImplicitInitKind = IIK_Copy; + // We need to build the initializer AST according to order of construction // and not what user specified in the Initializers list. CXXRecordDecl *ClassDecl = Constructor->getParent()->getDefinition(); @@ -1464,7 +1686,13 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, AllBaseFields[Member->getMember()] = Member; } - llvm::SmallVector<CXXBaseSpecifier *, 4> BasesToDefaultInit; + // Keep track of the direct virtual bases. + llvm::SmallPtrSet<CXXBaseSpecifier *, 16> DirectVBases; + for (CXXRecordDecl::base_class_iterator I = ClassDecl->bases_begin(), + E = ClassDecl->bases_end(); I != E; ++I) { + if (I->isVirtual()) + DirectVBases.insert(I); + } // Push virtual bases before others. for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(), @@ -1474,26 +1702,15 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(VBase->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, VBase); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { + bool IsInheritedVirtualBase = !DirectVBases.count(VBase); + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + VBase, IsInheritedVirtualBase, + CXXBaseInit)) { HadError = true; continue; } - - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(VBase->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); + AllToInit.push_back(CXXBaseInit); } } @@ -1508,26 +1725,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, = AllBaseFields.lookup(Base->getType()->getAs<RecordType>())) { AllToInit.push_back(Value); } else if (!AnyErrors) { - InitializedEntity InitEntity - = InitializedEntity::InitializeBase(Context, Base); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult BaseInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); - if (BaseInit.isInvalid()) { + CXXBaseOrMemberInitializer *CXXBaseInit; + if (BuildImplicitBaseInitializer(*this, Constructor, ImplicitInitKind, + Base, /*IsInheritedVirtualBase=*/false, + CXXBaseInit)) { HadError = true; continue; } - CXXBaseOrMemberInitializer *CXXBaseInit = - new (Context) CXXBaseOrMemberInitializer(Context, - Context.getTrivialTypeSourceInfo(Base->getType(), - SourceLocation()), - SourceLocation(), - BaseInit.takeAs<Expr>(), - SourceLocation()); AllToInit.push_back(CXXBaseInit); } } @@ -1560,54 +1765,19 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, continue; } - if ((*Field)->getType()->isDependentType() || AnyErrors) + if (AnyErrors) continue; - QualType FT = Context.getBaseElementType((*Field)->getType()); - if (FT->getAs<RecordType>()) { - InitializedEntity InitEntity - = InitializedEntity::InitializeMember(*Field); - InitializationKind InitKind - = InitializationKind::CreateDefault(Constructor->getLocation()); - - InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - OwningExprResult MemberInit = InitSeq.Perform(*this, InitEntity, InitKind, - MultiExprArg(*this, 0, 0)); - MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); - if (MemberInit.isInvalid()) { - HadError = true; - continue; - } - - // Don't attach synthesized member initializers in a dependent - // context; they'll be regenerated a template instantiation - // time. - if (CurContext->isDependentContext()) - continue; - - CXXBaseOrMemberInitializer *Member = - new (Context) CXXBaseOrMemberInitializer(Context, - *Field, SourceLocation(), - SourceLocation(), - MemberInit.takeAs<Expr>(), - SourceLocation()); - - AllToInit.push_back(Member); - } - else if (FT->isReferenceType()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 0 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); - HadError = true; - } - else if (FT.isConstQualified()) { - Diag(Constructor->getLocation(), diag::err_uninitialized_member_in_ctor) - << (int)Constructor->isImplicit() << Context.getTagDeclType(ClassDecl) - << 1 << (*Field)->getDeclName(); - Diag((*Field)->getLocation(), diag::note_declared_at); + CXXBaseOrMemberInitializer *Member; + if (BuildImplicitMemberInitializer(*this, Constructor, ImplicitInitKind, + *Field, Member)) { HadError = true; + continue; } + + // If the member doesn't need to be initialized, it will be null. + if (Member) + AllToInit.push_back(Member); } NumInitializers = AllToInit.size(); @@ -1657,11 +1827,20 @@ static void *GetKeyForMember(ASTContext &Context, if (MemberMaybeAnon && Field->isAnonymousStructOrUnion()) Field = Member->getAnonUnionMember(); - // If the field is a member of an anonymous union, we use record decl of the - // union as the key. + // If the field is a member of an anonymous struct or union, our key + // is the anonymous record decl that's a direct child of the class. RecordDecl *RD = Field->getParent(); - if (RD->isAnonymousStructOrUnion() && RD->isUnion()) + if (RD->isAnonymousStructOrUnion()) { + while (true) { + RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext()); + if (Parent->isAnonymousStructOrUnion()) + RD = Parent; + else + break; + } + return static_cast<void *>(RD); + } return static_cast<void *>(Field); } @@ -1669,89 +1848,153 @@ static void *GetKeyForMember(ASTContext &Context, static void DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, const CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **MemInits, - unsigned NumMemInits) { - if (Constructor->isDependentContext()) + CXXBaseOrMemberInitializer **Inits, + unsigned NumInits) { + if (Constructor->getDeclContext()->isDependentContext()) return; - if (SemaRef.Diags.getDiagnosticLevel(diag::warn_base_initialized) == - Diagnostic::Ignored && - SemaRef.Diags.getDiagnosticLevel(diag::warn_field_initialized) == - Diagnostic::Ignored) + if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order) + == Diagnostic::Ignored) return; - // Also issue warning if order of ctor-initializer list does not match order - // of 1) base class declarations and 2) order of non-static data members. - llvm::SmallVector<const void*, 32> AllBaseOrMembers; + // Build the list of bases and members in the order that they'll + // actually be initialized. The explicit initializers should be in + // this same order but may be missing things. + llvm::SmallVector<const void*, 32> IdealInitKeys; const CXXRecordDecl *ClassDecl = Constructor->getParent(); - // Push virtual bases before others. + // 1. Virtual bases. for (CXXRecordDecl::base_class_const_iterator VBase = ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); VBase != E; ++VBase) - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - VBase->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, VBase->getType())); + // 2. Non-virtual bases. for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - // Virtuals are alread in the virtual base list and are constructed - // first. if (Base->isVirtual()) continue; - AllBaseOrMembers.push_back(GetKeyForBase(SemaRef.Context, - Base->getType())); + IdealInitKeys.push_back(GetKeyForBase(SemaRef.Context, Base->getType())); } + // 3. Direct fields. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) - AllBaseOrMembers.push_back(GetKeyForTopLevelField(*Field)); + IdealInitKeys.push_back(GetKeyForTopLevelField(*Field)); - int Last = AllBaseOrMembers.size(); - int curIndex = 0; - CXXBaseOrMemberInitializer *PrevMember = 0; - for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; - void *MemberInCtorList = GetKeyForMember(SemaRef.Context, Member, true); + unsigned NumIdealInits = IdealInitKeys.size(); + unsigned IdealIndex = 0; + + CXXBaseOrMemberInitializer *PrevInit = 0; + for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) { + CXXBaseOrMemberInitializer *Init = Inits[InitIndex]; + void *InitKey = GetKeyForMember(SemaRef.Context, Init, true); - for (; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + // Scan forward to try to find this initializer in the idealized + // initializers list. + for (; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; - if (curIndex == Last) { - assert(PrevMember && "Member not in member list?!"); - // Initializer as specified in ctor-initializer list is out of order. - // Issue a warning diagnostic. - if (PrevMember->isBaseInitializer()) { - // Diagnostics is for an initialized base class. - Type *BaseClass = PrevMember->getBaseClass(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_base_initialized) - << QualType(BaseClass, 0); - } else { - FieldDecl *Field = PrevMember->getMember(); - SemaRef.Diag(PrevMember->getSourceLocation(), - diag::warn_field_initialized) - << Field->getNameAsString(); - } - // Also the note! - if (FieldDecl *Field = Member->getMember()) - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 0 - << Field->getNameAsString(); - else { - Type *BaseClass = Member->getBaseClass(); - SemaRef.Diag(Member->getSourceLocation(), - diag::note_fieldorbase_initialized_here) << 1 - << QualType(BaseClass, 0); - } - for (curIndex = 0; curIndex < Last; curIndex++) - if (MemberInCtorList == AllBaseOrMembers[curIndex]) + + // If we didn't find this initializer, it must be because we + // scanned past it on a previous iteration. That can only + // happen if we're out of order; emit a warning. + if (IdealIndex == NumIdealInits) { + assert(PrevInit && "initializer not found in initializer list"); + + Sema::SemaDiagnosticBuilder D = + SemaRef.Diag(PrevInit->getSourceLocation(), + diag::warn_initializer_out_of_order); + + if (PrevInit->isMemberInitializer()) + D << 0 << PrevInit->getMember()->getDeclName(); + else + D << 1 << PrevInit->getBaseClassInfo()->getType(); + + if (Init->isMemberInitializer()) + D << 0 << Init->getMember()->getDeclName(); + else + D << 1 << Init->getBaseClassInfo()->getType(); + + // Move back to the initializer's location in the ideal list. + for (IdealIndex = 0; IdealIndex != NumIdealInits; ++IdealIndex) + if (InitKey == IdealInitKeys[IdealIndex]) break; + + assert(IdealIndex != NumIdealInits && + "initializer not found in initializer list"); } - PrevMember = Member; + + PrevInit = Init; } } +namespace { +bool CheckRedundantInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + CXXBaseOrMemberInitializer *&PrevInit) { + if (!PrevInit) { + PrevInit = Init; + return false; + } + + if (FieldDecl *Field = Init->getMember()) + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + else { + Type *BaseClass = Init->getBaseClass(); + assert(BaseClass && "neither field nor base"); + S.Diag(Init->getSourceLocation(), + diag::err_multiple_base_initialization) + << QualType(BaseClass, 0) + << Init->getSourceRange(); + } + S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer) + << 0 << PrevInit->getSourceRange(); + + return true; +} + +typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry; +typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap; + +bool CheckRedundantUnionInit(Sema &S, + CXXBaseOrMemberInitializer *Init, + RedundantUnionMap &Unions) { + FieldDecl *Field = Init->getMember(); + RecordDecl *Parent = Field->getParent(); + if (!Parent->isAnonymousStructOrUnion()) + return false; + + NamedDecl *Child = Field; + do { + if (Parent->isUnion()) { + UnionEntry &En = Unions[Parent]; + if (En.first && En.first != Child) { + S.Diag(Init->getSourceLocation(), + diag::err_multiple_mem_union_initialization) + << Field->getDeclName() + << Init->getSourceRange(); + S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer) + << 0 << En.second->getSourceRange(); + return true; + } else if (!En.first) { + En.first = Child; + En.second = Init; + } + } + + Child = Parent; + Parent = cast<RecordDecl>(Parent->getDeclContext()); + } while (Parent->isAnonymousStructOrUnion()); + + return false; +} +} + /// ActOnMemInitializers - Handle the member initializers for a constructor. void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, SourceLocation ColonLoc, @@ -1772,34 +2015,29 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, CXXBaseOrMemberInitializer **MemInits = reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits); - + + // Mapping for the duplicate initializers check. + // For member initializers, this is keyed with a FieldDecl*. + // For base initializers, this is keyed with a Type*. llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members; + + // Mapping for the inconsistent anonymous-union initializers check. + RedundantUnionMap MemberUnions; + bool HadError = false; for (unsigned i = 0; i < NumMemInits; i++) { - CXXBaseOrMemberInitializer *Member = MemInits[i]; + CXXBaseOrMemberInitializer *Init = MemInits[i]; - void *KeyToMember = GetKeyForMember(Context, Member); - CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember]; - if (!PrevMember) { - PrevMember = Member; - continue; - } - if (FieldDecl *Field = Member->getMember()) - Diag(Member->getSourceLocation(), - diag::error_multiple_mem_initialization) - << Field->getNameAsString() - << Member->getSourceRange(); - else { - Type *BaseClass = Member->getBaseClass(); - assert(BaseClass && "ActOnMemInitializers - neither field or base"); - Diag(Member->getSourceLocation(), - diag::error_multiple_base_initialization) - << QualType(BaseClass, 0) - << Member->getSourceRange(); + if (Init->isMemberInitializer()) { + FieldDecl *Field = Init->getMember(); + if (CheckRedundantInit(*this, Init, Members[Field]) || + CheckRedundantUnionInit(*this, Init, MemberUnions)) + HadError = true; + } else { + void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); + if (CheckRedundantInit(*this, Init, Members[Key])) + HadError = true; } - Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer) - << 0; - HadError = true; } if (HadError) @@ -2060,12 +2298,12 @@ namespace { /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. -void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { +void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!Record || Record->isInvalidDecl()) return; if (!Record->isDependentType()) - AddImplicitlyDeclaredMembersToClass(Record); + AddImplicitlyDeclaredMembersToClass(S, Record); if (Record->isInvalidDecl()) return; @@ -2141,6 +2379,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (Record->isAbstract() && !Record->isInvalidDecl()) (void)AbstractClassUsageDiagnoser(*this, Record); + + // If this is not an aggregate type and has no user-declared constructor, + // complain about any non-static data members of reference or const scalar + // type, since they will never get initializers. + if (!Record->isInvalidDecl() && !Record->isDependentType() && + !Record->isAggregate() && !Record->hasUserDeclaredConstructor()) { + bool Complained = false; + for (RecordDecl::field_iterator F = Record->field_begin(), + FEnd = Record->field_end(); + F != FEnd; ++F) { + if (F->getType()->isReferenceType() || + (F->getType().isConstQualified() && F->getType()->isScalarType())) { + if (!Complained) { + Diag(Record->getLocation(), diag::warn_no_constructor_for_refconst) + << Record->getTagKind() << Record; + Complained = true; + } + + Diag(F->getLocation(), diag::note_refconst_member_not_initialized) + << F->getType()->isReferenceType() + << F->getDeclName(); + } + } + } } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, @@ -2157,7 +2419,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); - CheckCompletedCXXClass( + CheckCompletedCXXClass(S, dyn_cast_or_null<CXXRecordDecl>(TagDecl.getAs<Decl>())); } @@ -2166,7 +2428,10 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, /// constructor, or destructor, to the given C++ class (C++ /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. -void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { +/// +/// The scope, if provided, is the class scope. +void Sema::AddImplicitlyDeclaredMembersToClass(Scope *S, + CXXRecordDecl *ClassDecl) { CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); @@ -2197,7 +2462,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { DefaultCon->setAccess(AS_public); DefaultCon->setImplicit(); DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor()); - ClassDecl->addDecl(DefaultCon); + if (S) + PushOnScopeChains(DefaultCon, S, true); + else + ClassDecl->addDecl(DefaultCon); } if (!ClassDecl->hasUserDeclaredCopyConstructor()) { @@ -2278,9 +2546,13 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyConstructor->setParams(&FromParam, 1); - ClassDecl->addDecl(CopyConstructor); + if (S) + PushOnScopeChains(CopyConstructor, S, true); + else + ClassDecl->addDecl(CopyConstructor); } if (!ClassDecl->hasUserDeclaredCopyAssignment()) { @@ -2354,7 +2626,9 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { /*FIXME:*/false, false, 0, 0, FunctionType::ExtInfo()), - /*TInfo=*/0, /*isStatic=*/false, /*isInline=*/true); + /*TInfo=*/0, /*isStatic=*/false, + /*StorageClassAsWritten=*/FunctionDecl::None, + /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); @@ -2363,14 +2637,18 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, ClassDecl->getLocation(), - /*IdentifierInfo=*/0, + /*Id=*/0, ArgType, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); CopyAssignment->setParams(&FromParam, 1); // Don't call addedAssignmentOperator. There is no way to distinguish an // implicit from an explicit assignment operator. - ClassDecl->addDecl(CopyAssignment); + if (S) + PushOnScopeChains(CopyAssignment, S, true); + else + ClassDecl->addDecl(CopyAssignment); AddOverriddenMethods(ClassDecl, CopyAssignment); } @@ -2394,7 +2672,10 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - ClassDecl->addDecl(Destructor); + if (S) + PushOnScopeChains(Destructor, S, true); + else + ClassDecl->addDecl(Destructor); // This could be uniqued if it ever proves significant. Destructor->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(Ty)); @@ -2591,8 +2872,12 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { } } - // Notify the class that we've added a constructor. - ClassDecl->addedConstructor(Context, Constructor); + // Notify the class that we've added a constructor. In principle we + // don't need to do this for out-of-line declarations; in practice + // we only instantiate the most recent declaration of a method, so + // we have to call this for everything but friends. + if (!Constructor->getFriendObjectKind()) + ClassDecl->addedConstructor(Context, Constructor); } /// CheckDestructor - Checks a fully-formed destructor for well-formedness, @@ -2737,6 +3022,9 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); SC = FunctionDecl::None; } + + QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); + if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Conversion functions don't have return types, but the parser will // happily parse something like: @@ -2749,27 +3037,35 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, Diag(D.getIdentifierLoc(), diag::err_conv_function_return_type) << SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()) << SourceRange(D.getIdentifierLoc()); + D.setInvalidType(); } + const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + // Make sure we don't have any parameters. - if (R->getAs<FunctionProtoType>()->getNumArgs() > 0) { + if (Proto->getNumArgs() > 0) { Diag(D.getIdentifierLoc(), diag::err_conv_function_with_params); // Delete the parameters. D.getTypeObject(0).Fun.freeArgs(); D.setInvalidType(); + } else if (Proto->isVariadic()) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + D.setInvalidType(); } - // Make sure the conversion function isn't variadic. - if (R->getAs<FunctionProtoType>()->isVariadic() && !D.isInvalidType()) { - Diag(D.getIdentifierLoc(), diag::err_conv_function_variadic); + // Diagnose "&operator bool()" and other such nonsense. This + // is actually a gcc extension which we don't support. + if (Proto->getResultType() != ConvType) { + Diag(D.getIdentifierLoc(), diag::err_conv_function_with_complex_decl) + << Proto->getResultType(); D.setInvalidType(); + ConvType = Proto->getResultType(); } // C++ [class.conv.fct]p4: // The conversion-type-id shall not represent a function type nor // an array type. - QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); if (ConvType->isArrayType()) { Diag(D.getIdentifierLoc(), diag::err_conv_function_to_array); ConvType = Context.getPointerType(ConvType); @@ -2783,14 +3079,15 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // Rebuild the function type "R" without any parameters (in case any // of the errors above fired) and with the conversion type as the // return type. - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); - R = Context.getFunctionType(ConvType, 0, 0, false, - Proto->getTypeQuals(), - Proto->hasExceptionSpec(), - Proto->hasAnyExceptionSpec(), - Proto->getNumExceptions(), - Proto->exception_begin(), - Proto->getExtInfo()); + if (D.isInvalidType()) { + R = Context.getFunctionType(ConvType, 0, 0, false, + Proto->getTypeQuals(), + Proto->hasExceptionSpec(), + Proto->hasAnyExceptionSpec(), + Proto->getNumExceptions(), + Proto->exception_begin(), + Proto->getExtInfo()); + } // C++0x explicit conversion operators. if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) @@ -2886,7 +3183,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. NamedDecl *PrevDecl - = LookupSingleName(DeclRegionScope, II, LookupOrdinaryName, + = LookupSingleName(DeclRegionScope, II, IdentLoc, LookupOrdinaryName, ForRedeclaration); if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { @@ -3013,7 +3310,7 @@ void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { @@ -3082,7 +3379,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -3363,7 +3660,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, @@ -3438,7 +3735,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (!LookupContext) return D; UsingDecl *UD = cast<UsingDecl>(D); - if (RequireCompleteDeclContext(SS)) { + if (RequireCompleteDeclContext(SS, LookupContext)) { UD->setInvalidDecl(); return UD; } @@ -3700,7 +3997,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident) { @@ -3709,8 +4006,13 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, LookupParsedName(R, S, &SS); // Check if we have a previous declaration with the same name. - if (NamedDecl *PrevDecl - = LookupSingleName(S, Alias, LookupOrdinaryName, ForRedeclaration)) { + NamedDecl *PrevDecl + = LookupSingleName(S, Alias, AliasLoc, LookupOrdinaryName, + ForRedeclaration); + if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S)) + PrevDecl = 0; + + if (PrevDecl) { if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(PrevDecl)) { // We already have an alias with the same name that points to the same // namespace, so don't create a new one. @@ -3746,26 +4048,47 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, return DeclPtrTy::make(AliasDecl); } +namespace { + /// \brief Scoped object used to handle the state changes required in Sema + /// to implicitly define the body of a C++ member function; + class ImplicitlyDefinedFunctionScope { + Sema &S; + DeclContext *PreviousContext; + + public: + ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) + : S(S), PreviousContext(S.CurContext) + { + S.CurContext = Method; + S.PushFunctionScope(); + S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); + } + + ~ImplicitlyDefinedFunctionScope() { + S.PopExpressionEvaluationContext(); + S.PopFunctionOrBlockScope(); + S.CurContext = PreviousContext; + } + }; +} + void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor) { assert((Constructor->isImplicit() && Constructor->isDefaultConstructor() && !Constructor->isUsed()) && "DefineImplicitDefaultConstructor - call it for implicit default ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(Constructor->getDeclContext()); + CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Constructor; + ImplicitlyDefinedFunctionScope Scope(*this, Constructor); if (SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false)) { Diag(CurrentLocation, diag::note_member_synthesized_at) - << CXXDefaultConstructor << Context.getTagDeclType(ClassDecl); + << CXXConstructor << Context.getTagDeclType(ClassDecl); Constructor->setInvalidDecl(); } else { Constructor->setUsed(); } - CurContext = PreviousContext; } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, @@ -3775,8 +4098,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Destructor->getParent(); assert(ClassDecl && "DefineImplicitDestructor - invalid destructor"); - DeclContext *PreviousContext = CurContext; - CurContext = Destructor; + ImplicitlyDefinedFunctionScope Scope(*this, Destructor); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); @@ -3788,114 +4110,429 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, << CXXDestructor << Context.getTagDeclType(ClassDecl); Destructor->setInvalidDecl(); - CurContext = PreviousContext; - return; } - CurContext = PreviousContext; Destructor->setUsed(); } -void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl) { - assert((MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && - MethodDecl->getOverloadedOperator() == OO_Equal && - !MethodDecl->isUsed()) && - "DefineImplicitOverloadedAssign - call it for implicit assignment op"); +/// \brief Builds a statement that copies the given entity from \p From to +/// \c To. +/// +/// This routine is used to copy the members of a class with an +/// implicitly-declared copy assignment operator. When the entities being +/// copied are arrays, this routine builds for loops to copy them. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param Loc The location where the implicit copy is being generated. +/// +/// \param T The type of the expressions being copied. Both expressions must +/// have this type. +/// +/// \param To The expression we are copying to. +/// +/// \param From The expression we are copying from. +/// +/// \param Depth Internal parameter recording the depth of the recursion. +/// +/// \returns A statement or a loop that copies the expressions. +static Sema::OwningStmtResult +BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, + Sema::OwningExprResult To, Sema::OwningExprResult From, + unsigned Depth = 0) { + typedef Sema::OwningStmtResult OwningStmtResult; + typedef Sema::OwningExprResult OwningExprResult; + + // C++0x [class.copy]p30: + // Each subobject is assigned in the manner appropriate to its type: + // + // - if the subobject is of class type, the copy assignment operator + // for the class is used (as if by explicit qualification; that is, + // ignoring any possible virtual overriding functions in more derived + // classes); + if (const RecordType *RecordTy = T->getAs<RecordType>()) { + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); + + // Look for operator=. + DeclarationName Name + = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); + LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName); + S.LookupQualifiedName(OpLookup, ClassDecl, false); + + // Filter out any result that isn't a copy-assignment operator. + LookupResult::Filter F = OpLookup.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + if (Method->isCopyAssignmentOperator()) + continue; + + F.erase(); + } + F.done(); + + // Create the nested-name-specifier that will be used to qualify the + // reference to operator=; this is required to suppress the virtual + // call mechanism. + CXXScopeSpec SS; + SS.setRange(Loc); + SS.setScopeRep(NestedNameSpecifier::Create(S.Context, 0, false, + T.getTypePtr())); + + // Create the reference to operator=. + OwningExprResult OpEqualRef + = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS, + /*FirstQualifierInScope=*/0, OpLookup, + /*TemplateArgs=*/0, + /*SuppressQualifierCheck=*/true); + if (OpEqualRef.isInvalid()) + return S.StmtError(); + + // Build the call to the assignment operator. + Expr *FromE = From.takeAs<Expr>(); + OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, + OpEqualRef.takeAs<Expr>(), + Loc, &FromE, 1, 0, Loc); + if (Call.isInvalid()) + return S.StmtError(); + + return S.Owned(Call.takeAs<Stmt>()); + } + + // - if the subobject is of scalar type, the built-in assignment + // operator is used. + const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T); + if (!ArrayTy) { + OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc, + BinaryOperator::Assign, + To.takeAs<Expr>(), + From.takeAs<Expr>()); + if (Assignment.isInvalid()) + return S.StmtError(); + + return S.Owned(Assignment.takeAs<Stmt>()); + } + + // - if the subobject is an array, each element is assigned, in the + // manner appropriate to the element type; + + // Construct a loop over the array bounds, e.g., + // + // for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0) + // + // that will copy each of the array elements. + QualType SizeType = S.Context.getSizeType(); + + // Create the iteration variable. + IdentifierInfo *IterationVarName = 0; + { + llvm::SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "__i" << Depth; + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, + IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), + VarDecl::None, VarDecl::None); + + // Initialize the iteration variable to zero. + llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); + IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc)); + + // Create a reference to the iteration variable; we'll use this several + // times throughout. + Expr *IterationVarRef + = S.BuildDeclRefExpr(IterationVar, SizeType, Loc).takeAs<Expr>(); + assert(IterationVarRef && "Reference to invented variable cannot fail!"); + + // Create the DeclStmt that holds the iteration variable. + Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc); + + // Create the comparison against the array bound. + llvm::APInt Upper = ArrayTy->getSize(); + Upper.zextOrTrunc(S.Context.getTypeSize(SizeType)); + OwningExprResult Comparison + = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(), + new (S.Context) IntegerLiteral(Upper, SizeType, Loc), + BinaryOperator::NE, S.Context.BoolTy, Loc)); + + // Create the pre-increment of the iteration variable. + OwningExprResult Increment + = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(), + UnaryOperator::PreInc, + SizeType, Loc)); + + // Subscript the "from" and "to" expressions with the iteration variable. + From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc, + S.Owned(IterationVarRef->Retain()), + Loc); + assert(!From.isInvalid() && "Builtin subscripting can't fail!"); + assert(!To.isInvalid() && "Builtin subscripting can't fail!"); + + // Build the copy for an individual element of the array. + OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc, + ArrayTy->getElementType(), + move(To), move(From), Depth+1); + if (Copy.isInvalid()) { + InitStmt->Destroy(S.Context); + return S.StmtError(); + } + + // Construct the loop that copies all elements of this array. + return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt), + S.MakeFullExpr(Comparison), + Sema::DeclPtrTy(), + S.MakeFullExpr(Increment), + Loc, move(Copy)); +} - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(MethodDecl->getDeclContext()); +void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *CopyAssignOperator) { + assert((CopyAssignOperator->isImplicit() && + CopyAssignOperator->isOverloadedOperator() && + CopyAssignOperator->getOverloadedOperator() == OO_Equal && + !CopyAssignOperator->isUsed()) && + "DefineImplicitCopyAssignment called for wrong function"); + + CXXRecordDecl *ClassDecl = CopyAssignOperator->getParent(); - DeclContext *PreviousContext = CurContext; - CurContext = MethodDecl; + if (ClassDecl->isInvalidDecl() || CopyAssignOperator->isInvalidDecl()) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + CopyAssignOperator->setUsed(); - // C++[class.copy] p12 - // Before the implicitly-declared copy assignment operator for a class is - // implicitly defined, all implicitly-declared copy assignment operators - // for its direct base classes and its nonstatic data members shall have - // been implicitly defined. - bool err = false; + ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + + // C++0x [class.copy]p30: + // The implicitly-defined or explicitly-defaulted copy assignment operator + // for a non-union class X performs memberwise copy assignment of its + // subobjects. The direct base classes of X are assigned first, in the + // order of their declaration in the base-specifier-list, and then the + // immediate non-static data members of X are assigned, in the order in + // which they were declared in the class definition. + + // The statements that form the synthesized function body. + ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + + // The parameter for the "other" object, which we are copying from. + ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); + Qualifiers OtherQuals = Other->getType().getQualifiers(); + QualType OtherRefType = Other->getType(); + if (const LValueReferenceType *OtherRef + = OtherRefType->getAs<LValueReferenceType>()) { + OtherRefType = OtherRef->getPointeeType(); + OtherQuals = OtherRefType.getQualifiers(); + } + + // Our location for everything implicitly-generated. + SourceLocation Loc = CopyAssignOperator->getLocation(); + + // Construct a reference to the "other" object. We'll be using this + // throughout the generated ASTs. + Expr *OtherRef = BuildDeclRefExpr(Other, OtherRefType, Loc).takeAs<Expr>(); + assert(OtherRef && "Reference to parameter cannot fail!"); + + // Construct the "this" pointer. We'll be using this throughout the generated + // ASTs. + Expr *This = ActOnCXXThis(Loc).takeAs<Expr>(); + assert(This && "Reference to this cannot fail!"); + + // Assign base classes. + bool Invalid = false; for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), E = ClassDecl->bases_end(); Base != E; ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXMethodDecl *BaseAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - BaseClassDecl)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseAssignOpMethod, - PDiag(diag::err_access_assign_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod); + // Form the assignment: + // static_cast<Base*>(this)->Base::operator=(static_cast<Base&>(other)); + QualType BaseType = Base->getType().getUnqualifiedType(); + CXXRecordDecl *BaseClassDecl = 0; + if (const RecordType *BaseRecordT = BaseType->getAs<RecordType>()) + BaseClassDecl = cast<CXXRecordDecl>(BaseRecordT->getDecl()); + else { + Invalid = true; + continue; + } + + // Construct the "from" expression, which is an implicit cast to the + // appropriately-qualified base type. + Expr *From = OtherRef->Retain(); + ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), + CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true, + CXXBaseSpecifierArray(Base)); + + // Dereference "this". + OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + // Implicitly cast "this" to the appropriately-qualified base type. + Expr *ToE = To.takeAs<Expr>(); + ImpCastExprToType(ToE, + Context.getCVRQualifiedType(BaseType, + CopyAssignOperator->getTypeQualifiers()), + CastExpr::CK_UncheckedDerivedToBase, + /*isLvalue=*/true, CXXBaseSpecifierArray(Base)); + To = Owned(ToE); + + // Build the copy. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, + move(To), Owned(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Expr>()); } + + // \brief Reference to the __builtin_memcpy function. + Expr *BuiltinMemCpyRef = 0; + + // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), - E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = Context.getCanonicalType((*Field)->getType()); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) { - CXXRecordDecl *FieldClassDecl - = cast<CXXRecordDecl>(FieldClassType->getDecl()); - if (CXXMethodDecl *FieldAssignOpMethod = - getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0), - FieldClassDecl)) { - CheckDirectMemberAccess(Field->getLocation(), - FieldAssignOpMethod, - PDiag(diag::err_access_assign_field) - << Field->getDeclName() << Field->getType()); - - MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod); - } - } else if (FieldType->isReferenceType()) { + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + // Check for members of reference type; we can't copy those. + if (Field->getType()->isReferenceType()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; - } else if (FieldType.isConstQualified()) { + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; + } + + // Check for members of const-qualified, non-class type. + QualType BaseType = Context.getBaseElementType(Field->getType()); + if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) - << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); + << Context.getTagDeclType(ClassDecl) << 1 << Field->getDeclName(); Diag(Field->getLocation(), diag::note_declared_at); - Diag(CurrentLocation, diag::note_first_required_here); - err = true; + Diag(Loc, diag::note_first_required_here); + Invalid = true; + continue; } + + QualType FieldType = Field->getType().getNonReferenceType(); + + // Build references to the field in the object we're copying from and to. + CXXScopeSpec SS; // Intentionally empty + LookupResult MemberLookup(*this, Field->getDeclName(), Loc, + LookupMemberName); + MemberLookup.addDecl(*Field); + MemberLookup.resolveKind(); + OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()), + OtherRefType, + Loc, /*IsArrow=*/false, + SS, 0, MemberLookup, 0); + OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()), + This->getType(), + Loc, /*IsArrow=*/true, + SS, 0, MemberLookup, 0); + assert(!From.isInvalid() && "Implicit field reference cannot fail"); + assert(!To.isInvalid() && "Implicit field reference cannot fail"); + + // If the field should be copied with __builtin_memcpy rather than via + // explicit assignments, do so. This optimization only applies for arrays + // of scalars and arrays of class type with trivial copy-assignment + // operators. + if (FieldType->isArrayType() && + (!BaseType->isRecordType() || + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()) + ->hasTrivialCopyAssignment())) { + // Compute the size of the memory buffer to be copied. + QualType SizeType = Context.getSizeType(); + llvm::APInt Size(Context.getTypeSize(SizeType), + Context.getTypeSizeInChars(BaseType).getQuantity()); + for (const ConstantArrayType *Array + = Context.getAsConstantArrayType(FieldType); + Array; + Array = Context.getAsConstantArrayType(Array->getElementType())) { + llvm::APInt ArraySize = Array->getSize(); + ArraySize.zextOrTrunc(Size.getBitWidth()); + Size *= ArraySize; + } + + // Take the address of the field references for "from" and "to". + From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From)); + To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To)); + + // Create a reference to the __builtin_memcpy builtin function. + if (!BuiltinMemCpyRef) { + LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, + LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>(); + if (!BuiltinMemCpy) { + // Something went horribly wrong earlier, and we will have complained + // about it. + Invalid = true; + continue; + } + + BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, + BuiltinMemCpy->getType(), + Loc, 0).takeAs<Expr>(); + assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); + } + + ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this); + CallArgs.push_back(To.takeAs<Expr>()); + CallArgs.push_back(From.takeAs<Expr>()); + CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc)); + llvm::SmallVector<SourceLocation, 4> Commas; // FIXME: Silly + Commas.push_back(Loc); + Commas.push_back(Loc); + OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, + Owned(BuiltinMemCpyRef->Retain()), + Loc, move_arg(CallArgs), + Commas.data(), Loc); + assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); + Statements.push_back(Call.takeAs<Expr>()); + continue; + } + + // Build the copy of this field. + OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, + move(To), move(From)); + if (Copy.isInvalid()) { + Invalid = true; + continue; + } + + // Success! Record the copy. + Statements.push_back(Copy.takeAs<Stmt>()); } - if (!err) - MethodDecl->setUsed(); - CurContext = PreviousContext; -} + if (!Invalid) { + // Add a "return *this;" + OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, + Owned(This->Retain())); + + OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj)); + if (Return.isInvalid()) + Invalid = true; + else { + Statements.push_back(Return.takeAs<Stmt>()); + } + } -CXXMethodDecl * -Sema::getAssignOperatorMethod(SourceLocation CurrentLocation, - ParmVarDecl *ParmDecl, - CXXRecordDecl *ClassDecl) { - QualType LHSType = Context.getTypeDeclType(ClassDecl); - QualType RHSType(LHSType); - // If class's assignment operator argument is const/volatile qualified, - // look for operator = (const/volatile B&). Otherwise, look for - // operator = (B&). - RHSType = Context.getCVRQualifiedType(RHSType, - ParmDecl->getType().getCVRQualifiers()); - ExprOwningPtr<Expr> LHS(this, new (Context) DeclRefExpr(ParmDecl, - LHSType, - SourceLocation())); - ExprOwningPtr<Expr> RHS(this, new (Context) DeclRefExpr(ParmDecl, - RHSType, - CurrentLocation)); - Expr *Args[2] = { &*LHS, &*RHS }; - OverloadCandidateSet CandidateSet(CurrentLocation); - AddMemberOperatorCandidates(clang::OO_Equal, SourceLocation(), Args, 2, - CandidateSet); - OverloadCandidateSet::iterator Best; - if (BestViableFunction(CandidateSet, CurrentLocation, Best) == OR_Success) - return cast<CXXMethodDecl>(Best->Function); - assert(false && - "getAssignOperatorMethod - copy assignment operator method not found"); - return 0; + if (Invalid) { + CopyAssignOperator->setInvalidDecl(); + return; + } + + OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + /*isStmtExpr=*/false); + assert(!Body.isInvalid() && "Compound statement creation cannot fail"); + CopyAssignOperator->setBody(Body.takeAs<Stmt>()); } void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, @@ -3906,32 +4543,21 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, !CopyConstructor->isUsed()) && "DefineImplicitCopyConstructor - call it for implicit copy ctor"); - CXXRecordDecl *ClassDecl - = cast<CXXRecordDecl>(CopyConstructor->getDeclContext()); + CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); - DeclContext *PreviousContext = CurContext; - CurContext = CopyConstructor; + ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); - // C++ [class.copy] p209 - // Before the implicitly-declared copy constructor for a class is - // implicitly defined, all the implicitly-declared copy constructors - // for its base class and its non-static data members shall have been - // implicitly defined. - for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(); - Base != ClassDecl->bases_end(); ++Base) { - CXXRecordDecl *BaseClassDecl - = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - if (CXXConstructorDecl *BaseCopyCtor = - BaseClassDecl->getCopyConstructor(Context, TypeQuals)) { - CheckDirectMemberAccess(Base->getSourceRange().getBegin(), - BaseCopyCtor, - PDiag(diag::err_access_copy_base) - << Base->getType()); - - MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor); - } + if (SetBaseOrMemberInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false)) { + Diag(CurrentLocation, diag::note_member_synthesized_at) + << CXXCopyConstructor << Context.getTagDeclType(ClassDecl); + CopyConstructor->setInvalidDecl(); + } else { + CopyConstructor->setUsed(); } + + // FIXME: Once SetBaseOrMemberInitializers can handle copy initialization of + // fields, this code below should be removed. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), FieldEnd = ClassDecl->field_end(); Field != FieldEnd; ++Field) { @@ -3952,9 +4578,6 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } } } - CopyConstructor->setUsed(); - - CurContext = PreviousContext; } Sema::OwningExprResult @@ -3962,7 +4585,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { bool Elidable = false; // C++0x [class.copy]p34: @@ -3984,7 +4607,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, Elidable, move(ExprArgs), RequiresZeroInit, - BaseInitialization); + ConstructKind); } /// BuildCXXConstructExpr - Creates a complete call to a constructor, @@ -3994,14 +4617,14 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool RequiresZeroInit, - bool BaseInitialization) { + CXXConstructExpr::ConstructionKind ConstructKind) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, BaseInitialization)); + RequiresZeroInit, ConstructKind)); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, @@ -4138,113 +4761,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, FinalizeVarWithDestructor(VDecl, Record); } -/// \brief Add the applicable constructor candidates for an initialization -/// by constructor. -static void AddConstructorInitializationCandidates(Sema &SemaRef, - QualType ClassType, - Expr **Args, - unsigned NumArgs, - InitializationKind Kind, - OverloadCandidateSet &CandidateSet) { - // C++ [dcl.init]p14: - // If the initialization is direct-initialization, or if it is - // copy-initialization where the cv-unqualified version of the - // source type is the same class as, or a derived class of, the - // class of the destination, constructors are considered. The - // applicable constructors are enumerated (13.3.1.3), and the - // best one is chosen through overload resolution (13.3). The - // constructor so selected is called to initialize the object, - // with the initializer expression(s) as its argument(s). If no - // constructor applies, or the overload resolution is ambiguous, - // the initialization is ill-formed. - const RecordType *ClassRec = ClassType->getAs<RecordType>(); - assert(ClassRec && "Can only initialize a class type here"); - - // FIXME: When we decide not to synthesize the implicitly-declared - // constructors, we'll need to make them appear here. - - const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); - DeclarationName ConstructorName - = SemaRef.Context.DeclarationNames.getCXXConstructorName( - SemaRef.Context.getCanonicalType(ClassType).getUnqualifiedType()); - DeclContext::lookup_const_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(*Con); - - if ((Kind.getKind() == InitializationKind::IK_Direct) || - (Kind.getKind() == InitializationKind::IK_Value) || - (Kind.getKind() == InitializationKind::IK_Copy && - Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) || - ((Kind.getKind() == InitializationKind::IK_Default) && - Constructor->isDefaultConstructor())) { - if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet); - else - SemaRef.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet); - } - } -} - -/// \brief Attempt to perform initialization by constructor -/// (C++ [dcl.init]p14), which may occur as part of direct-initialization or -/// copy-initialization. -/// -/// This routine determines whether initialization by constructor is possible, -/// but it does not emit any diagnostics in the case where the initialization -/// is ill-formed. -/// -/// \param ClassType the type of the object being initialized, which must have -/// class type. -/// -/// \param Args the arguments provided to initialize the object -/// -/// \param NumArgs the number of arguments provided to initialize the object -/// -/// \param Kind the type of initialization being performed -/// -/// \returns the constructor used to initialize the object, if successful. -/// Otherwise, emits a diagnostic and returns NULL. -CXXConstructorDecl * -Sema::TryInitializationByConstructor(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, - InitializationKind Kind) { - // Build the overload candidate set - OverloadCandidateSet CandidateSet(Loc); - AddConstructorInitializationCandidates(*this, ClassType, Args, NumArgs, Kind, - CandidateSet); - - // Determine whether we found a constructor we can use. - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Loc, Best)) { - case OR_Success: - case OR_Deleted: - // We found a constructor. Return it. - return cast<CXXConstructorDecl>(Best->Function); - - case OR_No_Viable_Function: - case OR_Ambiguous: - // Overload resolution failed. Return nothing. - return 0; - } - - // Silence GCC warning - return 0; -} - /// \brief Given a constructor and the set of arguments provided for the /// constructor, convert the arguments and add any required default arguments /// to form a proper call to this constructor. @@ -4281,472 +4797,6 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, return Invalid; } -/// CompareReferenceRelationship - Compare the two types T1 and T2 to -/// determine whether they are reference-related, -/// reference-compatible, reference-compatible with added -/// qualification, or incompatible, for use in C++ initialization by -/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference -/// type, and the first type (T1) is the pointee type of the reference -/// type being initialized. -Sema::ReferenceCompareResult -Sema::CompareReferenceRelationship(SourceLocation Loc, - QualType OrigT1, QualType OrigT2, - bool& DerivedToBase) { - assert(!OrigT1->isReferenceType() && - "T1 must be the pointee type of the reference type"); - assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); - - QualType T1 = Context.getCanonicalType(OrigT1); - QualType T2 = Context.getCanonicalType(OrigT2); - Qualifiers T1Quals, T2Quals; - QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); - QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); - - // C++ [dcl.init.ref]p4: - // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is - // reference-related to "cv2 T2" if T1 is the same type as T2, or - // T1 is a base class of T2. - if (UnqualT1 == UnqualT2) - DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && - !RequireCompleteType(Loc, OrigT2, PDiag()) && - IsDerivedFrom(UnqualT2, UnqualT1)) - DerivedToBase = true; - else - return Ref_Incompatible; - - // At this point, we know that T1 and T2 are reference-related (at - // least). - - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); - - // C++ [dcl.init.ref]p4: - // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is - // reference-related to T2 and cv1 is the same cv-qualification - // as, or greater cv-qualification than, cv2. For purposes of - // overload resolution, cases for which cv1 is greater - // cv-qualification than cv2 are identified as - // reference-compatible with added qualification (see 13.3.3.2). - if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) - return Ref_Compatible; - else if (T1.isMoreQualifiedThan(T2)) - return Ref_Compatible_With_Added_Qualification; - else - return Ref_Related; -} - -/// CheckReferenceInit - Check the initialization of a reference -/// variable with the given initializer (C++ [dcl.init.ref]). Init is -/// the initializer (either a simple initializer or an initializer -/// list), and DeclType is the type of the declaration. When ICS is -/// non-null, this routine will compute the implicit conversion -/// sequence according to C++ [over.ics.ref] and will not produce any -/// diagnostics; when ICS is null, it will emit diagnostics when any -/// errors are found. Either way, a return value of true indicates -/// that there was a failure, a return value of false indicates that -/// the reference initialization succeeded. -/// -/// When @p SuppressUserConversions, user-defined conversions are -/// suppressed. -/// When @p AllowExplicit, we also permit explicit user-defined -/// conversion functions. -/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue. -/// When @p IgnoreBaseAccess, we don't do access control on to-base conversion. -/// This is used when this is called from a C-style cast. -bool -Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, - SourceLocation DeclLoc, - bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue, - ImplicitConversionSequence *ICS, - bool IgnoreBaseAccess) { - assert(DeclType->isReferenceType() && "Reference init needs a reference"); - - QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); - QualType T2 = Init->getType(); - - // If the initializer is the address of an overloaded function, try - // to resolve the overloaded function. If all goes well, T2 is the - // type of the resulting function. - if (Context.getCanonicalType(T2) == Context.OverloadTy) { - DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0, Found); - if (Fn) { - // Since we're performing this reference-initialization for - // real, update the initializer with the resulting function. - if (!ICS) { - if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; - - CheckAddressOfMemberAccess(Init, Found); - Init = FixOverloadedFunctionReference(Init, Found, Fn); - } - - T2 = Fn->getType(); - } - } - - // Compute some basic properties of the types and the initializer. - bool isRValRef = DeclType->isRValueReferenceType(); - bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : - Init->isLvalue(Context); - ReferenceCompareResult RefRelationship - = CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); - - // Most paths end in a failed conversion. - if (ICS) { - ICS->setBad(BadConversionSequence::no_conversion, Init, DeclType); - } - - // C++ [dcl.init.ref]p5: - // A reference to type "cv1 T1" is initialized by an expression - // of type "cv2 T2" as follows: - - // -- If the initializer expression - - // Rvalue references cannot bind to lvalues (N2812). - // There is absolutely no situation where they can. In particular, note that - // this is ill-formed, even if B has a user-defined conversion to A&&: - // B b; - // A&& r = b; - if (isRValRef && InitLvalue == Expr::LV_Valid) { - if (!ICS) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - return true; - } - - bool BindsDirectly = false; - // -- is an lvalue (but is not a bit-field), and "cv1 T1" is - // reference-compatible with "cv2 T2," or - // - // Note that the bit-field check is skipped if we are just computing - // the implicit conversion sequence (C++ [over.best.ics]p2). - if (InitLvalue == Expr::LV_Valid && (ICS || !Init->getBitField()) && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - BindsDirectly = true; - - if (ICS) { - // C++ [over.ics.ref]p1: - // When a parameter of reference type binds directly (8.5.3) - // to an argument expression, the implicit conversion sequence - // is the identity conversion, unless the argument expression - // has a type that is a derived class of the parameter type, - // in which case the implicit conversion sequence is a - // derived-to-base Conversion (13.3.3.1). - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = true; - ICS->Standard.RRefBinding = false; - ICS->Standard.CopyConstructor = 0; - - // Nothing more to do: the inaccessibility/ambiguity check for - // derived-to-base conversions is suppressed when we're - // computing the implicit conversion sequence (C++ - // [over.best.ics]p2). - return false; - } else { - // Perform the conversion. - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/true); - } - } - - // -- has a class type (i.e., T2 is a class type) and can be - // implicitly converted to an lvalue of type "cv3 T3," - // where "cv1 T1" is reference-compatible with "cv3 T3" - // 92) (this conversion is selected by enumerating the - // applicable conversion functions (13.3.1.6) and choosing - // the best one through overload resolution (13.3)), - if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && - !RequireCompleteType(DeclLoc, T2, 0)) { - CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); - - OverloadCandidateSet CandidateSet(DeclLoc); - const UnresolvedSetImpl *Conversions - = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSetImpl::iterator I = Conversions->begin(), - E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; - CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - FunctionTemplateDecl *ConvTemplate - = dyn_cast<FunctionTemplateDecl>(D); - CXXConversionDecl *Conv; - if (ConvTemplate) - Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); - else - Conv = cast<CXXConversionDecl>(D); - - // If the conversion function doesn't return a reference type, - // it can't be considered for this conversion. - if (Conv->getConversionType()->isLValueReferenceType() && - (AllowExplicit || !Conv->isExplicit())) { - if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet); - else - AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet); - } - } - - OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, DeclLoc, Best)) { - case OR_Success: - // C++ [over.ics.ref]p1: - // - // [...] If the parameter binds directly to the result of - // applying a conversion function to the argument - // expression, the implicit conversion sequence is a - // user-defined conversion sequence (13.3.3.1.2), with the - // second standard conversion sequence either an identity - // conversion or, if the conversion function returns an - // entity of a type that is a derived class of the parameter - // type, a derived-to-base Conversion. - if (!Best->FinalConversion.DirectBinding) - break; - - // This is a direct binding. - BindsDirectly = true; - - if (ICS) { - ICS->setUserDefined(); - ICS->UserDefined.Before = Best->Conversions[0].Standard; - ICS->UserDefined.After = Best->FinalConversion; - ICS->UserDefined.ConversionFunction = Best->Function; - ICS->UserDefined.EllipsisConversion = false; - assert(ICS->UserDefined.After.ReferenceBinding && - ICS->UserDefined.After.DirectBinding && - "Expected a direct reference binding!"); - return false; - } else { - OwningExprResult InitConversion = - BuildCXXCastArgument(DeclLoc, QualType(), - CastExpr::CK_UserDefinedConversion, - cast<CXXMethodDecl>(Best->Function), - Owned(Init)); - Init = InitConversion.takeAs<Expr>(); - - if (CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CastExpr::CK_UserDefinedConversion, - /*isLvalue=*/true); - } - break; - - case OR_Ambiguous: - if (ICS) { - ICS->setAmbiguous(); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) - if (Cand->Viable) - ICS->Ambiguous.addConversion(Cand->Function); - break; - } - Diag(DeclLoc, diag::err_ref_init_ambiguous) << DeclType << Init->getType() - << Init->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Init, 1); - return true; - - case OR_No_Viable_Function: - case OR_Deleted: - // There was no suitable conversion, or we found a deleted - // conversion; continue with other checks. - break; - } - } - - if (BindsDirectly) { - // C++ [dcl.init.ref]p4: - // [...] In all cases where the reference-related or - // reference-compatible relationship of two types is used to - // establish the validity of a reference binding, and T1 is a - // base class of T2, a program that necessitates such a binding - // is ill-formed if T1 is an inaccessible (clause 11) or - // ambiguous (10.2) base class of T2. - // - // Note that we only check this condition when we're allowed to - // complain about errors, because we should not be checking for - // ambiguity (or inaccessibility) unless the reference binding - // actually happens. - if (DerivedToBase) - return CheckDerivedToBaseConversion(T2, T1, DeclLoc, - Init->getSourceRange(), - IgnoreBaseAccess); - else - return false; - } - - // -- Otherwise, the reference shall be to a non-volatile const - // type (i.e., cv1 shall be const), or the reference shall be an - // rvalue reference and the initializer expression shall be an rvalue. - if (!isRValRef && T1.getCVRQualifiers() != Qualifiers::Const) { - if (!ICS) - Diag(DeclLoc, diag::err_not_reference_to_const_init) - << T1.isVolatileQualified() - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // -- If the initializer expression is an rvalue, with T2 a - // class type, and "cv1 T1" is reference-compatible with - // "cv2 T2," the reference is bound in one of the - // following ways (the choice is implementation-defined): - // - // -- The reference is bound to the object represented by - // the rvalue (see 3.10) or to a sub-object within that - // object. - // - // -- A temporary of type "cv1 T2" [sic] is created, and - // a constructor is called to copy the entire rvalue - // object into the temporary. The reference is bound to - // the temporary or to a sub-object within the - // temporary. - // - // The constructor that would be used to make the copy - // shall be callable whether or not the copy is actually - // done. - // - // Note that C++0x [dcl.init.ref]p5 takes away this implementation - // freedom, so we will always take the first option and never build - // a temporary in this case. FIXME: We will, however, have to check - // for the presence of a copy constructor in C++98/03 mode. - if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && - RefRelationship >= Ref_Compatible_With_Added_Qualification) { - if (ICS) { - ICS->setStandard(); - ICS->Standard.First = ICK_Identity; - ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS->Standard.Third = ICK_Identity; - ICS->Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS->Standard.setToType(0, T2); - ICS->Standard.setToType(1, T1); - ICS->Standard.setToType(2, T1); - ICS->Standard.ReferenceBinding = true; - ICS->Standard.DirectBinding = false; - ICS->Standard.RRefBinding = isRValRef; - ICS->Standard.CopyConstructor = 0; - } else { - CastExpr::CastKind CK = CastExpr::CK_NoOp; - if (DerivedToBase) - CK = CastExpr::CK_DerivedToBase; - else if(CheckExceptionSpecCompatibility(Init, T1)) - return true; - ImpCastExprToType(Init, T1, CK, /*isLvalue=*/false); - } - return false; - } - - // -- Otherwise, a temporary of type "cv1 T1" is created and - // initialized from the initializer expression using the - // rules for a non-reference copy initialization (8.5). The - // reference is then bound to the temporary. If T1 is - // reference-related to T2, cv1 must be the same - // cv-qualification as, or greater cv-qualification than, - // cv2; otherwise, the program is ill-formed. - if (RefRelationship == Ref_Related) { - // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then - // we would be reference-compatible or reference-compatible with - // added qualification. But that wasn't the case, so the reference - // initialization fails. - if (!ICS) - Diag(DeclLoc, diag::err_reference_init_drops_quals) - << T1 << int(InitLvalue != Expr::LV_Valid) - << T2 << Init->getSourceRange(); - return true; - } - - // If at least one of the types is a class type, the types are not - // related, and we aren't allowed any user conversions, the - // reference binding fails. This case is important for breaking - // recursion, since TryImplicitConversion below will attempt to - // create a temporary through the use of a copy constructor. - if (SuppressUserConversions && RefRelationship == Ref_Incompatible && - (T1->isRecordType() || T2->isRecordType())) { - if (!ICS) - Diag(DeclLoc, diag::err_typecheck_convert_incompatible) - << DeclType << Init->getType() << AA_Initializing << Init->getSourceRange(); - return true; - } - - // Actually try to convert the initializer to T1. - if (ICS) { - // C++ [over.ics.ref]p2: - // - // When a parameter of reference type is not bound directly to - // an argument expression, the conversion sequence is the one - // required to convert the argument expression to the - // underlying type of the reference according to - // 13.3.3.1. Conceptually, this conversion sequence corresponds - // to copy-initializing a temporary of the underlying type with - // the argument expression. Any difference in top-level - // cv-qualification is subsumed by the initialization itself - // and does not constitute a conversion. - *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - // Of course, that's still a reference binding. - if (ICS->isStandard()) { - ICS->Standard.ReferenceBinding = true; - ICS->Standard.RRefBinding = isRValRef; - } else if (ICS->isUserDefined()) { - ICS->UserDefined.After.ReferenceBinding = true; - ICS->UserDefined.After.RRefBinding = isRValRef; - } - return ICS->isBad(); - } else { - ImplicitConversionSequence Conversions; - bool badConversion = PerformImplicitConversion(Init, T1, AA_Initializing, - false, false, - Conversions); - if (badConversion) { - if (Conversions.isAmbiguous()) { - Diag(DeclLoc, - diag::err_lvalue_to_rvalue_ambig_ref) << Init->getSourceRange(); - for (int j = Conversions.Ambiguous.conversions().size()-1; - j >= 0; j--) { - FunctionDecl *Func = Conversions.Ambiguous.conversions()[j]; - NoteOverloadCandidate(Func); - } - } - else { - if (isRValRef) - Diag(DeclLoc, diag::err_lvalue_to_rvalue_ref) - << Init->getSourceRange(); - else - Diag(DeclLoc, diag::err_invalid_initialization) - << DeclType << Init->getType() << Init->getSourceRange(); - } - } - return badConversion; - } -} - static inline bool CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { @@ -5044,17 +5094,32 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { bool Valid = false; - // FIXME: Check for the one valid template signature - // template <char...> type operator "" name(); - - if (FunctionDecl::param_iterator Param = FnDecl->param_begin()) { + // template <char...> type operator "" name() is the only valid template + // signature, and the only valid signature with no parameters. + if (FnDecl->param_size() == 0) { + if (FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate()) { + // Must have only one template parameter + TemplateParameterList *Params = TpDecl->getTemplateParameters(); + if (Params->size() == 1) { + NonTypeTemplateParmDecl *PmDecl = + cast<NonTypeTemplateParmDecl>(Params->getParam(0)); + + // The template parameter must be a char parameter pack. + // FIXME: This test will always fail because non-type parameter packs + // have not been implemented. + if (PmDecl && PmDecl->isTemplateParameterPack() && + Context.hasSameType(PmDecl->getType(), Context.CharTy)) + Valid = true; + } + } + } else { // Check the first parameter + FunctionDecl::param_iterator Param = FnDecl->param_begin(); + QualType T = (*Param)->getType(); - // unsigned long long int and long double are allowed, but only - // alone. - // We also allow any character type; their omission seems to be a bug - // in n3000 + // unsigned long long int, long double, and any character type are allowed + // as the only parameters. if (Context.hasSameType(T, Context.UnsignedLongLongTy) || Context.hasSameType(T, Context.LongDoubleTy) || Context.hasSameType(T, Context.CharTy) || @@ -5066,7 +5131,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { goto FinishedParams; } - // Otherwise it must be a pointer to const; let's strip those. + // Otherwise it must be a pointer to const; let's strip those qualifiers. const PointerType *PT = T->getAs<PointerType>(); if (!PT) goto FinishedParams; @@ -5121,13 +5186,12 @@ FinishedParams: Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, - const char *Lang, - unsigned StrSize, + llvm::StringRef Lang, SourceLocation LBraceLoc) { LinkageSpecDecl::LanguageIDs Language; - if (strncmp(Lang, "\"C\"", StrSize) == 0) + if (Lang == "\"C\"") Language = LinkageSpecDecl::lang_c; - else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + else if (Lang == "\"C++\"") Language = LinkageSpecDecl::lang_cxx; else { Diag(LangLoc, diag::err_bad_language); @@ -5212,8 +5276,10 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, Invalid = true; VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, TInfo, VarDecl::None); - + Name, ExDeclType, TInfo, VarDecl::None, + VarDecl::None); + ExDecl->setExceptionVariable(true); + if (!Invalid) { if (const RecordType *RecordTy = ExDeclType->getAs<RecordType>()) { // C++ [except.handle]p16: @@ -5254,7 +5320,9 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); - if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { + if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); @@ -5318,6 +5386,62 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, return DeclPtrTy::make(Decl); } +/// \brief Perform semantic analysis of the given friend type declaration. +/// +/// \returns A friend declaration that. +FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, + TypeSourceInfo *TSInfo) { + assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); + + QualType T = TSInfo->getType(); + SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); + + if (!getLangOptions().CPlusPlus0x) { + // C++03 [class.friend]p2: + // An elaborated-type-specifier shall be used in a friend declaration + // for a class.* + // + // * The class-key of the elaborated-type-specifier is required. + if (!ActiveTemplateInstantiations.empty()) { + // Do not complain about the form of friend template types during + // template instantiation; we will already have complained when the + // template was declared. + } else if (!T->isElaboratedTypeSpecifier()) { + // If we evaluated the type to a record type, suggest putting + // a tag in front. + if (const RecordType *RT = T->getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + + std::string InsertionText = std::string(" ") + RD->getKindName(); + + Diag(TypeRange.getBegin(), diag::ext_unelaborated_friend_type) + << (unsigned) RD->getTagKind() + << T + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc), + InsertionText); + } else { + Diag(FriendLoc, diag::ext_nonclass_type_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } else if (T->getAs<EnumType>()) { + Diag(FriendLoc, diag::ext_enum_friend) + << T + << SourceRange(FriendLoc, TypeRange.getEnd()); + } + } + + // C++0x [class.friend]p3: + // If the type specifier in a friend declaration designates a (possibly + // cv-qualified) class type, that class is declared as a friend; otherwise, + // the friend declaration is ignored. + + // FIXME: C++0x has some syntactic restrictions on friend type declarations + // in [class.friend]p3 that we do not implement. + + return FriendDecl::Create(Context, CurContext, FriendLoc, TSInfo, FriendLoc); +} + /// Handle a friend type declaration. This works in tandem with /// ActOnTag. /// @@ -5351,6 +5475,9 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TheDeclarator.isInvalidType()) return DeclPtrTy(); + if (!TSI) + TSI = Context.getTrivialTypeSourceInfo(T, DS.getSourceRange().getBegin()); + // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just // poorly written. @@ -5370,41 +5497,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, << DS.getSourceRange(); return DeclPtrTy(); } - - // C++ [class.friend]p2: - // An elaborated-type-specifier shall be used in a friend declaration - // for a class.* - // * The class-key of the elaborated-type-specifier is required. - // This is one of the rare places in Clang where it's legitimate to - // ask about the "spelling" of the type. - if (!getLangOptions().CPlusPlus0x && !T->isElaboratedTypeSpecifier()) { - // If we evaluated the type to a record type, suggest putting - // a tag in front. - if (const RecordType *RT = T->getAs<RecordType>()) { - RecordDecl *RD = RT->getDecl(); - - std::string InsertionText = std::string(" ") + RD->getKindName(); - - Diag(DS.getTypeSpecTypeLoc(), diag::err_unelaborated_friend_type) - << (unsigned) RD->getTagKind() - << T - << SourceRange(DS.getFriendSpecLoc()) - << FixItHint::CreateInsertion(DS.getTypeSpecTypeLoc(), InsertionText); - return DeclPtrTy(); - }else { - Diag(DS.getFriendSpecLoc(), diag::err_unexpected_friend) - << DS.getSourceRange(); - return DeclPtrTy(); - } - } - - // Enum types cannot be friends. - if (T->getAs<EnumType>()) { - Diag(DS.getTypeSpecTypeLoc(), diag::err_enum_friend) - << SourceRange(DS.getFriendSpecLoc()); - return DeclPtrTy(); - } - + // C++98 [class.friend]p1: A friend of a class is a function // or class that is not a member of the class . . . // This is fixed in DR77, which just barely didn't make the C++03 @@ -5417,15 +5510,18 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend a member of an arbitrary specialization of your template). Decl *D; - if (TempParams.size()) + if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, - TempParams.size(), + NumTempParamLists, (TemplateParameterList**) TempParams.release(), TSI, DS.getFriendSpecLoc()); else - D = FriendDecl::Create(Context, CurContext, Loc, TSI, - DS.getFriendSpecLoc()); + D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI); + + if (!D) + return DeclPtrTy(); + D->setAccess(AS_public); CurContext->addDecl(D); @@ -5493,11 +5589,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S, LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, ForRedeclaration); if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { - // FIXME: RequireCompleteDeclContext DC = computeDeclContext(ScopeQual); // FIXME: handle dependent contexts if (!DC) return DeclPtrTy(); + if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy(); LookupQualifiedName(Previous, DC); @@ -5595,9 +5691,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) - FrD->setSpecialization(true); - return DeclPtrTy::make(ND); } @@ -5701,10 +5794,10 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // Check if we the conversion from derived to base is valid. if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, - diag::err_covariant_return_inaccessible_base, - diag::err_covariant_return_ambiguous_derived_to_base_conv, - // FIXME: Should this point to the return type? - New->getLocation(), SourceRange(), New->getDeclName())) { + diag::err_covariant_return_inaccessible_base, + diag::err_covariant_return_ambiguous_derived_to_base_conv, + // FIXME: Should this point to the return type? + New->getLocation(), SourceRange(), New->getDeclName(), 0)) { Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } @@ -5830,7 +5923,7 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return Dcl; } -static bool needsVtable(CXXMethodDecl *MD, ASTContext &Context) { +static bool needsVTable(CXXMethodDecl *MD, ASTContext &Context) { // Ignore dependent types. if (MD->isDependentContext()) return false; @@ -5893,7 +5986,7 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc, // We will need to mark all of the virtual members as referenced to build the // vtable. - if (!needsVtable(MD, Context)) + if (!needsVTable(MD, Context)) return; TemplateSpecializationKind kind = RD->getTemplateSpecializationKind(); @@ -5944,3 +6037,44 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, MarkVirtualMembersReferenced(Loc, Base); } } + +/// SetIvarInitializers - This routine builds initialization ASTs for the +/// Objective-C implementation whose ivars need be initialized. +void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { + if (!getLangOptions().CPlusPlus) + return; + if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { + llvm::SmallVector<ObjCIvarDecl*, 8> ivars; + CollectIvarsToConstructOrDestruct(OID, ivars); + if (ivars.empty()) + return; + llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit; + for (unsigned i = 0; i < ivars.size(); i++) { + FieldDecl *Field = ivars[i]; + CXXBaseOrMemberInitializer *Member; + InitializedEntity InitEntity = InitializedEntity::InitializeMember(Field); + InitializationKind InitKind = + InitializationKind::CreateDefault(ObjCImplementation->getLocation()); + + InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); + Sema::OwningExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, + Sema::MultiExprArg(*this, 0, 0)); + MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + // Note, MemberInit could actually come back empty if no initialization + // is required (e.g., because it would call a trivial default constructor) + if (!MemberInit.get() || MemberInit.isInvalid()) + continue; + + Member = + new (Context) CXXBaseOrMemberInitializer(Context, + Field, SourceLocation(), + SourceLocation(), + MemberInit.takeAs<Expr>(), + SourceLocation()); + AllToInit.push_back(Member); + } + ObjCImplementation->setIvarInitializers(Context, + AllToInit.data(), AllToInit.size()); + } +} diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 0c47e63..d446cc1 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -66,13 +66,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. - NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); - if (PrevDecl && PrevDecl->isTemplateParameter()) { - // Maybe we will complain about the shadowed template parameter. - DiagnoseTemplateParameterShadow(ClassLoc, PrevDecl); - // Just pretend that we didn't see the previous declaration. - PrevDecl = 0; - } + NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc, + LookupOrdinaryName, ForRedeclaration); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; @@ -98,6 +93,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Since this ObjCInterfaceDecl was created by a forward declaration, // we now add it to the DeclContext since it wasn't added before // (see ActOnForwardClassDeclaration). + IDecl->setLexicalDeclContext(CurContext); CurContext->addDecl(IDecl); if (AttrList) @@ -114,12 +110,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (SuperName) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, LookupOrdinaryName); + PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); if (!PrevDecl) { // Try to correct for a typo in the superclass name. LookupResult R(*this, SuperName, SuperLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (PrevDecl = R.getAsSingle<ObjCInterfaceDecl>())) { Diag(SuperLoc, diag::err_undef_superclass_suggest) << SuperName << ClassName << PrevDecl->getDeclName(); @@ -198,7 +195,8 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, IdentifierInfo *ClassName, SourceLocation ClassLocation) { // Look for previous declaration of alias name - NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, LookupOrdinaryName); + NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation, + LookupOrdinaryName, ForRedeclaration); if (ADecl) { if (isa<ObjCCompatibleAliasDecl>(ADecl)) Diag(AliasLocation, diag::warn_previous_alias_decl); @@ -208,13 +206,15 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, return DeclPtrTy(); } // Check for class declaration - NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, + LookupOrdinaryName, ForRedeclaration); if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCInterfaceType()) { if (NamedDecl *IDecl = T->getAs<ObjCInterfaceType>()->getDecl()) { ClassName = IDecl->getIdentifier(); - CDeclU = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, + LookupOrdinaryName, ForRedeclaration); } } } @@ -243,7 +243,8 @@ void Sema::CheckForwardProtocolDeclarationForCircularDependency( for (ObjCList<ObjCProtocolDecl>::iterator I = PList.begin(), E = PList.end(); I != E; ++I) { - if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier())) { + if (ObjCProtocolDecl *PDecl = LookupProtocol((*I)->getIdentifier(), + Ploc)) { if (PDecl->getIdentifier() == PName) { Diag(Ploc, diag::err_protocol_has_circular_dependency); Diag(PrevLoc, diag::note_previous_definition); @@ -265,7 +266,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, AttributeList *AttrList) { // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); - ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName); + ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolName, ProtocolLoc); if (PDecl) { // Protocol already seen. Better be a forward protocol declaration if (!PDecl->isForwardDecl()) { @@ -312,11 +313,12 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, unsigned NumProtocols, llvm::SmallVectorImpl<DeclPtrTy> &Protocols) { for (unsigned i = 0; i != NumProtocols; ++i) { - ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first); + ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, + ProtocolId[i].second); if (!PDecl) { LookupResult R(*this, ProtocolId[i].first, ProtocolId[i].second, LookupObjCProtocolName); - if (CorrectTypo(R, TUScope, 0) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (PDecl = R.getAsSingle<ObjCProtocolDecl>())) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) << ProtocolId[i].first << R.getLookupName(); @@ -382,7 +384,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; - ObjCProtocolDecl *PDecl = LookupProtocol(Ident); + ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); if (PDecl == 0) { // Not already seen? PDecl = ObjCProtocolDecl::Create(Context, CurContext, IdentList[i].second, Ident); @@ -413,7 +415,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = 0; - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); /// Check that class of this category is already completely declared. if (!IDecl || IDecl->isForwardDecl()) { @@ -491,7 +493,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { - ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc); + ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = 0; if (IDecl) { CatIDecl = IDecl->FindCategoryDeclaration(CatName); @@ -539,7 +541,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( ObjCInterfaceDecl* IDecl = 0; // Check for another declaration kind with the same name. NamedDecl *PrevDecl - = LookupSingleName(TUScope, ClassName, LookupOrdinaryName); + = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -553,7 +556,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( // We did not find anything with the name ClassName; try to correct for // typos in the class name. LookupResult R(*this, ClassName, ClassLoc, LookupOrdinaryName); - if (CorrectTypo(R, TUScope, 0) && + if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) && (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) { // Suggest the (potentially) correct interface name. However, put the // fix-it hint itself in a separate note, since changing the name in @@ -576,7 +579,8 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( ObjCInterfaceDecl* SDecl = 0; if (SuperClassname) { // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperClassname, LookupOrdinaryName); + PrevDecl = LookupSingleName(TUScope, SuperClassname, SuperClassLoc, + LookupOrdinaryName); if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) { Diag(SuperClassLoc, diag::err_redefinition_different_kind) << SuperClassname; @@ -1003,7 +1007,8 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, for (unsigned i = 0; i != NumElts; ++i) { // Check for another declaration kind with the same name. NamedDecl *PrevDecl - = LookupSingleName(TUScope, IdentList[i], LookupOrdinaryName); + = LookupSingleName(TUScope, IdentList[i], IdentLocs[i], + LookupOrdinaryName, ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(AtClassLoc, PrevDecl); @@ -1436,6 +1441,7 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, IDecl = IDecl->getSuperClass(); } } + SetIvarInitializers(IC); } else if (ObjCCategoryImplDecl* CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { CatImplClass->setAtEndRange(AtEnd); @@ -1487,6 +1493,16 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { return ret; } +static inline +bool containsInvalidMethodImplAttribute(const AttributeList *A) { + // The 'ibaction' attribute is allowed on method definitions because of + // how the IBAction macro is used on both method declarations and definitions. + // If the method definitions contains any other attributes, return true. + while (A && A->getKind() == AttributeList::AT_IBAction) + A = A->getNext(); + return A != NULL; +} + Sema::DeclPtrTy Sema::ActOnMethodDeclaration( SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, DeclPtrTy classDecl, @@ -1495,7 +1511,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, - llvm::SmallVectorImpl<Declarator> &Cdecls, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic) { Decl *ClassDecl = classDecl.getAs<Decl>(); @@ -1550,7 +1566,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, DI, - VarDecl::None, 0); + VarDecl::None, VarDecl::None, 0); if (ArgType->isObjCInterfaceType()) { Diag(ArgInfo[i].NameLoc, @@ -1568,7 +1584,27 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( Params.push_back(Param); } - ObjCMethod->setMethodParams(Context, Params.data(), Sel.getNumArgs()); + for (unsigned i = 0, e = CNumArgs; i != e; ++i) { + ParmVarDecl *Param = CParamInfo[i].Param.getAs<ParmVarDecl>(); + QualType ArgType = Param->getType(); + if (ArgType.isNull()) + ArgType = Context.getObjCIdType(); + else + // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). + ArgType = adjustParameterType(ArgType); + if (ArgType->isObjCInterfaceType()) { + Diag(Param->getLocation(), + diag::err_object_cannot_be_passed_returned_by_value) + << 1 << ArgType; + Param->setInvalidDecl(); + } + Param->setDeclContext(ObjCMethod); + IdResolver.RemoveDecl(Param); + Params.push_back(Param); + } + + ObjCMethod->setMethodParams(Context, Params.data(), Params.size(), + Sel.getNumArgs()); ObjCMethod->setObjCDeclQualifier( CvtQTToAstBitMask(ReturnQT.getObjCDeclQualifier())); const ObjCMethodDecl *PrevMethod = 0; @@ -1593,7 +1629,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, MethodType == tok::minus); - if (AttrList) + if (containsInvalidMethodImplAttribute(AttrList)) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = dyn_cast<ObjCCategoryImplDecl>(ClassDecl)) { @@ -1604,7 +1640,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = CatImpDecl->getClassMethod(Sel); CatImpDecl->addClassMethod(ObjCMethod); } - if (AttrList) + if (containsInvalidMethodImplAttribute(AttrList)) Diag(EndLoc, diag::warn_attribute_method_def); } if (PrevMethod) { @@ -1638,7 +1674,7 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclPtrTy> &Decls) { // Check that ClassName is a valid class - ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName); + ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { Diag(DeclStart, diag::err_undef_interface) << ClassName; return; @@ -1672,3 +1708,146 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, } } +/// \brief Build a type-check a new Objective-C exception variable declaration. +VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, + QualType T, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool Invalid) { + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // duration shall not be qualified by an address-space qualifier." + // Since all parameters have automatic store duration, they can not have + // an address space. + if (T.getAddressSpace() != 0) { + Diag(NameLoc, diag::err_arg_with_address_space); + Invalid = true; + } + + // An @catch parameter must be an unqualified object pointer type; + // FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"? + if (Invalid) { + // Don't do any further checking. + } else if (T->isDependentType()) { + // Okay: we don't know what this type will instantiate to. + } else if (!T->isObjCObjectPointerType()) { + Invalid = true; + Diag(NameLoc ,diag::err_catch_param_not_objc_type); + } else if (T->isObjCQualifiedIdType()) { + Invalid = true; + Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm); + } + + VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo, + VarDecl::None, VarDecl::None); + New->setExceptionVariable(true); + + if (Invalid) + New->setInvalidDecl(); + return New; +} + +Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { + const DeclSpec &DS = D.getDeclSpec(); + + // We allow the "register" storage class on exception variables because + // GCC did, but we drop it completely. Any other storage class is an error. + if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), diag::warn_register_objc_catch_parm) + << FixItHint::CreateRemoval(SourceRange(DS.getStorageClassSpecLoc())); + } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { + Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) + << DS.getStorageClassSpec(); + } + if (D.getDeclSpec().isThreadSpecified()) + Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + D.getMutableDeclSpec().ClearStorageClassSpecs(); + + DiagnoseFunctionSpecifiers(D); + + // Check that there are no default arguments inside the type of this + // exception object (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + + TypeSourceInfo *TInfo = 0; + TagDecl *OwnedDecl = 0; + QualType ExceptionType = GetTypeForDeclarator(D, S, &TInfo, &OwnedDecl); + + if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { + // Objective-C++: Types shall not be defined in exception types. + Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) + << Context.getTypeDeclType(OwnedDecl); + } + + VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(), + D.getIdentifierLoc(), + D.isInvalidType()); + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_objc_catch_parm) + << D.getCXXScopeSpec().getRange(); + New->setInvalidDecl(); + } + + // Add the parameter declaration into this scope. + S->AddDecl(DeclPtrTy::make(New)); + if (D.getIdentifier()) + IdResolver.AddDecl(New); + + ProcessDeclAttributes(S, New, D); + + if (New->hasAttr<BlocksAttr>()) + Diag(New->getLocation(), diag::err_block_on_nonlocal); + return DeclPtrTy::make(New); +} + +/// CollectIvarsToConstructOrDestruct - Collect those ivars which require +/// initialization. +void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + + // Find ivars to construct/destruct in class extension. + if (const ObjCCategoryDecl *CDecl = OI->getClassExtension()) { + for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); I != E; ++I) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + } + + // Also add any 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) { + ObjCIvarDecl *Iv = (*I); + QualType QT = Context.getBaseElementType(Iv->getType()); + if (isa<RecordType>(QT)) + Ivars.push_back(*I); + } + } +} + +void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, + CXXBaseOrMemberInitializer ** initializers, + unsigned numInitializers) { + if (numInitializers > 0) { + NumIvarInitializers = numInitializers; + CXXBaseOrMemberInitializer **ivarInitializers = + new (C) CXXBaseOrMemberInitializer*[NumIvarInitializers]; + memcpy(ivarInitializers, initializers, + numInitializers * sizeof(CXXBaseOrMemberInitializer*)); + IvarInitializers = ivarInitializers; + } +} + diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2dfb954..c4ab03f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -16,10 +16,13 @@ #include "Lookup.h" #include "AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -80,6 +83,9 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, const SentinelAttr *attr = D->getAttr<SentinelAttr>(); if (!attr) return; + + // FIXME: In C++0x, if any of the arguments are parameter pack + // expansions, we can't check for the sentinel now. int sentinelPos = attr->getSentinel(); int nullPos = attr->getNullPos(); @@ -155,6 +161,8 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, } Expr *sentinelExpr = Args[sentinel]; if (sentinelExpr && (!isa<GNUNullExpr>(sentinelExpr) && + !sentinelExpr->isTypeDependent() && + !sentinelExpr->isValueDependent() && (!sentinelExpr->getType()->isPointerType() || !sentinelExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)))) { @@ -454,7 +462,10 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, } if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { + if (isa<NonTypeTemplateParmDecl>(VD)) { + // Non-type template parameters can be referenced anywhere they are + // visible. + } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function) @@ -769,24 +780,6 @@ static bool IsProvablyNotDerivedFrom(Sema &SemaRef, return true; } -/// Determines if this is an instance member of a class. -static bool IsInstanceMember(NamedDecl *D) { - assert(D->isCXXClassMember() && - "checking whether non-member is instance member"); - - if (isa<FieldDecl>(D)) return true; - - if (isa<CXXMethodDecl>(D)) - return !cast<CXXMethodDecl>(D)->isStatic(); - - if (isa<FunctionTemplateDecl>(D)) { - D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl(); - return !cast<CXXMethodDecl>(D)->isStatic(); - } - - return false; -} - enum IMAKind { /// The reference is definitely not an instance member access. IMA_Static, @@ -846,8 +839,8 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, bool hasNonInstance = false; llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes; for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { - NamedDecl *D = (*I)->getUnderlyingDecl(); - if (IsInstanceMember(D)) { + NamedDecl *D = *I; + if (D->isCXXInstanceMember()) { CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext()); // If this is a member of an anonymous record, move out to the @@ -913,7 +906,7 @@ static void DiagnoseInstanceReference(Sema &SemaRef, /// Diagnose an empty lookup. /// /// \return false if new lookup candidates were found -bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, +bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R) { DeclarationName Name = R.getLookupName(); @@ -964,43 +957,55 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, } // We didn't find anything, so try to correct for a typo. - if (S && CorrectTypo(R, S, &SS)) { - if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { - if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - else - Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() - << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), - R.getLookupName().getAsString()); - if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) - Diag(ND->getLocation(), diag::note_previous_decl) - << ND->getDeclName(); - - // Tell the callee to try to recover. - return false; - } + DeclarationName Corrected; + if (S && (Corrected = CorrectTypo(R, S, &SS))) { + if (!R.empty()) { + if (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin())) { + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName() + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange() + << FixItHint::CreateReplacement(R.getNameLoc(), + R.getLookupName().getAsString()); + if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + + // Tell the callee to try to recover. + return false; + } + + if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { + // FIXME: If we ended up with a typo for a type name or + // Objective-C class name, we're in trouble because the parser + // is in the wrong place to recover. Suggest the typo + // correction, but don't make it a fix-it since we're not going + // to recover well anyway. + if (SS.isEmpty()) + Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); + else + Diag(R.getNameLoc(), diag::err_no_member_suggest) + << Name << computeDeclContext(SS, false) << R.getLookupName() + << SS.getRange(); - if (isa<TypeDecl>(*R.begin()) || isa<ObjCInterfaceDecl>(*R.begin())) { - // FIXME: If we ended up with a typo for a type name or - // Objective-C class name, we're in trouble because the parser - // is in the wrong place to recover. Suggest the typo - // correction, but don't make it a fix-it since we're not going - // to recover well anyway. + // Don't try to recover; it won't work. + return true; + } + } else { + // FIXME: We found a keyword. Suggest it, but don't provide a fix-it + // because we aren't able to recover. if (SS.isEmpty()) - Diag(R.getNameLoc(), diagnostic_suggest) << Name << R.getLookupName(); + Diag(R.getNameLoc(), diagnostic_suggest) << Name << Corrected; else Diag(R.getNameLoc(), diag::err_no_member_suggest) - << Name << computeDeclContext(SS, false) << R.getLookupName() - << SS.getRange(); - - // Don't try to recover; it won't work. + << Name << computeDeclContext(SS, false) << Corrected + << SS.getRange(); return true; } - R.clear(); } @@ -1019,7 +1024,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, const CXXScopeSpec &SS, } Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Id, bool HasTrailingLParen, bool isAddressOfOperand) { @@ -1064,6 +1069,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, if (TemplateArgs) { // Just re-use the lookup done by isTemplateName. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); @@ -1123,16 +1137,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // Warn about constructs like: // if (void *X = foo()) { ... } else { X }. // In the else block, the pointer is always false. - if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { Scope *CheckS = S; while (CheckS && CheckS->getControlParent()) { - if (CheckS->isWithinElse() && + if ((CheckS->getFlags() & Scope::ElseScope) && CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { ExprError(Diag(NameLoc, diag::warn_value_always_zero) << Var->getDeclName() - << (Var->getType()->isPointerType()? 2 : - Var->getType()->isBooleanType()? 1 : 0)); + << (Var->getType()->isPointerType() ? 2 : + Var->getType()->isBooleanType() ? 1 : 0)); break; } @@ -1218,15 +1231,16 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, /// There's a large number of things which don't need to be done along /// this path. Sema::OwningExprResult -Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, +Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc) { DeclContext *DC; - if (!(DC = computeDeclContext(SS, false)) || - DC->isDependentContext() || - RequireCompleteDeclContext(SS)) + if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext()) return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0); + if (RequireCompleteDeclContext(SS, DC)) + return ExprError(); + LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); LookupQualifiedName(R, DC); @@ -1251,9 +1265,9 @@ Sema::BuildQualifiedDeclarationNameExpr(const CXXScopeSpec &SS, /// Returns a null sentinel to indicate trivial success. Sema::OwningExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, - IdentifierInfo *II, - bool AllowBuiltinCreation) { + IdentifierInfo *II, bool AllowBuiltinCreation) { SourceLocation Loc = Lookup.getNameLoc(); + ObjCMethodDecl *CurMethod = getCurMethodDecl(); // There are two cases to handle here. 1) scoped lookup could have failed, // in which case we should look for an ivar. 2) scoped lookup could have @@ -1264,7 +1278,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, // If we're in a class method, we don't normally want to look for // ivars. But if we don't find anything else, and there's an // ivar, that's an error. - bool IsClassMethod = getCurMethodDecl()->isClassMethod(); + bool IsClassMethod = CurMethod->isClassMethod(); bool LookForIvars; if (Lookup.empty()) @@ -1276,7 +1290,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); ObjCInterfaceDecl *IFace = 0; if (LookForIvars) { - IFace = getCurMethodDecl()->getClassInterface(); + IFace = CurMethod->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { // Diagnose using an ivar in a class method. @@ -1311,9 +1325,9 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCIvarRefExpr(IV, IV->getType(), Loc, SelfExpr.takeAs<Expr>(), true, true)); } - } else if (getCurMethodDecl()->isInstanceMethod()) { + } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. - ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface(); + ObjCInterfaceDecl *IFace = CurMethod->getClassInterface(); ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II, ClassDeclared)) { if (IV->getAccessControl() != ObjCIvarDecl::Private || @@ -1322,17 +1336,6 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, } } - // Needed to implement property "super.method" notation. - if (Lookup.empty() && II->isStr("super")) { - QualType T; - - if (getCurMethodDecl()->isInstanceMethod()) - T = Context.getObjCObjectPointerType(Context.getObjCInterfaceType( - getCurMethodDecl()->getClassInterface())); - else - T = Context.getObjCClassType(); - return Owned(new (Context) ObjCSuperExpr(Loc, T)); - } if (Lookup.empty() && II && AllowBuiltinCreation) { // FIXME. Consolidate this with similar code in LookupName. if (unsigned BuiltinID = II->getBuiltinID()) { @@ -1449,14 +1452,15 @@ Sema::PerformObjectMemberConversion(Expr *&From, // type of the object type, in which case we just ignore it. // Otherwise build the appropriate casts. if (IsDerivedFrom(FromRecordType, QRecordType)) { + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, - FromLoc, FromRange)) + FromLoc, FromRange, &BasePath)) return true; if (PointerConversions) QType = Context.getPointerType(QType); ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1484,15 +1488,16 @@ Sema::PerformObjectMemberConversion(Expr *&From, // conversion is non-trivial. if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { assert(IsDerivedFrom(FromRecordType, URecordType)); + CXXBaseSpecifierArray BasePath; if (CheckDerivedToBaseConversion(FromRecordType, URecordType, - FromLoc, FromRange)) + FromLoc, FromRange, &BasePath)) return true; - + QualType UType = URecordType; if (PointerConversions) UType = Context.getPointerType(UType); ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1502,23 +1507,22 @@ Sema::PerformObjectMemberConversion(Expr *&From, IgnoreAccess = true; } - if (CheckDerivedToBaseConversion(FromRecordType, - DestRecordType, - FromLoc, - FromRange, + CXXBaseSpecifierArray BasePath; + if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, + FromLoc, FromRange, &BasePath, IgnoreAccess)) return true; ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/ !PointerConversions); + /*isLvalue=*/!PointerConversions, BasePath); return false; } /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, - NamedDecl *FoundDecl, SourceLocation Loc, - QualType Ty, + DeclAccessPair FoundDecl, + SourceLocation Loc, QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -2484,7 +2488,8 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, } } - assert(BaseType->isDependentType() || Name.isDependentName()); + assert(BaseType->isDependentType() || Name.isDependentName() || + isDependentScopeSpecifier(SS)); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. @@ -2510,11 +2515,8 @@ static void DiagnoseQualifiedMemberReference(Sema &SemaRef, if (!BaseExpr) return DiagnoseInstanceReference(SemaRef, SS, R); - // FIXME: this is an exceedingly lame diagnostic for some of the more - // complicated cases here. - DeclContext *DC = R.getRepresentativeDecl()->getDeclContext(); - SemaRef.Diag(R.getNameLoc(), diag::err_not_direct_base_or_virtual) - << SS.getRange() << DC << BaseType; + SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_of_unrelated) + << SS.getRange() << R.getRepresentativeDecl() << BaseType; } // Check whether the declarations we found through a nested-name @@ -2545,7 +2547,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { // If this is an implicit member reference and we find a // non-instance member, it's not an error. - if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl())) + if (!BaseExpr && !(*I)->isCXXInstanceMember()) return false; // Note that we use the DC of the decl, not the underlying decl. @@ -2567,7 +2569,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, SourceRange BaseRange, const RecordType *RTy, - SourceLocation OpLoc, const CXXScopeSpec &SS) { + SourceLocation OpLoc, CXXScopeSpec &SS) { RecordDecl *RDecl = RTy->getDecl(); if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0), SemaRef.PDiag(diag::err_typecheck_incomplete_tag) @@ -2580,7 +2582,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // nested-name-specifier. DC = SemaRef.computeDeclContext(SS, false); - if (SemaRef.RequireCompleteDeclContext(SS)) { + if (SemaRef.RequireCompleteDeclContext(SS, DC)) { SemaRef.Diag(SS.getRange().getEnd(), diag::err_typecheck_incomplete_tag) << SS.getRange() << DC; return true; @@ -2604,7 +2606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, // We didn't find anything with the given name, so try to correct // for typos. DeclarationName Name = R.getLookupName(); - if (SemaRef.CorrectTypo(R, 0, &SS, DC) && + if (SemaRef.CorrectTypo(R, 0, &SS, DC, false, Sema::CTC_MemberLookup) && + !R.empty() && (isa<ValueDecl>(*R.begin()) || isa<FunctionTemplateDecl>(*R.begin()))) { SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << R.getLookupName() << SS.getRange() @@ -2624,7 +2627,7 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, Sema::OwningExprResult Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo *TemplateArgs) { @@ -2675,13 +2678,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck) { Expr *BaseExpr = Base.takeAs<Expr>(); QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); BaseType = BaseType->getAs<PointerType>()->getPointeeType(); } + R.setBaseObjectType(BaseType); NestedNameSpecifier *Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); @@ -2713,6 +2718,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if ((SS.isSet() || !BaseExpr || (isa<CXXThisExpr>(BaseExpr) && cast<CXXThisExpr>(BaseExpr)->isImplicit())) && + !SuppressQualifierCheck && CheckQualifiedMemberReference(BaseExpr, BaseType, SS, R)) return ExprError(); @@ -2742,7 +2748,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } assert(R.isSingleResult()); - NamedDecl *FoundDecl = *R.begin(); + DeclAccessPair FoundDecl = R.begin().getPair(); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2756,7 +2762,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, // Handle the implicit-member-access case. if (!BaseExpr) { // If this is not an instance member, convert to a non-member access. - if (!IsInstanceMember(MemberDecl)) + if (!MemberDecl->isCXXInstanceMember()) return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); SourceLocation Loc = R.getNameLoc(); @@ -2833,16 +2839,18 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Owned(BaseExpr); + // We found something that we didn't expect. Complain. if (isa<TypeDecl>(MemberDecl)) - return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) - << MemberName << int(IsArrow)); + Diag(MemberLoc,diag::err_typecheck_member_reference_type) + << MemberName << BaseType << int(IsArrow); + else + Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) + << MemberName << BaseType << int(IsArrow); - // We found a declaration kind that we didn't expect. This is a - // generic error message that tells the user that she can't refer - // to this member with '.' or '->'. - return ExprError(Diag(MemberLoc, - diag::err_typecheck_member_reference_unknown) - << MemberName << int(IsArrow)); + Diag(MemberDecl->getLocation(), diag::note_member_declared_here) + << MemberName; + R.suppressDiagnostics(); + return ExprError(); } /// Look up the given member of the given non-type-dependent @@ -2858,7 +2866,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, Sema::OwningExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool &IsArrow, SourceLocation OpLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, DeclPtrTy ObjCImpDecl) { assert(BaseExpr && "no base expression"); @@ -3060,7 +3068,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // Attempt to correct for typos in ivar names. LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), LookupMemberName); - if (CorrectTypo(Res, 0, 0, IDecl) && + if (CorrectTypo(Res, 0, 0, IDecl, false, CTC_MemberLookup) && (IV = Res.getAsSingle<ObjCIvarDecl>())) { Diag(R.getNameLoc(), diag::err_typecheck_member_reference_ivar_suggest) @@ -3145,117 +3153,23 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (DiagnoseUseOfDecl(OMD, MemberLoc)) return ExprError(); - return Owned(new (Context) ObjCMessageExpr(Context, BaseExpr, Sel, - OMD->getResultType(), - OMD, OpLoc, MemberLoc, - NULL, 0)); + return Owned(ObjCMessageExpr::Create(Context, + OMD->getResultType().getNonReferenceType(), + OpLoc, BaseExpr, Sel, + OMD, NULL, 0, MemberLoc)); } } return ExprError(Diag(MemberLoc, diag::err_property_not_found) << MemberName << BaseType); } + // Handle Objective-C property access, which is "Obj.property" where Obj is a // pointer to a (potentially qualified) interface type. - const ObjCObjectPointerType *OPT; - if (!IsArrow && (OPT = BaseType->getAsObjCInterfacePointerType())) { - const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); - ObjCInterfaceDecl *IFace = IFaceT->getDecl(); - IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - - // Search for a declared property first. - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - QualType ResTy = PD->getType(); - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) - ResTy = Getter->getResultType(); - return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, - MemberLoc, BaseExpr)); - } - // Check protocols on qualified interfaces. - for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), - E = OPT->qual_end(); I != E; ++I) - if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { - // Check whether we can reference this property. - if (DiagnoseUseOfDecl(PD, MemberLoc)) - return ExprError(); - - return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), - MemberLoc, BaseExpr)); - } - // If that failed, look for an "implicit" property by seeing if the nullary - // selector is implemented. - - // FIXME: The logic for looking up nullary and unary selectors should be - // shared with the code in ActOnInstanceMessage. - - Selector Sel = PP.getSelectorTable().getNullarySelector(Member); - ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - - // If this reference is in an @implementation, check for 'private' methods. - if (!Getter) - Getter = IFace->lookupPrivateInstanceMethod(Sel); - - // Look through local category implementations associated with the class. - if (!Getter) - Getter = IFace->getCategoryInstanceMethod(Sel); - if (Getter) { - // Check if we can reference this property. - if (DiagnoseUseOfDecl(Getter, MemberLoc)) - return ExprError(); - } - // If we found a getter then this may be a valid dot-reference, we - // will look for the matching setter, in case it is needed. - Selector SetterSel = - SelectorTable::constructSetterName(PP.getIdentifierTable(), - PP.getSelectorTable(), Member); - ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - if (!Setter) { - // If this reference is in an @implementation, also check for 'private' - // methods. - Setter = IFace->lookupPrivateInstanceMethod(SetterSel); - } - // Look through local category implementations associated with the class. - if (!Setter) - Setter = IFace->getCategoryInstanceMethod(SetterSel); - - if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) - return ExprError(); - - if (Getter) { - QualType PType; - PType = Getter->getResultType(); - return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, - Setter, MemberLoc, BaseExpr)); - } - - // Attempt to correct for typos in property names. - LookupResult Res(*this, R.getLookupName(), R.getNameLoc(), - LookupOrdinaryName); - if (CorrectTypo(Res, 0, 0, IFace, false, OPT) && - Res.getAsSingle<ObjCPropertyDecl>()) { - Diag(R.getNameLoc(), diag::err_property_not_found_suggest) - << MemberName << BaseType << Res.getLookupName() - << FixItHint::CreateReplacement(R.getNameLoc(), - Res.getLookupName().getAsString()); - ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); - Diag(Property->getLocation(), diag::note_previous_decl) - << Property->getDeclName(); - - return LookupMemberExpr(Res, BaseExpr, IsArrow, OpLoc, SS, - ObjCImpDecl); - } - Diag(MemberLoc, diag::err_property_not_found) - << MemberName << BaseType; - if (Setter && !Getter) - Diag(Setter->getLocation(), diag::note_getter_unavailable) - << MemberName << BaseExpr->getSourceRange(); - return ExprError(); - } + if (!IsArrow) + if (const ObjCObjectPointerType *OPT = + BaseType->getAsObjCInterfacePointerType()) + return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc); // Handle the following exceptional case (*Obj).isa. if (!IsArrow && @@ -3296,7 +3210,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Id, DeclPtrTy ObjCImpDecl, bool HasTrailingLParen) { @@ -3323,7 +3237,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, Expr *Base = BaseArg.takeAs<Expr>(); OwningExprResult Result(*this); - if (Base->getType()->isDependentType() || Name.isDependentName()) { + if (Base->getType()->isDependentType() || Name.isDependentName() || + isDependentScopeSpecifier(SS)) { Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, @@ -3334,6 +3249,21 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, if (TemplateArgs) { // Re-use the lookup done for the template name. DecomposeTemplateName(R, Id); + + // Re-derive the naming class. + if (SS.isSet()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (const Type *Ty = Qualifier->getAsType()) + if (CXXRecordDecl *NamingClass = Ty->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } else { + QualType BaseType = Base->getType(); + if (const PointerType *Ptr = BaseType->getAs<PointerType>()) + BaseType = Ptr->getPointeeType(); + if (CXXRecordDecl *NamingClass = BaseType->getAsCXXRecordDecl()) + R.setNamingClass(NamingClass); + } } else { Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, SS, ObjCImpDecl); @@ -3443,7 +3373,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (NumArgs < NumArgsInProto) { if (!FDecl || NumArgs < FDecl->getMinRequiredArguments()) return Diag(RParenLoc, diag::err_typecheck_call_too_few_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange(); + << Fn->getType()->isBlockPointerType() + << NumArgsInProto << NumArgs << Fn->getSourceRange(); Call->setNumArgs(Context, NumArgsInProto); } @@ -3453,7 +3384,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, if (!Proto->isVariadic()) { Diag(Args[NumArgsInProto]->getLocStart(), diag::err_typecheck_call_too_many_args) - << Fn->getType()->isBlockPointerType() << Fn->getSourceRange() + << Fn->getType()->isBlockPointerType() + << NumArgsInProto << NumArgs << Fn->getSourceRange() << SourceRange(Args[NumArgsInProto]->getLocStart(), Args[NumArgs-1]->getLocEnd()); // This deletes the extra arguments. @@ -3613,7 +3545,8 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // declarations (all methods or method templates) or a single // method template. assert((MemE->getNumDecls() > 1) || - isa<FunctionTemplateDecl>(*MemE->decls_begin())); + isa<FunctionTemplateDecl>( + (*MemE->decls_begin())->getUnderlyingDecl())); (void)MemE; return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, @@ -3666,7 +3599,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, Expr *NakedFn = Fn->IgnoreParens(); if (isa<UnresolvedLookupExpr>(NakedFn)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn); - return BuildOverloadedCallExpr(Fn, ULE, LParenLoc, Args, NumArgs, + return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); } @@ -3851,8 +3784,8 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. - InitListExpr *E = new (Context) InitListExpr(LBraceLoc, InitList, NumInit, - RBraceLoc); + InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList, + NumInit, RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return Owned(E); } @@ -3895,11 +3828,11 @@ static CastExpr::CastKind getScalarCastKind(ASTContext &Context, /// CheckCastTypes - Check type constraints for casting between types. bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, CastExpr::CastKind& Kind, - CXXMethodDecl *& ConversionDecl, + CXXBaseSpecifierArray &BasePath, bool FunctionalStyle) { if (getLangOptions().CPlusPlus) - return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, FunctionalStyle, - ConversionDecl); + return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath, + FunctionalStyle); DefaultFunctionArrayLvalueConversion(castExpr); @@ -3962,9 +3895,6 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (castExpr->getType()->isVectorType()) return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); - if (getLangOptions().ObjC1 && isa<ObjCSuperExpr>(castExpr)) - return Diag(castExpr->getLocStart(), diag::err_illegal_super_cast) << TyR; - if (isa<ObjCSelectorExpr>(castExpr)) return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); @@ -4062,27 +3992,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, ExprArg Op) { Expr *castExpr = static_cast<Expr*>(Op.get()); - CXXMethodDecl *Method = 0; CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CXXBaseSpecifierArray BasePath; if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, Method)) + Kind, BasePath)) return ExprError(); - if (Method) { - // FIXME: preserve type source info here - OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(), - Kind, Method, move(Op)); - - if (CastArg.isInvalid()) - return ExprError(); - - castExpr = CastArg.takeAs<Expr>(); - } else { - Op.release(); - } - + Op.release(); return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(), - Kind, castExpr, Ty, + Kind, castExpr, BasePath, Ty, LParenLoc, RParenLoc)); } @@ -4126,7 +4044,8 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. Op.release(); - InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], + InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc, + &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); @@ -4856,7 +4775,7 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, QualType UnionType, FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. - InitListExpr *Initializer = new (C) InitListExpr(SourceLocation(), + InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), &E, 1, SourceLocation()); Initializer->setType(UnionType); @@ -5419,11 +5338,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, DiagRuntimeBehavior(Loc, PDiag(diag::warn_stringcompare) << isa<ObjCEncodeExpr>(literalStringStripped) - << literalString->getSourceRange() - << FixItHint::CreateReplacement(SourceRange(Loc), ", ") - << FixItHint::CreateInsertion(lex->getLocStart(), "strcmp(") - << FixItHint::CreateInsertion(PP.getLocForEndOfToken(rex->getLocEnd()), - resultComparison)); + << literalString->getSourceRange()); } } @@ -5480,7 +5395,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(lex, rex, + QualType T = FindCompositePointerType(Loc, lex, rex, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) @@ -5553,7 +5468,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // that is the union of the cv-qualification signatures of the operand // types. bool NonStandardCompositeType = false; - QualType T = FindCompositePointerType(lex, rex, + QualType T = FindCompositePointerType(Loc, lex, rex, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) @@ -5944,7 +5859,7 @@ QualType Sema::CheckCommaOperands(Expr *LHS, Expr *&RHS, SourceLocation Loc) { /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine /// doesn't need to call UsualUnaryConversions or UsualArithmeticConversions. QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, - bool isInc) { + bool isInc, bool isPrefix) { if (Op->isTypeDependent()) return Context.DependentTy; @@ -6007,7 +5922,11 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc, // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, *this)) return QualType(); - return ResType; + // In C++, a prefix increment is the same type as the operand. Otherwise + // (in C or with postfix), the increment is the unqualified type of the + // operand. + return isPrefix && getLangOptions().CPlusPlus + ? ResType : ResType.getUnqualifiedType(); } /// getPrimaryDecl - Helper function for CheckAddressOfOperand(). @@ -6395,33 +6314,37 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, /// ParenRange in parentheses. static void SuggestParentheses(Sema &Self, SourceLocation Loc, const PartialDiagnostic &PD, - SourceRange ParenRange, - const PartialDiagnostic &SecondPD, + const PartialDiagnostic &FirstNote, + SourceRange FirstParenRange, + const PartialDiagnostic &SecondNote, SourceRange SecondParenRange) { - SourceLocation EndLoc = Self.PP.getLocForEndOfToken(ParenRange.getEnd()); - if (!ParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { - // We can't display the parentheses, so just dig the - // warning/error and return. - Self.Diag(Loc, PD); + Self.Diag(Loc, PD); + + if (!FirstNote.getDiagID()) + return; + + SourceLocation EndLoc = Self.PP.getLocForEndOfToken(FirstParenRange.getEnd()); + if (!FirstParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { + // We can't display the parentheses, so just return. return; } - Self.Diag(Loc, PD) - << FixItHint::CreateInsertion(ParenRange.getBegin(), "(") + Self.Diag(Loc, FirstNote) + << FixItHint::CreateInsertion(FirstParenRange.getBegin(), "(") << FixItHint::CreateInsertion(EndLoc, ")"); - if (!SecondPD.getDiagID()) + if (!SecondNote.getDiagID()) return; EndLoc = Self.PP.getLocForEndOfToken(SecondParenRange.getEnd()); if (!SecondParenRange.getEnd().isFileID() || EndLoc.isInvalid()) { // We can't display the parentheses, so just dig the // warning/error and return. - Self.Diag(Loc, SecondPD); + Self.Diag(Loc, SecondNote); return; } - Self.Diag(Loc, SecondPD) + Self.Diag(Loc, SecondNote) << FixItHint::CreateInsertion(SecondParenRange.getBegin(), "(") << FixItHint::CreateInsertion(EndLoc, ")"); } @@ -6455,19 +6378,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange(), Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); + SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()), + Self.PDiag(diag::note_precedence_bitwise_silence) + << BinOp::getOpcodeStr(lhsopc), + lhs->getSourceRange()); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange(), Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); + SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()), + Self.PDiag(diag::note_precedence_bitwise_silence) + << BinOp::getOpcodeStr(rhsopc), + rhs->getSourceRange()); } /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky @@ -6532,14 +6459,16 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UnaryOperator::OffsetOf: assert(false && "Invalid unary operator"); break; - + case UnaryOperator::PreInc: case UnaryOperator::PreDec: case UnaryOperator::PostInc: case UnaryOperator::PostDec: resultType = CheckIncrementDecrementOperand(Input, OpLoc, Opc == UnaryOperator::PreInc || - Opc == UnaryOperator::PostInc); + Opc == UnaryOperator::PostInc, + Opc == UnaryOperator::PreInc || + Opc == UnaryOperator::PreDec); break; case UnaryOperator::AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); @@ -6690,6 +6619,157 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt, return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc)); } +Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc) { + QualType ArgTy = TInfo->getType(); + bool Dependent = ArgTy->isDependentType(); + SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange(); + + // We must have at least one component that refers to the type, and the first + // one is known to be a field designator. Verify that the ArgTy represents + // a struct/union/class. + if (!Dependent && !ArgTy->isRecordType()) + return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type) + << ArgTy << TypeRange); + + // Type must be complete per C99 7.17p3 because a declaring a variable + // with an incomplete type would be ill-formed. + if (!Dependent + && RequireCompleteType(BuiltinLoc, ArgTy, + PDiag(diag::err_offsetof_incomplete_type) + << TypeRange)) + return ExprError(); + + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a + // GCC extension, diagnose them. + // FIXME: This diagnostic isn't actually visible because the location is in + // a system header! + if (NumComponents != 1) + Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) + << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); + + bool DidWarnAboutNonPOD = false; + QualType CurrentType = ArgTy; + typedef OffsetOfExpr::OffsetOfNode OffsetOfNode; + llvm::SmallVector<OffsetOfNode, 4> Comps; + llvm::SmallVector<Expr*, 4> Exprs; + for (unsigned i = 0; i != NumComponents; ++i) { + const OffsetOfComponent &OC = CompPtr[i]; + if (OC.isBrackets) { + // Offset of an array sub-field. TODO: Should we allow vector elements? + if (!CurrentType->isDependentType()) { + const ArrayType *AT = Context.getAsArrayType(CurrentType); + if(!AT) + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) + << CurrentType); + CurrentType = AT->getElementType(); + } else + CurrentType = Context.DependentTy; + + // The expression must be an integral expression. + // FIXME: An integral constant expression? + Expr *Idx = static_cast<Expr*>(OC.U.E); + if (!Idx->isTypeDependent() && !Idx->isValueDependent() && + !Idx->getType()->isIntegerType()) + return ExprError(Diag(Idx->getLocStart(), + diag::err_typecheck_subscript_not_integer) + << Idx->getSourceRange()); + + // Record this array index. + Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd)); + Exprs.push_back(Idx); + continue; + } + + // Offset of a field. + if (CurrentType->isDependentType()) { + // We have the offset of a field, but we can't look into the dependent + // type. Just record the identifier of the field. + Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd)); + CurrentType = Context.DependentTy; + continue; + } + + // We need to have a complete type to look into. + if (RequireCompleteType(OC.LocStart, CurrentType, + diag::err_offsetof_incomplete_type)) + return ExprError(); + + // Look for the designated field. + const RecordType *RC = CurrentType->getAs<RecordType>(); + if (!RC) + return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) + << CurrentType); + RecordDecl *RD = RC->getDecl(); + + // C++ [lib.support.types]p5: + // The macro offsetof accepts a restricted set of type arguments in this + // International Standard. type shall be a POD structure or a POD union + // (clause 9). + if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { + if (!CRD->isPOD() && !DidWarnAboutNonPOD && + DiagRuntimeBehavior(BuiltinLoc, + PDiag(diag::warn_offsetof_non_pod_type) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << CurrentType)) + DidWarnAboutNonPOD = true; + } + + // Look for the field. + LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); + LookupQualifiedName(R, RD); + FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); + if (!MemberDecl) + return ExprError(Diag(BuiltinLoc, diag::err_no_member) + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, + OC.LocEnd)); + + // C99 7.17p3: + // (If the specified member is a bit-field, the behavior is undefined.) + // + // We diagnose this as an error. + if (MemberDecl->getBitWidth()) { + Diag(OC.LocEnd, diag::err_offsetof_bitfield) + << MemberDecl->getDeclName() + << SourceRange(BuiltinLoc, RParenLoc); + Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); + return ExprError(); + } + + // If the member was found in a base class, introduce OffsetOfNodes for + // the base class indirections. + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (IsDerivedFrom(CurrentType, + Context.getTypeDeclType(MemberDecl->getParent()), + Paths)) { + CXXBasePath &Path = Paths.front(); + for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end(); + B != BEnd; ++B) + Comps.push_back(OffsetOfNode(B->Base)); + } + + if (cast<RecordDecl>(MemberDecl->getDeclContext())-> + isAnonymousStructOrUnion()) { + llvm::SmallVector<FieldDecl*, 4> Path; + BuildAnonymousStructUnionMemberPath(MemberDecl, Path); + unsigned n = Path.size(); + for (int j = n - 1; j > -1; --j) + Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd)); + } else { + Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd)); + } + CurrentType = MemberDecl->getType().getNonReferenceType(); + } + + return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, + TInfo, Comps.data(), Comps.size(), + Exprs.data(), Exprs.size(), RParenLoc)); +} + Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, @@ -6697,45 +6777,56 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, OffsetOfComponent *CompPtr, unsigned NumComponents, SourceLocation RPLoc) { - // FIXME: This function leaks all expressions in the offset components on - // error. - // FIXME: Preserve type source info. - QualType ArgTy = GetTypeFromParser(argty); - assert(!ArgTy.isNull() && "Missing type argument!"); - bool Dependent = ArgTy->isDependentType(); + TypeSourceInfo *ArgTInfo; + QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo); + if (ArgTy.isNull()) + return ExprError(); + if (getLangOptions().CPlusPlus) { + if (!ArgTInfo) + ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); + + return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, + RPLoc); + } + + // FIXME: The code below is marked for death, once we have proper CodeGen + // support for non-constant OffsetOf expressions. + + bool Dependent = ArgTy->isDependentType(); + // We must have at least one component that refers to the type, and the first // one is known to be a field designator. Verify that the ArgTy represents // a struct/union/class. if (!Dependent && !ArgTy->isRecordType()) return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy); - + // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable // with an incomplete type would be illegal. - + // Otherwise, create a null pointer as the base, and iteratively process // the offsetof designators. QualType ArgTyPtr = Context.getPointerType(ArgTy); Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr); Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref, ArgTy, SourceLocation()); - + // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a // GCC extension, diagnose them. // FIXME: This diagnostic isn't actually visible because the location is in // a system header! if (NumComponents != 1) Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) - << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); - + << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); + if (!Dependent) { bool DidWarnAboutNonPOD = false; - + if (RequireCompleteType(TypeLoc, Res->getType(), diag::err_offsetof_incomplete_type)) return ExprError(); - + // FIXME: Dependent case loses a lot of information here. And probably // leaks like a sieve. for (unsigned i = 0; i != NumComponents; ++i) { @@ -6746,71 +6837,83 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (!AT) { Res->Destroy(Context); return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) - << Res->getType()); + << Res->getType()); } - + // FIXME: C++: Verify that operator[] isn't overloaded. - + // Promote the array so it looks more like a normal array subscript // expression. DefaultFunctionArrayLvalueConversion(Res); - + // C99 6.5.2.1p1 Expr *Idx = static_cast<Expr*>(OC.U.E); // FIXME: Leaks Res if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType()) return ExprError(Diag(Idx->getLocStart(), diag::err_typecheck_subscript_not_integer) - << Idx->getSourceRange()); - + << Idx->getSourceRange()); + Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd); continue; } - + const RecordType *RC = Res->getType()->getAs<RecordType>(); if (!RC) { Res->Destroy(Context); return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) - << Res->getType()); + << Res->getType()); } - + // Get the decl corresponding to this. RecordDecl *RD = RC->getDecl(); if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { if (!CRD->isPOD() && !DidWarnAboutNonPOD && DiagRuntimeBehavior(BuiltinLoc, PDiag(diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType())) + << SourceRange(CompPtr[0].LocStart, OC.LocEnd) + << Res->getType())) DidWarnAboutNonPOD = true; } - + LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); LookupQualifiedName(R, RD); - + FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>(); // FIXME: Leaks Res if (!MemberDecl) return ExprError(Diag(BuiltinLoc, diag::err_no_member) - << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); - + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); + + // C99 7.17p3: + // (If the specified member is a bit-field, the behavior is undefined.) + // + // We diagnose this as an error. + if (MemberDecl->getBitWidth()) { + Diag(OC.LocEnd, diag::err_offsetof_bitfield) + << MemberDecl->getDeclName() + << SourceRange(BuiltinLoc, RPLoc); + Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); + return ExprError(); + } + // FIXME: C++: Verify that MemberDecl isn't a static field. // FIXME: Verify that MemberDecl isn't a bitfield. if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) { Res = BuildAnonymousStructUnionMemberReference( - OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); + OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>(); } else { PerformObjectMemberConversion(Res, /*Qualifier=*/0, *R.begin(), MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, - MemberDecl->getType().getNonReferenceType()); + MemberDecl->getType().getNonReferenceType()); } } } - + return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(), BuiltinLoc)); } @@ -7127,7 +7230,7 @@ Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { return Owned(new (Context) GNUNullExpr(Ty, TokenLoc)); } -static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, +static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, Expr *SrcExpr, FixItHint &Hint) { if (!SemaRef.getLangOptions().ObjC1) return; @@ -7155,7 +7258,11 @@ static void MakeObjCStringLiteralFixItHint(Sema& SemaRef, QualType DstType, bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, - Expr *SrcExpr, AssignmentAction Action) { + Expr *SrcExpr, AssignmentAction Action, + bool *Complained) { + if (Complained) + *Complained = false; + // Decode the result (notice that AST's are still created for extensions). bool isInvalid = false; unsigned DiagKind; @@ -7218,8 +7325,30 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, break; } - Diag(Loc, DiagKind) << DstType << SrcType << Action + QualType FirstType, SecondType; + switch (Action) { + case AA_Assigning: + case AA_Initializing: + // The destination type comes first. + FirstType = DstType; + SecondType = SrcType; + break; + + case AA_Returning: + case AA_Passing: + case AA_Converting: + case AA_Sending: + case AA_Casting: + // The source type comes first. + FirstType = SrcType; + SecondType = DstType; + break; + } + + Diag(Loc, DiagKind) << FirstType << SecondType << Action << SrcExpr->getSourceRange() << Hint; + if (Complained) + *Complained = true; return isInvalid; } @@ -7328,8 +7457,13 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // (e.g. (void)sizeof()) constitute a use for warning purposes (-Wunused-variables and // -Wunused-parameters) if (isa<ParmVarDecl>(D) || - (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) + (isa<VarDecl>(D) && D->getDeclContext()->isFunctionOrMethod())) { D->setUsed(true); + return; + } + + if (!isa<VarDecl>(D) && !isa<FunctionDecl>(D)) + return; // Do not mark anything as "used" within a dependent context; wait for // an instantiation. @@ -7375,7 +7509,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (MethodDecl->isImplicit() && MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal) { if (!MethodDecl->isUsed()) - DefineImplicitOverloadedAssign(Loc, MethodDecl); + DefineImplicitCopyAssignment(Loc, MethodDecl); } } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -7536,12 +7670,12 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - Diag(Loc, diagnostic) - << E->getSourceRange() - << FixItHint::CreateInsertion(Open, "(") - << FixItHint::CreateInsertion(Close, ")"); + Diag(Loc, diagnostic) << E->getSourceRange(); Diag(Loc, diag::note_condition_assign_to_comparison) << FixItHint::CreateReplacement(Loc, "=="); + Diag(Loc, diag::note_condition_assign_silence) + << FixItHint::CreateInsertion(Open, "(") + << FixItHint::CreateInsertion(Close, ")"); } bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 501c877..425fc2d 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -29,7 +29,7 @@ using namespace clang; Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, TypeTy *ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. @@ -261,7 +261,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Range = SourceRange(NameLoc); } - return CheckTypenameType(NNS, II, Range).getAsOpaquePtr(); + return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr(); } if (ObjectTypePtr) @@ -273,89 +273,107 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, return 0; } -/// ActOnCXXTypeidOfType - Parse typeid( type-id ). +/// \brief Build a C++ typeid expression with a type operand. +Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + // C++ [expr.typeid]p4: + // The top-level cv-qualifiers of the lvalue expression or the type-id + // that is the operand of typeid are always ignored. + // If the type of the type-id is a class type or a reference to a class + // type, the class shall be completely-defined. + QualType T = Operand->getType().getNonReferenceType(); + if (T->getAs<RecordType>() && + RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), + Operand, + SourceRange(TypeidLoc, RParenLoc))); +} + +/// \brief Build a C++ typeid expression with an expression operand. +Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + ExprArg Operand, + SourceLocation RParenLoc) { + bool isUnevaluatedOperand = true; + Expr *E = static_cast<Expr *>(Operand.get()); + if (E && !E->isTypeDependent()) { + QualType T = E->getType(); + if (const RecordType *RecordT = T->getAs<RecordType>()) { + CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); + // C++ [expr.typeid]p3: + // [...] If the type of the expression is a class type, the class + // shall be completely-defined. + if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) + return ExprError(); + + // C++ [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] [the] expression is an unevaluated + // operand. [...] + if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) + isUnevaluatedOperand = false; + } + + // C++ [expr.typeid]p4: + // [...] If the type of the type-id is a reference to a possibly + // cv-qualified type, the result of the typeid expression refers to a + // std::type_info object representing the cv-unqualified referenced + // type. + if (T.hasQualifiers()) { + ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp, + E->isLvalue(Context)); + Operand.release(); + Operand = Owned(E); + } + } + + // If this is an unevaluated operand, clear out the set of + // declaration references we have been computing and eliminate any + // temporaries introduced in its computation. + if (isUnevaluatedOperand) + ExprEvalContexts.back().Context = Unevaluated; + + return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), + Operand.takeAs<Expr>(), + SourceRange(TypeidLoc, RParenLoc))); +} + +/// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { + // Find the std::type_info type. if (!StdNamespace) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - if (isType) { - // C++ [expr.typeid]p4: - // The top-level cv-qualifiers of the lvalue expression or the type-id - // that is the operand of typeid are always ignored. - // FIXME: Preserve type source info. - // FIXME: Preserve the type before we stripped the cv-qualifiers? - QualType T = GetTypeFromParser(TyOrExpr); - if (T.isNull()) - return ExprError(); - - // C++ [expr.typeid]p4: - // If the type of the type-id is a class type or a reference to a class - // type, the class shall be completely-defined. - QualType CheckT = T; - if (const ReferenceType *RefType = CheckT->getAs<ReferenceType>()) - CheckT = RefType->getPointeeType(); - - if (CheckT->getAs<RecordType>() && - RequireCompleteType(OpLoc, CheckT, diag::err_incomplete_typeid)) - return ExprError(); - - TyOrExpr = T.getUnqualifiedType().getAsOpaquePtr(); - } - IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, StdNamespace); RecordDecl *TypeInfoRecordDecl = R.getAsSingle<RecordDecl>(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); - + QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl); + + if (isType) { + // The operand is a type; handle it as such. + TypeSourceInfo *TInfo = 0; + QualType T = GetTypeFromParser(TyOrExpr, &TInfo); + if (T.isNull()) + return ExprError(); + + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); - if (!isType) { - bool isUnevaluatedOperand = true; - Expr *E = static_cast<Expr *>(TyOrExpr); - if (E && !E->isTypeDependent()) { - QualType T = E->getType(); - if (const RecordType *RecordT = T->getAs<RecordType>()) { - CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl()); - // C++ [expr.typeid]p3: - // [...] If the type of the expression is a class type, the class - // shall be completely-defined. - if (RequireCompleteType(OpLoc, T, diag::err_incomplete_typeid)) - return ExprError(); - - // C++ [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] [the] expression is an unevaluated - // operand. [...] - if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) - isUnevaluatedOperand = false; - } - - // C++ [expr.typeid]p4: - // [...] If the type of the type-id is a reference to a possibly - // cv-qualified type, the result of the typeid expression refers to a - // std::type_info object representing the cv-unqualified referenced - // type. - if (T.hasQualifiers()) { - ImpCastExprToType(E, T.getUnqualifiedType(), CastExpr::CK_NoOp, - E->isLvalue(Context)); - TyOrExpr = E; - } - } - - // If this is an unevaluated operand, clear out the set of - // declaration references we have been computing and eliminate any - // temporaries introduced in its computation. - if (isUnevaluatedOperand) - ExprEvalContexts.back().Context = Unevaluated; + return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } - return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, - TypeInfoType.withConst(), - SourceRange(OpLoc, RParenLoc))); + // The operand is an expression. + return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. @@ -399,10 +417,10 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = E->getType(); - int isPointer = 0; + bool isPointer = false; if (const PointerType* Ptr = Ty->getAs<PointerType>()) { Ty = Ptr->getPointeeType(); - isPointer = 1; + isPointer = true; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, @@ -411,20 +429,22 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { << E->getSourceRange())) return true; - // FIXME: This is just a hack to mark the copy constructor referenced. - // This should go away when the next FIXME is fixed. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) - return false; - - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->hasTrivialCopyConstructor()) - return false; - CXXConstructorDecl *CopyCtor = RD->getCopyConstructor(Context, 0); - MarkDeclarationReferenced(ThrowLoc, CopyCtor); + if (RequireNonAbstractType(ThrowLoc, E->getType(), + PDiag(diag::err_throw_abstract_type) + << E->getSourceRange())) + return true; } - // FIXME: Construct a temporary here. + // Initialize the exception result. This implicitly weeds out + // abstract types or types with inaccessible copy constructors. + InitializedEntity Entity = + InitializedEntity::InitializeException(ThrowLoc, E->getType()); + OwningExprResult Res = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(E)); + if (Res.isInvalid()) + return true; + E = Res.takeAs<Expr>(); return false; } @@ -499,25 +519,17 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // if (NumExprs == 1) { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXMethodDecl *Method = 0; - if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, Method, + CXXBaseSpecifierArray BasePath; + if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath, /*FunctionalStyle=*/true)) return ExprError(); exprs.release(); - if (Method) { - OwningExprResult CastArg - = BuildCXXCastArgument(TypeRange.getBegin(), Ty.getNonReferenceType(), - Kind, Method, Owned(Exprs[0])); - if (CastArg.isInvalid()) - return ExprError(); - - Exprs[0] = CastArg.takeAs<Expr>(); - } return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), TInfo, TyBeginLoc, Kind, - Exprs[0], RParenLoc)); + Exprs[0], BasePath, + RParenLoc)); } if (const RecordType *RT = Ty->getAs<RecordType>()) { @@ -708,10 +720,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, OperatorNew->getType()->getAs<FunctionProtoType>(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; - bool Invalid = GatherArgumentsForCall(PlacementLParen, OperatorNew, - Proto, 1, PlaceArgs, NumPlaceArgs, - AllPlaceArgs, CallType); - if (Invalid) + + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, + Proto, 1, PlaceArgs, NumPlaceArgs, + AllPlaceArgs, CallType)) return ExprError(); NumPlaceArgs = AllPlaceArgs.size(); @@ -726,6 +738,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, unsigned NumConsArgs = ConstructorArgs.size(); ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + // Array 'new' can't have any initializers. + if (NumConsArgs && ArraySize) { + SourceRange InitRange(ConsArgs[0]->getLocStart(), + ConsArgs[NumConsArgs - 1]->getLocEnd()); + + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; + return ExprError(); + } + if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) { // C++0x [expr.new]p15: @@ -892,6 +913,13 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, return true; } + // We don't need an operator delete if we're running under + // -fno-exceptions. + if (!getLangOptions().Exceptions) { + OperatorDelete = 0; + return false; + } + // FindAllocationOverload can change the passed in arguments, so we need to // copy them back. if (NumPlaceArgs > 0) @@ -1214,7 +1242,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FunctionType::ExtInfo()); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, /*TInfo=*/0, FunctionDecl::None, false, true); + FnType, /*TInfo=*/0, FunctionDecl::None, + FunctionDecl::None, false, true); Alloc->setImplicit(); if (AddMallocAttr) @@ -1222,6 +1251,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, + VarDecl::None, VarDecl::None, 0); Alloc->setParams(&Param, 1); @@ -1258,8 +1288,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { - Diag((*F)->getLocation(), - diag::note_delete_member_function_declared_here) + Diag((*F)->getLocation(), diag::note_member_declared_here) << Name; } @@ -1396,6 +1425,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); } + MarkDeclarationReferenced(StartLoc, OperatorDelete); + // FIXME: Check access and ambiguity of operator delete and destructor. } @@ -1469,45 +1500,43 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return false; } -/// PerformImplicitConversion - Perform an implicit conversion of the -/// expression From to the type ToType. Returns true if there was an -/// error, false otherwise. The expression From is replaced with the -/// converted expression. Flavor is the kind of conversion we're -/// performing, used in the error message. If @p AllowExplicit, -/// explicit user-defined conversions are permitted. @p Elidable should be true -/// when called for copies which may be elided (C++ 12.8p15). C++0x overload -/// resolution works differently in that case. -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, bool AllowExplicit, - bool Elidable) { - ImplicitConversionSequence ICS; - return PerformImplicitConversion(From, ToType, Action, AllowExplicit, - Elidable, ICS); -} - -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, bool AllowExplicit, - bool Elidable, - ImplicitConversionSequence& ICS) { - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - if (Elidable && getLangOptions().CPlusPlus0x) { - ICS = TryImplicitConversion(From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*ForceRValue=*/true, - /*InOverloadResolution=*/false); - } - if (ICS.isBad()) { - ICS = TryImplicitConversion(From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - } - return PerformImplicitConversion(From, ToType, ICS, Action); -} +static Sema::OwningExprResult BuildCXXCastArgument(Sema &S, + SourceLocation CastLoc, + QualType Ty, + CastExpr::CastKind Kind, + CXXMethodDecl *Method, + Sema::ExprArg Arg) { + Expr *From = Arg.takeAs<Expr>(); + + switch (Kind) { + default: assert(0 && "Unhandled cast kind!"); + case CastExpr::CK_ConstructorConversion: { + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + + if (S.CompleteConstructorCall(cast<CXXConstructorDecl>(Method), + Sema::MultiExprArg(S, (void **)&From, 1), + CastLoc, ConstructorArgs)) + return S.ExprError(); + + Sema::OwningExprResult Result = + S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), + move_arg(ConstructorArgs)); + if (Result.isInvalid()) + return S.ExprError(); + + return S.MaybeBindToTemporary(Result.takeAs<Expr>()); + } + + case CastExpr::CK_UserDefinedConversion: { + assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); + + // Create an implicit call expr that calls it. + // FIXME: pass the FoundDecl for the user-defined conversion here + CXXMemberCallExpr *CE = S.BuildCXXMemberCallExpr(From, Method, Method); + return S.MaybeBindToTemporary(CE); + } + } +} /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit @@ -1560,7 +1589,8 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } OwningExprResult CastArg - = BuildCXXCastArgument(From->getLocStart(), + = BuildCXXCastArgument(*this, + From->getLocStart(), ToType.getNonReferenceType(), CastKind, cast<CXXMethodDecl>(FD), Owned(From)); @@ -1639,6 +1669,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } + // Resolve overloaded function references. + if (Context.hasSameType(FromType, Context.OverloadTy)) { + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, + true, Found); + if (!Fn) + return true; + + if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) + return true; + + From = FixOverloadedFunctionReference(From, Found, Fn); + FromType = From->getType(); + } + // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: @@ -1652,25 +1697,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; case ICK_Function_To_Pointer: - if (Context.getCanonicalType(FromType) == Context.OverloadTy) { - DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, - true, Found); - if (!Fn) - return true; - - if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) - return true; - - From = FixOverloadedFunctionReference(From, Found, Fn); - FromType = From->getType(); - - // If there's already an address-of operator in the expression, we have - // the right type already, and the code below would just introduce an - // invalid additional pointer level. - if (FromType->isPointerType() || FromType->isMemberFunctionPointerType()) - break; - } FromType = Context.getPointerType(FromType); ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); break; @@ -1741,19 +1767,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) + CXXBaseSpecifierArray BasePath; + if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) return true; - ImpCastExprToType(From, ToType, Kind); + ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); break; } case ICK_Pointer_Member: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; - if (CheckMemberPointerConversion(From, ToType, Kind, IgnoreBaseAccess)) + CXXBaseSpecifierArray BasePath; + if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, + IgnoreBaseAccess)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; - ImpCastExprToType(From, ToType, Kind); + ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); break; } case ICK_Boolean_Conversion: { @@ -1769,7 +1798,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), - From->getSourceRange(), + From->getSourceRange(), 0, IgnoreBaseAccess)) return true; ImpCastExprToType(From, ToType.getNonReferenceType(), @@ -1790,8 +1819,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue // references. ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_NoOp, - ToType->isLValueReferenceType()); + CastExpr::CK_NoOp, ToType->isLValueReferenceType()); if (SCS.DeprecatedStringLiteralToCharPtr) Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion) @@ -1847,6 +1875,9 @@ QualType Sema::CheckPointerToMemberOperands( QualType Class(MemPtr->getClass(), 0); + if (RequireCompleteType(Loc, Class, diag::err_memptr_rhs_to_incomplete)) + return QualType(); + // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to @@ -1864,7 +1895,12 @@ QualType Sema::CheckPointerToMemberOperands( } if (!Context.hasSameUnqualifiedType(Class, LType)) { - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + // If we want to check the hierarchy, we need a complete type. + if (RequireCompleteType(Loc, LType, PDiag(diag::err_bad_memptr_lhs) + << OpSpelling << (int)isIndirect)) { + return QualType(); + } + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); // FIXME: Would it be useful to print full ambiguity paths, or is that // overkill? @@ -1877,7 +1913,11 @@ QualType Sema::CheckPointerToMemberOperands( // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid; - ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue); + + CXXBaseSpecifierArray BasePath; + BuildBasePathArray(Paths, BasePath); + ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue, + BasePath); } if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) { @@ -2201,7 +2241,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. bool NonStandardCompositeType = false; - QualType Composite = FindCompositePointerType(LHS, RHS, + QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS, isSFINAEContext()? 0 : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) @@ -2231,11 +2271,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// type and returns it. /// It does not emit diagnostics. /// +/// \param Loc The location of the operator requiring these two expressions to +/// be converted to the composite pointer type. +/// /// If \p NonStandardCompositeType is non-NULL, then we are permitted to find /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. -QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, +QualType Sema::FindCompositePointerType(SourceLocation Loc, + Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; @@ -2372,48 +2416,70 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2, } } - ImplicitConversionSequence E1ToC1 = - TryImplicitConversion(E1, Composite1, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - ImplicitConversionSequence E2ToC1 = - TryImplicitConversion(E2, Composite1, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - - bool ToC2Viable = false; - ImplicitConversionSequence E1ToC2, E2ToC2; - if (Context.getCanonicalType(Composite1) != - Context.getCanonicalType(Composite2)) { - E1ToC2 = TryImplicitConversion(E1, Composite2, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - E2ToC2 = TryImplicitConversion(E2, Composite2, - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*InOverloadResolution=*/false); - ToC2Viable = !E1ToC2.isBad() && !E2ToC2.isBad(); - } - - bool ToC1Viable = !E1ToC1.isBad() && !E2ToC1.isBad(); - if (ToC1Viable && !ToC2Viable) { - if (!PerformImplicitConversion(E1, Composite1, E1ToC1, Sema::AA_Converting) && - !PerformImplicitConversion(E2, Composite1, E2ToC1, Sema::AA_Converting)) - return Composite1; - } - if (ToC2Viable && !ToC1Viable) { - if (!PerformImplicitConversion(E1, Composite2, E1ToC2, Sema::AA_Converting) && - !PerformImplicitConversion(E2, Composite2, E2ToC2, Sema::AA_Converting)) - return Composite2; + // Try to convert to the first composite pointer type. + InitializedEntity Entity1 + = InitializedEntity::InitializeTemporary(Composite1); + InitializationKind Kind + = InitializationKind::CreateCopy(Loc, SourceLocation()); + InitializationSequence E1ToC1(*this, Entity1, Kind, &E1, 1); + InitializationSequence E2ToC1(*this, Entity1, Kind, &E2, 1); + + if (E1ToC1 && E2ToC1) { + // Conversion to Composite1 is viable. + if (!Context.hasSameType(Composite1, Composite2)) { + // Composite2 is a different type from Composite1. Check whether + // Composite2 is also viable. + InitializedEntity Entity2 + = InitializedEntity::InitializeTemporary(Composite2); + InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); + InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + if (E1ToC2 && E2ToC2) { + // Both Composite1 and Composite2 are viable and are different; + // this is an ambiguity. + return QualType(); + } + } + + // Convert E1 to Composite1 + OwningExprResult E1Result + = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E1,1)); + if (E1Result.isInvalid()) + return QualType(); + E1 = E1Result.takeAs<Expr>(); + + // Convert E2 to Composite1 + OwningExprResult E2Result + = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E2,1)); + if (E2Result.isInvalid()) + return QualType(); + E2 = E2Result.takeAs<Expr>(); + + return Composite1; } - return QualType(); + + // Check whether Composite2 is viable. + InitializedEntity Entity2 + = InitializedEntity::InitializeTemporary(Composite2); + InitializationSequence E1ToC2(*this, Entity2, Kind, &E1, 1); + InitializationSequence E2ToC2(*this, Entity2, Kind, &E2, 1); + if (!E1ToC2 || !E2ToC2) + return QualType(); + + // Convert E1 to Composite2 + OwningExprResult E1Result + = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E1, 1)); + if (E1Result.isInvalid()) + return QualType(); + E1 = E1Result.takeAs<Expr>(); + + // Convert E2 to Composite2 + OwningExprResult E2Result + = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E2, 1)); + if (E2Result.isInvalid()) + return QualType(); + E2 = E2Result.takeAs<Expr>(); + + return Composite2; } Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { @@ -2450,8 +2516,12 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { RD->getDestructor(Context)); ExprTemporaries.push_back(Temp); if (CXXDestructorDecl *Destructor = - const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) + const_cast<CXXDestructorDecl*>(RD->getDestructor(Context))) { MarkDeclarationReferenced(E->getExprLoc(), Destructor); + CheckDestructorAccess(E->getExprLoc(), Destructor, + PDiag(diag::err_access_dtor_temp) + << E->getType()); + } // FIXME: Add the temporary to the temporaries vector. return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); } @@ -2701,7 +2771,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, @@ -2869,43 +2939,6 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, return CE; } -Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, - QualType Ty, - CastExpr::CastKind Kind, - CXXMethodDecl *Method, - ExprArg Arg) { - Expr *From = Arg.takeAs<Expr>(); - - switch (Kind) { - default: assert(0 && "Unhandled cast kind!"); - case CastExpr::CK_ConstructorConversion: { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); - - if (CompleteConstructorCall(cast<CXXConstructorDecl>(Method), - MultiExprArg(*this, (void **)&From, 1), - CastLoc, ConstructorArgs)) - return ExprError(); - - OwningExprResult Result = - BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs)); - if (Result.isInvalid()) - return ExprError(); - - return MaybeBindToTemporary(Result.takeAs<Expr>()); - } - - case CastExpr::CK_UserDefinedConversion: { - assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); - - // Create an implicit call expr that calls it. - // FIXME: pass the FoundDecl for the user-defined conversion here - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method); - return MaybeBindToTemporary(CE); - } - } -} - Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { Expr *FullExpr = Arg.takeAs<Expr>(); if (FullExpr) diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index d5a22ca..db9a2e2 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -12,9 +12,12 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" +#include "SemaInit.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/TypeLoc.h" #include "llvm/ADT/SmallString.h" #include "clang/Lex/Preprocessor.h" @@ -75,9 +78,25 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, QualType Ty = Context.getObjCConstantStringInterface(); if (!Ty.isNull()) { Ty = Context.getObjCObjectPointerType(Ty); + } else if (getLangOptions().NoConstantCFStrings) { + IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0], + LookupOrdinaryName); + if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { + Context.setObjCConstantStringInterface(StrIF); + Ty = Context.getObjCConstantStringInterface(); + Ty = Context.getObjCObjectPointerType(Ty); + } else { + // If there is no NSConstantString interface defined then treat this + // as error and recover from it. + Diag(S->getLocStart(), diag::err_no_nsconstant_string_class) << NSIdent + << S->getSourceRange(); + Ty = Context.getObjCIdType(); + } } else { IdentifierInfo *NSIdent = &Context.Idents.get("NSString"); - NamedDecl *IF = LookupSingleName(TUScope, NSIdent, LookupOrdinaryName); + NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLocs[0], + LookupOrdinaryName); if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) { Context.setObjCConstantStringInterface(StrIF); Ty = Context.getObjCConstantStringInterface(); @@ -93,8 +112,9 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, } Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, - QualType EncodedType, + TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc) { + QualType EncodedType = EncodedTypeInfo->getType(); QualType StrTy; if (EncodedType->isDependentType()) StrTy = Context.DependentTy; @@ -112,7 +132,7 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, ArrayType::Normal, 0); } - return new (Context) ObjCEncodeExpr(StrTy, EncodedType, AtLoc, RParenLoc); + return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc); } Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, @@ -121,9 +141,13 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, TypeTy *ty, SourceLocation RParenLoc) { // FIXME: Preserve type source info ? - QualType EncodedType = GetTypeFromParser(ty); + TypeSourceInfo *TInfo; + QualType EncodedType = GetTypeFromParser(ty, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(EncodedType, + PP.getLocForEndOfToken(LParenLoc)); - return BuildObjCEncodeExpression(AtLoc, EncodedType, RParenLoc); + return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc); } Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, @@ -148,7 +172,7 @@ Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation RParenLoc) { - ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId); + ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc); if (!PDecl) { Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; return true; @@ -168,8 +192,12 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, QualType &ReturnType) { if (!Method) { // Apply default argument promotion as for (C99 6.5.2.2p6). - for (unsigned i = 0; i != NumArgs; i++) + for (unsigned i = 0; i != NumArgs; i++) { + if (Args[i]->isTypeDependent()) + continue; + DefaultArgumentPromotion(Args[i]); + } unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : diag::warn_inst_method_not_found; @@ -179,50 +207,68 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return false; } - ReturnType = Method->getResultType(); + ReturnType = Method->getResultType().getNonReferenceType(); unsigned NumNamedArgs = Sel.getNumArgs(); - assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); + // Method might have more arguments than selector indicates. This is due + // to addition of c-style arguments in method. + if (Method->param_size() > Sel.getNumArgs()) + NumNamedArgs = Method->param_size(); + // FIXME. This need be cleaned up. + if (NumArgs < NumNamedArgs) { + Diag(lbrac, diag::err_typecheck_call_too_few_args) << 2 + << NumNamedArgs << NumArgs; + return false; + } bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { - Expr *argExpr = Args[i]; - assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); + // We can't do any type-checking on a type-dependent argument. + if (Args[i]->isTypeDependent()) + continue; - QualType lhsType = Method->param_begin()[i]->getType(); - QualType rhsType = argExpr->getType(); + Expr *argExpr = Args[i]; - // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. - if (lhsType->isArrayType()) - lhsType = Context.getArrayDecayedType(lhsType); - else if (lhsType->isFunctionType()) - lhsType = Context.getPointerType(lhsType); + ParmVarDecl *Param = Method->param_begin()[i]; + assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); - AssignConvertType Result = - CheckSingleAssignmentConstraints(lhsType, argExpr); - if (Args[i] != argExpr) // The expression was converted. - Args[i] = argExpr; // Make sure we store the converted expression. + if (RequireCompleteType(argExpr->getSourceRange().getBegin(), + Param->getType(), + PDiag(diag::err_call_incomplete_argument) + << argExpr->getSourceRange())) + return true; - IsError |= - DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, - argExpr, AA_Sending); + InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); + OwningExprResult ArgE = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(argExpr->Retain())); + if (ArgE.isInvalid()) + IsError = true; + else + Args[i] = ArgE.takeAs<Expr>(); } // Promote additional arguments to variadic methods. if (Method->isVariadic()) { - for (unsigned i = NumNamedArgs; i < NumArgs; ++i) + for (unsigned i = NumNamedArgs; i < NumArgs; ++i) { + if (Args[i]->isTypeDependent()) + continue; + IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); + } } else { // Check for extra arguments to non-variadic methods. if (NumArgs != NumNamedArgs) { Diag(Args[NumNamedArgs]->getLocStart(), diag::err_typecheck_call_too_many_args) - << 2 /*method*/ << Method->getSourceRange() + << 2 /*method*/ << NumNamedArgs << NumArgs + << Method->getSourceRange() << SourceRange(Args[NumNamedArgs]->getLocStart(), Args[NumArgs-1]->getLocEnd()); } } + DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); return IsError; } @@ -281,20 +327,147 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, return Method; } -Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( - IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation &receiverNameLoc, - SourceLocation &propertyNameLoc) { +/// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an +/// objective C interface. This is a property reference expression. +Action::OwningExprResult Sema:: +HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, DeclarationName MemberName, + SourceLocation MemberLoc) { + const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); + ObjCInterfaceDecl *IFace = IFaceT->getDecl(); + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - IdentifierInfo *receiverNamePtr = &receiverName; - ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr); - if (!IFace) { - Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + // Search for a declared property first. + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + QualType ResTy = PD->getType(); + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); + if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) + ResTy = Getter->getResultType(); + return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy, + MemberLoc, BaseExpr)); + } + // Check protocols on qualified interfaces. + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) + if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(Member)) { + // Check whether we can reference this property. + if (DiagnoseUseOfDecl(PD, MemberLoc)) + return ExprError(); + + return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(), + MemberLoc, BaseExpr)); + } + // If that failed, look for an "implicit" property by seeing if the nullary + // selector is implemented. + + // FIXME: The logic for looking up nullary and unary selectors should be + // shared with the code in ActOnInstanceMessage. + + Selector Sel = PP.getSelectorTable().getNullarySelector(Member); + ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); + + // If this reference is in an @implementation, check for 'private' methods. + if (!Getter) + Getter = IFace->lookupPrivateInstanceMethod(Sel); + + // Look through local category implementations associated with the class. + if (!Getter) + Getter = IFace->getCategoryInstanceMethod(Sel); + if (Getter) { + // Check if we can reference this property. + if (DiagnoseUseOfDecl(Getter, MemberLoc)) + return ExprError(); + } + // If we found a getter then this may be a valid dot-reference, we + // will look for the matching setter, in case it is needed. + Selector SetterSel = + SelectorTable::constructSetterName(PP.getIdentifierTable(), + PP.getSelectorTable(), Member); + ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); + if (!Setter) { + // If this reference is in an @implementation, also check for 'private' + // methods. + Setter = IFace->lookupPrivateInstanceMethod(SetterSel); + } + // Look through local category implementations associated with the class. + if (!Setter) + Setter = IFace->getCategoryInstanceMethod(SetterSel); + + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); + + if (Getter) { + QualType PType; + PType = Getter->getResultType(); + return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, + Setter, MemberLoc, BaseExpr)); + } + + // Attempt to correct for typos in property names. + LookupResult Res(*this, MemberName, MemberLoc, LookupOrdinaryName); + if (CorrectTypo(Res, 0, 0, IFace, false, CTC_NoKeywords, OPT) && + Res.getAsSingle<ObjCPropertyDecl>()) { + DeclarationName TypoResult = Res.getLookupName(); + Diag(MemberLoc, diag::err_property_not_found_suggest) + << MemberName << QualType(OPT, 0) << TypoResult + << FixItHint::CreateReplacement(MemberLoc, TypoResult.getAsString()); + ObjCPropertyDecl *Property = Res.getAsSingle<ObjCPropertyDecl>(); + Diag(Property->getLocation(), diag::note_previous_decl) + << Property->getDeclName(); + return HandleExprPropertyRefExpr(OPT, BaseExpr, TypoResult, MemberLoc); + } + + Diag(MemberLoc, diag::err_property_not_found) + << MemberName << QualType(OPT, 0); + if (Setter && !Getter) + Diag(Setter->getLocation(), diag::note_getter_unavailable) + << MemberName << BaseExpr->getSourceRange(); + return ExprError(); +} + + + +Action::OwningExprResult Sema:: +ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc) { + + IdentifierInfo *receiverNamePtr = &receiverName; + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, + receiverNameLoc); + if (IFace == 0) { + // If the "receiver" is 'super' in a method, handle it as an expression-like + // property reference. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + if (receiverNamePtr->isStr("super")) { + if (CurMethod->isInstanceMethod()) { + QualType T = + Context.getObjCInterfaceType(CurMethod->getClassInterface()); + T = Context.getObjCObjectPointerType(T); + Expr *SuperExpr = new (Context) ObjCSuperExpr(receiverNameLoc, T); + + return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + SuperExpr, &propertyName, + propertyNameLoc); + } + + // Otherwise, if this is a class method, try dispatching to our + // superclass. + IFace = CurMethod->getClassInterface()->getSuperClass(); + } + + if (IFace == 0) { + Diag(receiverNameLoc, diag::err_expected_ident_or_lparen); + return ExprError(); + } } - // Search for a declared property first. + // Search for a declared property first. Selector Sel = PP.getSelectorTable().getNullarySelector(&propertyName); ObjCMethodDecl *Getter = IFace->lookupClassMethod(Sel); @@ -351,329 +524,502 @@ Action::OwningExprResult Sema::ActOnClassPropertyRefExpr( << &propertyName << Context.getObjCInterfaceType(IFace)); } +Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType) { + ReceiverType = 0; + + // If the identifier is "super" and there is no trailing dot, we're + // messaging super. + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); + LookupName(Result, S); + + switch (Result.getResultKind()) { + case LookupResult::NotFound: + // Normal name lookup didn't find anything. If we're in an + // Objective-C method, look for ivars. If we find one, we're done! + // FIXME: This is a hack. Ivar lookup should be part of normal lookup. + if (ObjCMethodDecl *Method = getCurMethodDecl()) { + ObjCInterfaceDecl *ClassDeclared; + if (Method->getClassInterface()->lookupInstanceVariable(Name, + ClassDeclared)) + return ObjCInstanceMessage; + } + + // Break out; we'll perform typo correction below. + break; + + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + case LookupResult::Ambiguous: + Result.suppressDiagnostics(); + return ObjCInstanceMessage; + + case LookupResult::Found: { + // We found something. If it's a type, then we have a class + // message. Otherwise, it's an instance message. + NamedDecl *ND = Result.getFoundDecl(); + QualType T; + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) + T = Context.getObjCInterfaceType(Class); + else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) + T = Context.getTypeDeclType(Type); + else + return ObjCInstanceMessage; + + // We have a class message, and T is the type we're + // messaging. Build source-location information for it. + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); + ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + return ObjCClassMessage; + } + } -// ActOnClassMessage - used for both unary and keyword messages. -// ArgExprs is optional - if it is present, the number of expressions -// is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnClassMessage( - Scope *S, - IdentifierInfo *receiverName, Selector Sel, - SourceLocation lbrac, SourceLocation receiverLoc, - SourceLocation selectorLoc, SourceLocation rbrac, - ExprTy **Args, unsigned NumArgs) { - assert(receiverName && "missing receiver class name"); - - Expr **ArgExprs = reinterpret_cast<Expr **>(Args); - ObjCInterfaceDecl* ClassDecl = 0; - bool isSuper = false; - - if (receiverName->isStr("super")) { - if (getCurMethodDecl()) { - isSuper = true; - ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface(); - if (!OID) - return Diag(lbrac, diag::error_no_super_class_message) - << getCurMethodDecl()->getDeclName(); - ClassDecl = OID->getSuperClass(); - if (!ClassDecl) - return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); - if (getCurMethodDecl()->isInstanceMethod()) { - QualType superTy = Context.getObjCInterfaceType(ClassDecl); - superTy = Context.getObjCObjectPointerType(superTy); - ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), - superTy); - // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, - selectorLoc, rbrac, Args, NumArgs); + // Determine our typo-correction context. + CorrectTypoContext CTC = CTC_Expression; + if (ObjCMethodDecl *Method = getCurMethodDecl()) + if (Method->getClassInterface() && + Method->getClassInterface()->getSuperClass()) + CTC = CTC_ObjCMessageReceiver; + + if (DeclarationName Corrected = CorrectTypo(Result, S, 0, 0, false, CTC)) { + if (Result.isSingleResult()) { + // If we found a declaration, correct when it refers to an Objective-C + // class. + NamedDecl *ND = Result.getFoundDecl(); + if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND)) { + Diag(NameLoc, diag::err_unknown_receiver_suggest) + << Name << Result.getLookupName() + << FixItHint::CreateReplacement(SourceRange(NameLoc), + ND->getNameAsString()); + Diag(ND->getLocation(), diag::note_previous_decl) + << Corrected; + + QualType T = Context.getObjCInterfaceType(Class); + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); + ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + return ObjCClassMessage; } - // We are sending a message to 'super' within a class method. Do nothing, - // the receiver will pass through as 'super' (how convenient:-). - } else { - // 'super' has been used outside a method context. If a variable named - // 'super' has been declared, redirect. If not, produce a diagnostic. - NamedDecl *SuperDecl - = LookupSingleName(S, receiverName, LookupOrdinaryName); - ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl); - if (VD) { - ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), - receiverLoc); - // We are really in an instance method, redirect. - return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, - selectorLoc, rbrac, Args, NumArgs); - } - else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) { - const ObjCInterfaceType *OCIT; - OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>(); - if (!OCIT) { - Diag(receiverLoc, diag::err_invalid_receiver_to_message); - return true; - } - ClassDecl = OCIT->getDecl(); - } - else - return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; - } - } else - ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc); - - // The following code allows for the following GCC-ism: - // - // typedef XCElementDisplayRect XCElementGraphicsRect; - // - // @implementation XCRASlice - // - whatever { // Note that XCElementGraphicsRect is a typedef name. - // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init]; - // } - // - // If necessary, the following lookup could move to getObjCInterfaceDecl(). - if (!ClassDecl) { - NamedDecl *IDecl - = LookupSingleName(TUScope, receiverName, LookupOrdinaryName); - if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) - if (const ObjCInterfaceType *OCIT - = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>()) - ClassDecl = OCIT->getDecl(); - - if (!ClassDecl) { - Diag(receiverLoc, diag::err_invalid_receiver_to_message); - return true; + } else if (Result.empty() && Corrected.getAsIdentifierInfo() && + Corrected.getAsIdentifierInfo()->isStr("super")) { + // If we've found the keyword "super", this is a send to super. + Diag(NameLoc, diag::err_unknown_receiver_suggest) + << Name << Corrected + << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); + Name = Corrected.getAsIdentifierInfo(); + return ObjCSuperMessage; } } - assert(ClassDecl && "missing interface declaration"); - ObjCMethodDecl *Method = 0; - QualType returnType; - if (ClassDecl->isForwardDecl()) { - // A forward class used in messaging is tread as a 'Class' - Diag(lbrac, diag::warn_receiver_forward_class) << ClassDecl->getDeclName(); - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); - if (Method) - Diag(Method->getLocation(), diag::note_method_sent_forward_class) - << Method->getDeclName(); + + // Fall back: let the parser try to parse it as an instance message. + return ObjCInstanceMessage; +} + +Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S, + SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + // Determine whether we are inside a method or not. + ObjCMethodDecl *Method = getCurMethodDecl(); + if (!Method) { + Diag(SuperLoc, diag::err_invalid_receiver_to_message_super); + return ExprError(); } - if (!Method) - Method = ClassDecl->lookupClassMethod(Sel); - // If we have an implementation in scope, check "private" methods. - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + ObjCInterfaceDecl *Class = Method->getClassInterface(); + if (!Class) { + Diag(SuperLoc, diag::error_no_super_class_message) + << Method->getDeclName(); + return ExprError(); + } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; + ObjCInterfaceDecl *Super = Class->getSuperClass(); + if (!Super) { + // The current class does not have a superclass. + Diag(SuperLoc, diag::error_no_super_class) << Class->getIdentifier(); + return ExprError(); + } - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, - lbrac, rbrac, returnType)) - return true; + // We are in a method whose class has a superclass, so 'super' + // is acting as a keyword. + if (Method->isInstanceMethod()) { + // Since we are in an instance method, this is an instance + // message to the superclass instance. + QualType SuperTy = Context.getObjCInterfaceType(Super); + SuperTy = Context.getObjCObjectPointerType(SuperTy); + return BuildInstanceMessage(ExprArg(*this), SuperTy, SuperLoc, + Sel, /*Method=*/0, LBracLoc, RBracLoc, + move(Args)); + } + + // Since we are in a class method, this is a class message to + // the superclass. + return BuildClassMessage(/*ReceiverTypeInfo=*/0, + Context.getObjCInterfaceType(Super), + SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc, + move(Args)); +} + +/// \brief Build an Objective-C class message expression. +/// +/// This routine takes care of both normal class messages and +/// class messages to the superclass. +/// +/// \param ReceiverTypeInfo Type source information that describes the +/// receiver of this message. This may be NULL, in which case we are +/// sending to the superclass and \p SuperLoc must be a valid source +/// location. + +/// \param ReceiverType The type of the object receiving the +/// message. When \p ReceiverTypeInfo is non-NULL, this is the same +/// type as that refers to. For a superclass send, this is the type of +/// the superclass. +/// +/// \param SuperLoc The location of the "super" keyword in a +/// superclass message. +/// +/// \param Sel The selector to which the message is being sent. +/// +/// \param Method The method that this class message is invoking, if +/// already known. +/// +/// \param LBracLoc The location of the opening square bracket ']'. +/// +/// \param RBrac The location of the closing square bracket ']'. +/// +/// \param Args The message arguments. +Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + if (ReceiverType->isDependentType()) { + // If the receiver type is dependent, we can't type-check anything + // at this point. Build a dependent expression. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + assert(SuperLoc.isInvalid() && "Message to super with dependent type"); + return Owned(ObjCMessageExpr::Create(Context, ReceiverType, LBracLoc, + ReceiverTypeInfo, Sel, /*Method=*/0, + Args, NumArgs, RBracLoc)); + } + + SourceLocation Loc = SuperLoc.isValid()? SuperLoc + : ReceiverTypeInfo->getTypeLoc().getSourceRange().getBegin(); + + // Find the class to which we are sending this message. + ObjCInterfaceDecl *Class = 0; + if (const ObjCInterfaceType *ClassType + = ReceiverType->getAs<ObjCInterfaceType>()) + Class = ClassType->getDecl(); + else { + Diag(Loc, diag::err_invalid_receiver_class_message) + << ReceiverType; + return ExprError(); + } + assert(Class && "We don't know which class we're messaging?"); + + // Find the method we are messaging. + if (!Method) { + if (Class->isForwardDecl()) { + // A forward class used in messaging is treated as a 'Class' + Diag(Loc, diag::warn_receiver_forward_class) << Class->getDeclName(); + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (Method) + Diag(Method->getLocation(), diag::note_method_sent_forward_class) + << Method->getDeclName(); + } + if (!Method) + Method = Class->lookupClassMethod(Sel); - returnType = returnType.getNonReferenceType(); - - // If we have the ObjCInterfaceDecl* for the class that is receiving the - // message, use that to construct the ObjCMessageExpr. Otherwise pass on the - // IdentifierInfo* for the class. - // FIXME: need to do a better job handling 'super' usage within a class. For - // now, we simply pass the "super" identifier through (which isn't consistent - // with instance methods. - if (isSuper) - return new (Context) ObjCMessageExpr(Context, receiverName, receiverLoc, - Sel, returnType, Method, lbrac, rbrac, - ArgExprs, NumArgs); - else - return new (Context) ObjCMessageExpr(Context, ClassDecl, receiverLoc, - Sel, returnType, Method, lbrac, rbrac, - ArgExprs, NumArgs); + // If we have an implementation in scope, check "private" methods. + if (!Method) + Method = LookupPrivateClassMethod(Sel, Class); + + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); + } + + // Check the argument types and determine the result type. + QualType ReturnType; + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, + LBracLoc, RBracLoc, ReturnType)) { + for (unsigned I = 0; I != NumArgs; ++I) + Args[I]->Destroy(Context); + return ExprError(); + } + + // Construct the appropriate ObjCMessageExpr. + if (SuperLoc.isValid()) + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, Method, Args, + NumArgs, RBracLoc)); + + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + ReceiverTypeInfo, Sel, Method, Args, + NumArgs, RBracLoc)); } -// ActOnInstanceMessage - used for both unary and keyword messages. +// ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). -Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, - SourceLocation lbrac, - SourceLocation receiverLoc, - SourceLocation rbrac, - ExprTy **Args, unsigned NumArgs) { - assert(receiver && "missing receiver expression"); - - Expr **ArgExprs = reinterpret_cast<Expr **>(Args); - Expr *RExpr = static_cast<Expr *>(receiver); - - // If necessary, apply function/array conversion to the receiver. - // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayLvalueConversion(RExpr); - - QualType returnType; - QualType ReceiverCType = - Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); - - // Handle messages to 'super'. - if (isa<ObjCSuperExpr>(RExpr)) { - ObjCMethodDecl *Method = 0; - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - // If we have an interface in scope, check 'super' methods. - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) - if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) { - Method = SuperDecl->lookupInstanceMethod(Sel); +Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S, + TypeTy *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + TypeSourceInfo *ReceiverTypeInfo; + QualType ReceiverType = GetTypeFromParser(Receiver, &ReceiverTypeInfo); + if (ReceiverType.isNull()) + return ExprError(); - if (!Method) - // If we have implementations in scope, check "private" methods. - Method = LookupPrivateInstanceMethod(Sel, SuperDecl); - } - } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; + if (!ReceiverTypeInfo) + ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; + return BuildClassMessage(ReceiverTypeInfo, ReceiverType, + /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, + LBracLoc, RBracLoc, move(Args)); +} - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); - } +/// \brief Build an Objective-C instance message expression. +/// +/// This routine takes care of both normal instance messages and +/// instance messages to the superclass instance. +/// +/// \param Receiver The expression that computes the object that will +/// receive this message. This may be empty, in which case we are +/// sending to the superclass instance and \p SuperLoc must be a valid +/// source location. +/// +/// \param ReceiverType The (static) type of the object receiving the +/// message. When a \p Receiver expression is provided, this is the +/// same type as that expression. For a superclass instance send, this +/// is a pointer to the type of the superclass. +/// +/// \param SuperLoc The location of the "super" keyword in a +/// superclass instance message. +/// +/// \param Sel The selector to which the message is being sent. +/// +/// \param Method The method that this instance message is invoking, if +/// already known. +/// +/// \param LBracLoc The location of the opening square bracket ']'. +/// +/// \param RBrac The location of the closing square bracket ']'. +/// +/// \param Args The message arguments. +Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + SourceLocation RBracLoc, + MultiExprArg ArgsIn) { + // If we have a receiver expression, perform appropriate promotions + // and determine receiver type. + Expr *Receiver = ReceiverE.takeAs<Expr>(); + if (Receiver) { + if (Receiver->isTypeDependent()) { + // If the receiver is type-dependent, we can't type-check anything + // at this point. Build a dependent expression. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + assert(SuperLoc.isInvalid() && "Message to super with dependent type"); + return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, + LBracLoc, Receiver, Sel, + /*Method=*/0, Args, NumArgs, + RBracLoc)); + } - // Handle messages to id. - if (ReceiverCType->isObjCIdType() || ReceiverCType->isBlockPointerType() || - Context.isObjCNSObjectType(RExpr->getType())) { - ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (!Method) - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac, rbrac)); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); + // If necessary, apply function/array conversion to the receiver. + // C99 6.7.5.3p[7,8]. + DefaultFunctionArrayLvalueConversion(Receiver); + ReceiverType = Receiver->getType(); } - // Handle messages to Class. - if (ReceiverCType->isObjCClassType() || - ReceiverCType->isObjCQualifiedClassType()) { - ObjCMethodDecl *Method = 0; + // The location of the receiver. + SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // First check the public methods in the class interface. - Method = ClassDecl->lookupClassMethod(Sel); + if (!Method) { + // Handle messages to id. + if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType() || + (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (!Method) + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + } else if (ReceiverType->isObjCClassType() || + ReceiverType->isObjCQualifiedClassType()) { + // Handle messages to Class. + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // First check the public methods in the class interface. + Method = ClassDecl->lookupClassMethod(Sel); - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); - // FIXME: if we still haven't found a method, we need to look in - // protocols (if we have qualifiers). + // FIXME: if we still haven't found a method, we need to look in + // protocols (if we have qualifiers). + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; - } - if (!Method) { - // If not messaging 'self', look for any factory method named 'Sel'. - if (!isSelfExpr(RExpr)) { - Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(lbrac,rbrac)); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(lbrac, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(lbrac, rbrac); - } + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!Receiver || !isSelfExpr(Receiver)) { + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (!Method) { + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (Method) + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(Loc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } } } - } - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, - Method, lbrac, rbrac, - ArgExprs, NumArgs); - } + } else { + ObjCInterfaceDecl* ClassDecl = 0; + + // We allow sending a message to a qualified ID ("id<foo>"), which is ok as + // long as one of the protocols implements the selector (if not, warn). + if (const ObjCObjectPointerType *QIdTy + = ReceiverType->getAsObjCQualifiedIdType()) { + // Search protocols for instance methods. + for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), + E = QIdTy->qual_end(); I != E; ++I) { + ObjCProtocolDecl *PDecl = *I; + if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) + break; + // Since we aren't supporting "Class<foo>", look for a class method. + if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) + break; + } + } else if (const ObjCObjectPointerType *OCIType + = ReceiverType->getAsObjCInterfacePointerType()) { + // We allow sending a message to a pointer to an interface (an object). + ClassDecl = OCIType->getInterfaceDecl(); + // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be + // faster than the following method (which can do *many* linear searches). + // The idea is to add class info to InstanceMethodPool. + Method = ClassDecl->lookupInstanceMethod(Sel); - ObjCMethodDecl *Method = 0; - ObjCInterfaceDecl* ClassDecl = 0; - - // We allow sending a message to a qualified ID ("id<foo>"), which is ok as - // long as one of the protocols implements the selector (if not, warn). - if (const ObjCObjectPointerType *QIdTy = - ReceiverCType->getAsObjCQualifiedIdType()) { - // Search protocols for instance methods. - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - ObjCProtocolDecl *PDecl = *I; - if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) - break; - // Since we aren't supporting "Class<foo>", look for a class method. - if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) - break; - } - } else if (const ObjCObjectPointerType *OCIType = - ReceiverCType->getAsObjCInterfacePointerType()) { - // We allow sending a message to a pointer to an interface (an object). - - ClassDecl = OCIType->getInterfaceDecl(); - // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be - // faster than the following method (which can do *many* linear searches). - // The idea is to add class info to InstanceMethodPool. - Method = ClassDecl->lookupInstanceMethod(Sel); - - if (!Method) { - // Search protocol qualifiers. - for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), - E = OCIType->qual_end(); QI != E; ++QI) { - if ((Method = (*QI)->lookupInstanceMethod(Sel))) - break; - } - } - if (!Method) { - // If we have implementations in scope, check "private" methods. - Method = LookupPrivateInstanceMethod(Sel, ClassDecl); - - if (!Method && !isSelfExpr(RExpr)) { - // If we still haven't found a method, look in the global pool. This - // behavior isn't very desirable, however we need it for GCC - // compatibility. FIXME: should we deviate?? - if (OCIType->qual_empty()) { - Method = LookupInstanceMethodInGlobalPool( - Sel, SourceRange(lbrac,rbrac)); - if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) - Diag(lbrac, diag::warn_maynot_respond) - << OCIType->getInterfaceDecl()->getIdentifier()->getName() << Sel; + if (!Method) { + // Search protocol qualifiers. + for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), + E = OCIType->qual_end(); QI != E; ++QI) { + if ((Method = (*QI)->lookupInstanceMethod(Sel))) + break; + } } + if (!Method) { + // If we have implementations in scope, check "private" methods. + Method = LookupPrivateInstanceMethod(Sel, ClassDecl); + + if (!Method && (!Receiver || !isSelfExpr(Receiver))) { + // If we still haven't found a method, look in the global pool. This + // behavior isn't very desirable, however we need it for GCC + // compatibility. FIXME: should we deviate?? + if (OCIType->qual_empty()) { + Method = LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc)); + if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) + Diag(Loc, diag::warn_maynot_respond) + << OCIType->getInterfaceDecl()->getIdentifier() << Sel; + } + } + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); + } else if (!Context.getObjCIdType().isNull() && + (ReceiverType->isPointerType() || + (ReceiverType->isIntegerType() && + ReceiverType->isScalarType()))) { + // Implicitly convert integers and pointers to 'id' but emit a warning. + Diag(Loc, diag::warn_bad_receiver_type) + << ReceiverType + << Receiver->getSourceRange(); + if (ReceiverType->isPointerType()) + ImpCastExprToType(Receiver, Context.getObjCIdType(), + CastExpr::CK_BitCast); + else + ImpCastExprToType(Receiver, Context.getObjCIdType(), + CastExpr::CK_IntegralToPointer); + ReceiverType = Receiver->getType(); + } else { + // Reject other random receiver types (e.g. structs). + Diag(Loc, diag::err_bad_receiver_type) + << ReceiverType << Receiver->getSourceRange(); + return ExprError(); } } - if (Method && DiagnoseUseOfDecl(Method, receiverLoc)) - return true; - } else if (!Context.getObjCIdType().isNull() && - (ReceiverCType->isPointerType() || - (ReceiverCType->isIntegerType() && - ReceiverCType->isScalarType()))) { - // Implicitly convert integers and pointers to 'id' but emit a warning. - Diag(lbrac, diag::warn_bad_receiver_type) - << RExpr->getType() << RExpr->getSourceRange(); - if (ReceiverCType->isPointerType()) - ImpCastExprToType(RExpr, Context.getObjCIdType(), CastExpr::CK_BitCast); - else - ImpCastExprToType(RExpr, Context.getObjCIdType(), - CastExpr::CK_IntegralToPointer); - } else { - // Reject other random receiver types (e.g. structs). - Diag(lbrac, diag::err_bad_receiver_type) - << RExpr->getType() << RExpr->getSourceRange(); - return true; } - if (Method) - DiagnoseSentinelCalls(Method, receiverLoc, ArgExprs, NumArgs); - if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, - lbrac, rbrac, returnType)) - return true; - returnType = returnType.getNonReferenceType(); - return new (Context) ObjCMessageExpr(Context, RExpr, Sel, returnType, Method, - lbrac, rbrac, ArgExprs, NumArgs); + // Check the message arguments. + unsigned NumArgs = ArgsIn.size(); + Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + QualType ReturnType; + if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, false, + LBracLoc, RBracLoc, ReturnType)) + return ExprError(); + + // Construct the appropriate ObjCMessageExpr instance. + if (SuperLoc.isValid()) + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, + SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, Method, + Args, NumArgs, RBracLoc)); + + return Owned(ObjCMessageExpr::Create(Context, ReturnType, LBracLoc, Receiver, + Sel, Method, Args, NumArgs, RBracLoc)); +} + +// ActOnInstanceMessage - used for both unary and keyword messages. +// ArgExprs is optional - if it is present, the number of expressions +// is obtained from Sel.getNumArgs(). +Sema::OwningExprResult Sema::ActOnInstanceMessage(Scope *S, + ExprArg ReceiverE, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { + Expr *Receiver = static_cast<Expr *>(ReceiverE.get()); + if (!Receiver) + return ExprError(); + + return BuildInstanceMessage(move(ReceiverE), Receiver->getType(), + /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, + LBracLoc, RBracLoc, move(Args)); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1d0575c..0aa3446 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -281,7 +281,7 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. - ILE->updateInit(Init, MemberInit.takeAs<Expr>()); + ILE->updateInit(SemaRef.Context, Init, MemberInit.takeAs<Expr>()); RequiresSecondPass = true; } } else if (InitListExpr *InnerILE @@ -391,7 +391,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, // extend the initializer list to include the constructor // call and make a note that we'll need to take another pass // through the initializer list. - ILE->updateInit(Init, ElementInit.takeAs<Expr>()); + ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>()); RequiresSecondPass = true; } } else if (InitListExpr *InnerILE @@ -458,7 +458,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, if (T->isArrayType()) maxElements = numArrayElements(T); - else if (T->isStructureType() || T->isUnionType()) + else if (T->isRecordType()) maxElements = numStructUnionElements(T); else if (T->isVectorType()) maxElements = T->getAs<VectorType>()->getNumElements(); @@ -624,10 +624,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, } else if (DeclType->isReferenceType()) { CheckReferenceType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); + } else if (DeclType->isObjCInterfaceType()) { + SemaRef.Diag(IList->getLocStart(), diag::err_init_objc_class) + << DeclType; + hadError = true; } else { - // In C, all types are either scalars or aggregates, but - // additional handling is needed here for C++ (and possibly others?). - assert(0 && "Unsupported initializer type"); + SemaRef.Diag(IList->getLocStart(), diag::err_illegal_initializer_type) + << DeclType; + hadError = true; } } @@ -884,9 +888,9 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity, } } - // OpenCL & AltiVec require all elements to be initialized. + // OpenCL requires all elements to be initialized. if (numEltsInit != maxElements) - if (SemaRef.getLangOptions().OpenCL || SemaRef.getLangOptions().AltiVec) + if (SemaRef.getLangOptions().OpenCL) SemaRef.Diag(IList->getSourceRange().getBegin(), diag::err_vector_incorrect_num_initializers) << (numEltsInit < maxElements) << maxElements << numEltsInit; @@ -1354,7 +1358,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // was a typo for another field name. LookupResult R(SemaRef, FieldName, D->getFieldLoc(), Sema::LookupMemberName); - if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl()) && + if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, + Sema::CTC_NoKeywords) && (ReplacementField = R.getAsSingle<FieldDecl>()) && ReplacementField->getDeclContext()->getLookupContext() ->Equals(RT->getDecl())) { @@ -1702,7 +1707,8 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, } InitListExpr *Result - = new (SemaRef.Context) InitListExpr(InitRange.getBegin(), 0, 0, + = new (SemaRef.Context) InitListExpr(SemaRef.Context, + InitRange.getBegin(), 0, 0, InitRange.getEnd()); Result->setType(CurrentObjectType.getNonReferenceType()); @@ -1740,12 +1746,12 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, if (NumElements < NumInits) NumElements = IList->getNumInits(); - Result->reserveInits(NumElements); + Result->reserveInits(SemaRef.Context, NumElements); // Link this new initializer list into the structured initializer // lists. if (StructuredList) - StructuredList->updateInit(StructuredIndex, Result); + StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result); else { Result->setSyntacticForm(IList); SyntacticToSemantic[IList] = Result; @@ -1763,7 +1769,8 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList, if (!StructuredList) return; - if (Expr *PrevInit = StructuredList->updateInit(StructuredIndex, expr)) { + if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context, + StructuredIndex, expr)) { // This initializer overwrites a previous initializer. Warn. SemaRef.Diag(expr->getSourceRange().getBegin(), diag::warn_initializer_overrides) @@ -1918,11 +1925,15 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base) + CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase) { InitializedEntity Result; Result.Kind = EK_Base; - Result.Base = Base; + Result.Base = reinterpret_cast<uintptr_t>(Base); + if (IsInheritedVirtualBase) + Result.Base |= 0x01; + Result.Type = Base->getType(); return Result; } @@ -1984,6 +1995,7 @@ void InitializationSequence::Step::Destroy() { case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionRValue: case SK_QualificationConversionLValue: @@ -2033,6 +2045,10 @@ bool InitializationSequence::isAmbiguous() const { return false; } +bool InitializationSequence::isConstructorInitialization() const { + return !Steps.empty() && Steps.back().Kind == SK_ConstructorInitialization; +} + void InitializationSequence::AddAddressOverloadResolutionStep( FunctionDecl *Function, DeclAccessPair Found) { @@ -2060,6 +2076,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, Steps.push_back(S); } +void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) { + Step S; + S.Kind = SK_ExtraneousCopyToTemporary; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, DeclAccessPair FoundDecl, QualType T) { @@ -2388,15 +2411,11 @@ static void TryReferenceInitialization(Sema &S, T2 = cv2T2.getUnqualifiedType(); } - // FIXME: Rvalue references - bool ForceRValue = false; - // Compute some basic properties of the types and the initializer. bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; bool DerivedToBase = false; - Expr::isLvalueResult InitLvalue = ForceRValue ? Expr::LV_InvalidExpression : - Initializer->isLvalue(S.Context); + Expr::isLvalueResult InitLvalue = Initializer->isLvalue(S.Context); Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); @@ -2480,6 +2499,18 @@ static void TryReferenceInitialization(Sema &S, // reference-compatible with "cv2 T2", or if (InitLvalue != Expr::LV_Valid && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the + // compiler the freedom to perform a copy here or bind to the + // object, while C++0x requires that we bind directly to the + // object. Hence, we always bind to the object without making an + // extra copy. However, in C++03 requires that we check for the + // presence of a suitable copy constructor: + // + // The constructor that would be used to make the copy shall + // be callable whether or not the copy is actually done. + if (!S.getLangOptions().CPlusPlus0x) + Sequence.AddExtraneousCopyToTemporary(cv2T2); + if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), @@ -2528,9 +2559,7 @@ static void TryReferenceInitialization(Sema &S, ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, cv1T1, /*SuppressUserConversions=*/false, AllowExplicit, - /*ForceRValue=*/false, - /*FIXME:InOverloadResolution=*/false, - /*UserCast=*/Kind.isExplicitCast()); + /*FIXME:InOverloadResolution=*/false); if (ICS.isBad()) { // FIXME: Use the conversion function set stored in ICS to turn @@ -2595,6 +2624,12 @@ static void TryConstructorInitialization(Sema &S, bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct || Kind.getKind() == InitializationKind::IK_Value || Kind.getKind() == InitializationKind::IK_Default); + + // The type we're constructing needs to be complete. + if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); + return; + } // The type we're converting to is a class type. Enumerate its constructors // to see if one is suitable. @@ -2611,25 +2646,36 @@ static void TryConstructorInitialization(Sema &S, Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - + bool SuppressUserConversions = false; + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); - else + else { Constructor = cast<CXXConstructorDecl>(D); + + // If we're performing copy initialization using a copy constructor, we + // suppress user-defined conversions on the arguments. + // FIXME: Move constructors? + if (Kind.getKind() == InitializationKind::IK_Copy && + Constructor->isCopyConstructor()) + SuppressUserConversions = true; + } if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, - Args, NumArgs, CandidateSet); + Args, NumArgs, CandidateSet, + SuppressUserConversions); else S.AddOverloadCandidate(Constructor, FoundDecl, - Args, NumArgs, CandidateSet); + Args, NumArgs, CandidateSet, + SuppressUserConversions); } } @@ -2770,36 +2816,51 @@ static void TryUserDefinedConversion(Sema &S, CXXRecordDecl *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getDecl()); - DeclarationName ConstructorName - = S.Context.DeclarationNames.getCXXConstructorName( + // Try to complete the type we're converting to. + if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { + DeclarationName ConstructorName + = S.Context.DeclarationNames.getCXXConstructorName( S.Context.getCanonicalType(DestType).getUnqualifiedType()); - DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); - Con != ConEnd; ++Con) { - NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); - - if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { + DeclContext::lookup_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); + Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + bool SuppressUserConversions = false; + + // Find the constructor (which may be a template). + CXXConstructorDecl *Constructor = 0; + FunctionTemplateDecl *ConstructorTmpl + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - &Initializer, 1, CandidateSet); - else - S.AddOverloadCandidate(Constructor, FoundDecl, - &Initializer, 1, CandidateSet); - } - } + Constructor = cast<CXXConstructorDecl>( + ConstructorTmpl->getTemplatedDecl()); + else { + Constructor = cast<CXXConstructorDecl>(D); + + // If we're performing copy initialization using a copy constructor, + // we suppress user-defined conversions on the arguments. + // FIXME: Move constructors? + if (Kind.getKind() == InitializationKind::IK_Copy && + Constructor->isCopyConstructor()) + SuppressUserConversions = true; + + } + + if (!Constructor->isInvalidDecl() && + Constructor->isConvertingConstructor(AllowExplicit)) { + if (ConstructorTmpl) + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + /*ExplicitArgs*/ 0, + &Initializer, 1, CandidateSet, + SuppressUserConversions); + else + S.AddOverloadCandidate(Constructor, FoundDecl, + &Initializer, 1, CandidateSet, + SuppressUserConversions); + } + } + } } SourceLocation DeclLoc = Initializer->getLocStart(); @@ -2865,10 +2926,21 @@ static void TryUserDefinedConversion(Sema &S, // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getResultType().getNonReferenceType(); - Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); + if (ConvType->getAs<RecordType>()) { + // If we're converting to a class type, there may be an copy if + // the resulting temporary object (possible to create an object of + // a base class type). That copy is not a separate conversion, so + // we just make a note of the actual destination type (possibly a + // base class of the type returned by the conversion function) and + // let the user-defined conversion step handle the conversion. + Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType); + return; + } - // If the conversion following the call to the conversion function is - // interesting, add it as a separate step. + Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); + + // If the conversion following the call to the conversion function + // is interesting, add it as a separate step. if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; @@ -2889,9 +2961,7 @@ static void TryImplicitConversion(Sema &S, = S.TryImplicitConversion(Initializer, Entity.getType(), /*SuppressUserConversions=*/true, /*AllowExplicit=*/false, - /*ForceRValue=*/false, - /*FIXME:InOverloadResolution=*/false, - /*UserCast=*/Kind.isExplicitCast()); + /*InOverloadResolution=*/false); if (ICS.isBad()) { Sequence.SetFailed(InitializationSequence::FK_ConversionFailed); @@ -3054,7 +3124,10 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: - // FIXME: Can we tell when we're sending vs. passing? + if (Entity.getDecl() && + isa<ObjCMethodDecl>(Entity.getDecl()->getDeclContext())) + return Sema::AA_Sending; + return Sema::AA_Passing; case InitializedEntity::EK_Result: @@ -3078,6 +3151,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Converting; } +/// \brief Whether we should binding a created object as a temporary when +/// initializing the given entity. static bool shouldBindAsTemporary(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_ArrayElement: @@ -3098,14 +3173,57 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } +/// \brief Whether the given entity, when initialized with an object +/// created for that initialization, requires destruction. +static bool shouldDestroyTemporary(const InitializedEntity &Entity) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Member: + case InitializedEntity::EK_Result: + case InitializedEntity::EK_New: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_VectorElement: + return false; + + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_Exception: + return true; + } + + llvm_unreachable("missed an InitializedEntity kind?"); +} + +/// \brief Make a (potentially elidable) temporary copy of the object +/// provided by the given initializer by calling the appropriate copy +/// constructor. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param T The type of the temporary object, which must either by +/// the type of the initializer expression or a superclass thereof. +/// +/// \param Enter The entity being initialized. +/// +/// \param CurInit The initializer expression. +/// +/// \param IsExtraneousCopy Whether this is an "extraneous" copy that +/// is permitted in C++03 (but not C++0x) when binding a reference to +/// an rvalue. +/// +/// \returns An expression that copies the initializer expression into +/// a temporary object, or an error expression if a copy could not be +/// created. static Sema::OwningExprResult CopyObject(Sema &S, + QualType T, const InitializedEntity &Entity, - const InitializationKind &Kind, - Sema::OwningExprResult CurInit) { - // Determine which class type we're copying. + Sema::OwningExprResult CurInit, + bool IsExtraneousCopy) { + // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); CXXRecordDecl *Class = 0; - if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>()) + if (const RecordType *Record = T->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); if (!Class) return move(CurInit); @@ -3126,7 +3244,7 @@ static Sema::OwningExprResult CopyObject(Sema &S, // not yet) handled as part of constructor initialization, while // copy elision for exception handlers is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject() && - S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType()); + S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); SourceLocation Loc; switch (Entity.getKind()) { case InitializedEntity::EK_Result: @@ -3151,7 +3269,11 @@ static Sema::OwningExprResult CopyObject(Sema &S, Loc = CurInitExpr->getLocStart(); break; } - + + // Make sure that the type we are copying is complete. + if (S.RequireCompleteType(Loc, T, S.PDiag(diag::err_temp_copy_incomplete))) + return move(CurInit); + // Perform overload resolution using the class's copy constructors. DeclarationName ConstructorName = S.Context.DeclarationNames.getCXXConstructorName( @@ -3163,7 +3285,8 @@ static Sema::OwningExprResult CopyObject(Sema &S, // Only consider copy constructors. CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con); if (!Constructor || Constructor->isInvalidDecl() || - !Constructor->isCopyConstructor()) + !Constructor->isCopyConstructor() || + !Constructor->isConvertingConstructor(/*AllowExplicit=*/false)) continue; DeclAccessPair FoundDecl @@ -3202,16 +3325,71 @@ static Sema::OwningExprResult CopyObject(Sema &S, return S.ExprError(); } - S.CheckConstructorAccess(Loc, - cast<CXXConstructorDecl>(Best->Function), + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); + ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + CurInit.release(); // Ownership transferred into MultiExprArg, below. + + S.CheckConstructorAccess(Loc, Constructor, Entity, Best->FoundDecl.getAccess()); - CurInit.release(); - return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(), - cast<CXXConstructorDecl>(Best->Function), - Elidable, - Sema::MultiExprArg(S, - (void**)&CurInitExpr, 1)); + if (IsExtraneousCopy) { + // If this is a totally extraneous copy for C++03 reference + // binding purposes, just return the original initialization + // expression. We don't generate an (elided) copy operation here + // because doing so would require us to pass down a flag to avoid + // infinite recursion, where each step adds another extraneous, + // elidable copy. + + // Instantiate the default arguments of any extra parameters in + // the selected copy constructor, as if we were going to create a + // proper call to the copy constructor. + for (unsigned I = 1, N = Constructor->getNumParams(); I != N; ++I) { + ParmVarDecl *Parm = Constructor->getParamDecl(I); + if (S.RequireCompleteType(Loc, Parm->getType(), + S.PDiag(diag::err_call_incomplete_argument))) + break; + + // Build the default argument expression; we don't actually care + // if this succeeds or not, because this routine will complain + // if there was a problem. + S.BuildCXXDefaultArgExpr(Loc, Constructor, Parm); + } + + return S.Owned(CurInitExpr); + } + + // Determine the arguments required to actually perform the + // constructor call (we might have derived-to-base conversions, or + // the copy constructor may have default arguments). + if (S.CompleteConstructorCall(Constructor, + Sema::MultiExprArg(S, + (void **)&CurInitExpr, + 1), + Loc, ConstructorArgs)) + return S.ExprError(); + + // Actually perform the constructor call. + CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, + move_arg(ConstructorArgs)); + + // If we're supposed to bind temporaries, do so. + if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); + return move(CurInit); +} + +void InitializationSequence::PrintInitLocationNote(Sema &S, + const InitializedEntity &Entity) { + if (Entity.getKind() == InitializedEntity::EK_Parameter && Entity.getDecl()) { + if (Entity.getDecl()->getLocation().isInvalid()) + return; + + if (Entity.getDecl()->getDeclName()) + S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_named_here) + << Entity.getDecl()->getDeclName(); + else + S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here); + } } Action::OwningExprResult @@ -3304,6 +3482,7 @@ InitializationSequence::Perform(Sema &S, case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionLValue: case SK_QualificationConversionRValue: @@ -3348,17 +3527,20 @@ InitializationSequence::Perform(Sema &S, // We have a derived-to-base cast that produces either an rvalue or an // lvalue. Perform that cast. + CXXBaseSpecifierArray BasePath; + // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, CurInitExpr->getLocStart(), - CurInitExpr->getSourceRange(), - IgnoreBaseAccess)) + CurInitExpr->getSourceRange(), + &BasePath, IgnoreBaseAccess)) return S.ExprError(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, CastExpr::CK_DerivedToBase, - (Expr*)CurInit.release(), + (Expr*)CurInit.release(), + BasePath, Step->Kind == SK_CastDerivedToBaseLValue)); break; } @@ -3379,6 +3561,7 @@ InitializationSequence::Perform(Sema &S, S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) << Entity.getType().isVolatileQualified() << CurInitExpr->getSourceRange(); + PrintInitLocationNote(S, Entity); return S.ExprError(); } @@ -3399,6 +3582,11 @@ InitializationSequence::Perform(Sema &S, break; + case SK_ExtraneousCopyToTemporary: + CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + /*IsExtraneousCopy=*/true); + break; + case SK_UserConversion: { // We have a user-defined conversion that invokes either a constructor // or a conversion function. @@ -3406,6 +3594,7 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool CreatedObject = false; bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. @@ -3428,7 +3617,7 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return S.ExprError(); - S.CheckConstructorAccess(Kind.getLocation(), Constructor, + S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); CastKind = CastExpr::CK_ConstructorConversion; @@ -3436,6 +3625,8 @@ InitializationSequence::Perform(Sema &S, if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) IsCopy = true; + + CreatedObject = true; } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); @@ -3461,21 +3652,37 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); CastKind = CastExpr::CK_UserDefinedConversion; + + CreatedObject = Conversion->getResultType()->isRecordType(); } bool RequiresCopy = !IsCopy && getKind() != InitializationSequence::ReferenceBinding; if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - + else if (CreatedObject && shouldDestroyTemporary(Entity)) { + CurInitExpr = static_cast<Expr *>(CurInit.get()); + QualType T = CurInitExpr->getType(); + if (const RecordType *Record = T->getAs<RecordType>()) { + CXXDestructorDecl *Destructor + = cast<CXXRecordDecl>(Record->getDecl())->getDestructor(S.Context); + S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.PDiag(diag::err_access_dtor_temp) << T); + S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); + } + } + CurInitExpr = CurInit.takeAs<Expr>(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CastKind, CurInitExpr, + CXXBaseSpecifierArray(), IsLvalue)); if (RequiresCopy) - CurInit = CopyObject(S, Entity, Kind, move(CurInit)); + CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, + move(CurInit), /*IsExtraneousCopy=*/false); + break; } @@ -3483,21 +3690,24 @@ InitializationSequence::Perform(Sema &S, case SK_QualificationConversionRValue: // Perform a qualification conversion; these can never go wrong. S.ImpCastExprToType(CurInitExpr, Step->Type, - CastExpr::CK_NoOp, + CastExpr::CK_NoOp, Step->Kind == SK_QualificationConversionLValue); CurInit.release(); CurInit = S.Owned(CurInitExpr); break; - case SK_ConversionSequence: - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, Sema::AA_Converting, - false, false, *Step->ICS)) + case SK_ConversionSequence: { + bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); + + if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, + Sema::AA_Converting, IgnoreBaseAccess)) return S.ExprError(); CurInit.release(); - CurInit = S.Owned(CurInitExpr); + CurInit = S.Owned(CurInitExpr); break; - + } + case SK_ListInitialization: { InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); QualType Ty = Step->Type; @@ -3510,6 +3720,7 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitialization: { + unsigned NumArgs = Args.size(); CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Step->Function.Function); @@ -3523,8 +3734,9 @@ InitializationSequence::Perform(Sema &S, Loc, ConstructorArgs)) return S.ExprError(); - // Build the an expression that constructs a temporary. + // Build the expression that constructs a temporary. if (Entity.getKind() == InitializedEntity::EK_Temporary && + NumArgs != 1 && // FIXME: Hack to work around cast weirdness (Kind.getKind() == InitializationKind::IK_Direct || Kind.getKind() == InitializationKind::IK_Value)) { // An explicitly-constructed temporary, e.g., X(1, 2). @@ -3537,23 +3749,33 @@ InitializationSequence::Perform(Sema &S, Kind.getLocation(), Exprs, NumExprs, - Kind.getParenRange().getEnd())); - } else + Kind.getParenRange().getEnd(), + ConstructorInitRequiresZeroInit)); + } else { + CXXConstructExpr::ConstructionKind ConstructKind = + CXXConstructExpr::CK_Complete; + + if (Entity.getKind() == InitializedEntity::EK_Base) { + ConstructKind = Entity.getBaseSpecifier()->isVirtual() ? + CXXConstructExpr::CK_VirtualBase : + CXXConstructExpr::CK_NonVirtualBase; + } CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, move_arg(ConstructorArgs), ConstructorInitRequiresZeroInit, - Entity.getKind() == InitializedEntity::EK_Base); + ConstructKind); + } if (CurInit.isInvalid()) return S.ExprError(); // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, + S.CheckConstructorAccess(Loc, Constructor, Entity, Step->Function.FoundDecl.getAccess()); if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - + break; } @@ -3589,10 +3811,16 @@ InitializationSequence::Perform(Sema &S, == Sema::Compatible) ConvTy = Sema::Compatible; + bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInitExpr, getAssignmentAction(Entity))) + CurInitExpr, + getAssignmentAction(Entity), + &Complained)) { + PrintInitLocationNote(S, Entity); return S.ExprError(); + } else if (Complained) + PrintInitLocationNote(S, Entity); CurInit.release(); CurInit = S.Owned(CurInitExpr); @@ -3866,6 +4094,7 @@ bool InitializationSequence::Diagnose(Sema &S, break; } + PrintInitLocationNote(S, Entity); return true; } @@ -4013,9 +4242,12 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { OS << "bind reference to a temporary"; break; + case SK_ExtraneousCopyToTemporary: + OS << "extraneous C++03 copy to temporary"; + break; + case SK_UserConversion: - OS << "user-defined conversion via " - << S->Function.Function->getNameAsString(); + OS << "user-defined conversion via " << S->Function.Function; break; case SK_QualificationConversionRValue: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 7c6327f..5f2592f 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -92,11 +92,12 @@ private: unsigned Location; /// \brief When Kind == EK_Base, the base specifier that provides the - /// base class. - CXXBaseSpecifier *Base; + /// base class. The lower bit specifies whether the base is an inherited + /// virtual base. + uintptr_t Base; - /// \brief When Kind = EK_ArrayElement or EK_VectorElement, the - /// index of the array or vector element being initialized. + /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the + /// index of the array or vector element being initialized. unsigned Index; }; @@ -141,7 +142,12 @@ public: /// \brief Create the initialization entity for a parameter that is /// only known by its type. static InitializedEntity InitializeParameter(QualType Type) { - return InitializedEntity(EK_Parameter, SourceLocation(), Type); + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Type; + Entity.Parent = 0; + Entity.VariableOrMember = 0; + return Entity; } /// \brief Create the initialization entity for the result of a function. @@ -168,7 +174,8 @@ public: /// \brief Create the initialization entity for a base class subobject. static InitializedEntity InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base); + CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase); /// \brief Create the initialization entity for a member subobject. static InitializedEntity InitializeMember(FieldDecl *Member, @@ -204,7 +211,13 @@ public: /// \brief Retrieve the base specifier. CXXBaseSpecifier *getBaseSpecifier() const { assert(getKind() == EK_Base && "Not a base specifier"); - return Base; + return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1); + } + + /// \brief Return whether the base is an inherited virtual base. + bool isInheritedVirtualBase() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base & 0x1; } /// \brief Determine the location of the 'return' keyword when initializing @@ -416,6 +429,10 @@ public: SK_BindReference, /// \brief Reference binding to a temporary. SK_BindReferenceToTemporary, + /// \brief An optional copy of a temporary object to another + /// temporary object, which is permitted (but not required) by + /// C++98/03 but not C++0x. + SK_ExtraneousCopyToTemporary, /// \brief Perform a user-defined conversion, either via a conversion /// function or via a constructor. SK_UserConversion, @@ -525,7 +542,11 @@ private: /// \brief The candidate set created when initialization failed. OverloadCandidateSet FailedCandidateSet; - + + /// \brief Prints a follow-up note that highlights the location of + /// the initialized entity, if it's remote. + void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); + public: /// \brief Try to perform initialization of the given entity, creating a /// record of the steps required to perform the initialization. @@ -606,6 +627,10 @@ public: /// \brief Determine whether this initialization failed due to an ambiguity. bool isAmbiguous() const; + /// \brief Determine whether this initialization is direct call to a + /// constructor. + bool isConstructorInitialization() const; + /// \brief Add a new step in the initialization that resolves the address /// of an overloaded function to a specific function declaration. /// @@ -625,11 +650,26 @@ public: /// \brief Add a new step binding a reference to an object. /// - /// \param BindingTemporary true if we are binding a reference to a temporary + /// \param BindingTemporary True if we are binding a reference to a temporary /// object (thereby extending its lifetime); false if we are binding to an /// lvalue or an lvalue treated as an rvalue. + /// + /// \param UnnecessaryCopy True if we should check for a copy + /// constructor for a completely unnecessary but void AddReferenceBindingStep(QualType T, bool BindingTemporary); - + + /// \brief Add a new step that makes an extraneous copy of the input + /// to a temporary of the same class type. + /// + /// This extraneous copy only occurs during reference binding in + /// C++98/03, where we are permitted (but not required) to introduce + /// an extra copy. At a bare minimum, we must check that we could + /// call the copy constructor, and produce a diagnostic if the copy + /// constructor is inaccessible or no copy constructor matches. + // + /// \param T The type of the temporary being created. + void AddExtraneousCopyToTemporary(QualType T); + /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. void AddUserConversionStep(FunctionDecl *Function, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a29c4d4..337a4a3 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -193,62 +193,6 @@ namespace { }; } -static bool IsAcceptableIDNS(NamedDecl *D, unsigned IDNS) { - return D->isInIdentifierNamespace(IDNS); -} - -static bool IsAcceptableOperatorName(NamedDecl *D, unsigned IDNS) { - return D->isInIdentifierNamespace(IDNS) && - !D->getDeclContext()->isRecord(); -} - -static bool IsAcceptableNestedNameSpecifierName(NamedDecl *D, unsigned IDNS) { - // This lookup ignores everything that isn't a type. - - // This is a fast check for the far most common case. - if (D->isInIdentifierNamespace(Decl::IDNS_Tag)) - return true; - - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - return isa<TypeDecl>(D); -} - -static bool IsAcceptableNamespaceName(NamedDecl *D, unsigned IDNS) { - // We don't need to look through using decls here because - // using decls aren't allowed to name namespaces. - - return isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D); -} - -/// Gets the default result filter for the given lookup. -static inline -LookupResult::ResultFilter getResultFilter(Sema::LookupNameKind NameKind) { - switch (NameKind) { - case Sema::LookupOrdinaryName: - case Sema::LookupTagName: - case Sema::LookupMemberName: - case Sema::LookupRedeclarationWithLinkage: // FIXME: check linkage, scoping - case Sema::LookupUsingDeclName: - case Sema::LookupObjCProtocolName: - case Sema::LookupObjCImplementationName: - return &IsAcceptableIDNS; - - case Sema::LookupOperatorName: - return &IsAcceptableOperatorName; - - case Sema::LookupNestedNameSpecifierName: - return &IsAcceptableNestedNameSpecifierName; - - case Sema::LookupNamespaceName: - return &IsAcceptableNamespaceName; - } - - llvm_unreachable("unkknown lookup kind"); - return 0; -} - // Retrieve the set of identifier namespaces that correspond to a // specific kind of name lookup. static inline unsigned getIDNS(Sema::LookupNameKind NameKind, @@ -257,19 +201,35 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, unsigned IDNS = 0; switch (NameKind) { case Sema::LookupOrdinaryName: - case Sema::LookupOperatorName: case Sema::LookupRedeclarationWithLinkage: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { - IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; if (Redeclaration) IDNS |= Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend; } break; + case Sema::LookupOperatorName: + // Operator lookup is its own crazy thing; it is not the same + // as (e.g.) looking up an operator name for redeclaration. + assert(!Redeclaration && "cannot do redeclaration operator lookup"); + IDNS = Decl::IDNS_NonMemberOperator; + break; + case Sema::LookupTagName: - IDNS = Decl::IDNS_Tag; - if (CPlusPlus && Redeclaration) - IDNS |= Decl::IDNS_TagFriend; + if (CPlusPlus) { + IDNS = Decl::IDNS_Type; + + // When looking for a redeclaration of a tag name, we add: + // 1) TagFriend to find undeclared friend decls + // 2) Namespace because they can't "overload" with tag decls. + // 3) Tag because it includes class templates, which can't + // "overload" with tag decls. + if (Redeclaration) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_TagFriend | Decl::IDNS_Namespace; + } else { + IDNS = Decl::IDNS_Tag; + } break; case Sema::LookupMemberName: @@ -279,8 +239,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, break; case Sema::LookupNestedNameSpecifierName: + IDNS = Decl::IDNS_Type | Decl::IDNS_Namespace; + break; + case Sema::LookupNamespaceName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; + IDNS = Decl::IDNS_Namespace; break; case Sema::LookupUsingDeclName: @@ -291,10 +254,6 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; - - case Sema::LookupObjCImplementationName: - IDNS = Decl::IDNS_ObjCImplementation; - break; } return IDNS; } @@ -303,7 +262,6 @@ void LookupResult::configure() { IDNS = getIDNS(LookupKind, SemaRef.getLangOptions().CPlusPlus, isForRedeclaration()); - IsAcceptableFn = getResultFilter(LookupKind); // If we're looking for one of the allocation or deallocation // operators, make sure that the implicitly-declared new and delete @@ -341,9 +299,10 @@ void LookupResult::resolveKind() { // If there's a single decl, we need to examine it to decide what // kind of lookup this is. if (N == 1) { - if (isa<FunctionTemplateDecl>(*Decls.begin())) + NamedDecl *D = (*Decls.begin())->getUnderlyingDecl(); + if (isa<FunctionTemplateDecl>(D)) ResultKind = FoundOverloaded; - else if (isa<UnresolvedUsingValueDecl>(*Decls.begin())) + else if (isa<UnresolvedUsingValueDecl>(D)) ResultKind = FoundUnresolvedValue; return; } @@ -1169,7 +1128,6 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupOperatorName: case LookupNamespaceName: case LookupObjCProtocolName: - case LookupObjCImplementationName: // These lookups will never find a member in a C++ class (or base class). return false; @@ -1291,7 +1249,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, /// context of the scope-specifier SS (if present). /// /// @returns True if any decls were found (but possibly ambiguous) -bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, +bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation, bool EnteringContext) { if (SS && SS->isInvalid()) { // When the scope specifier is invalid, don't even look for @@ -1303,7 +1261,7 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, const CXXScopeSpec *SS, if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. - if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS)) + if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS, DC)) return false; R.setContextRange(SS->getRange()); @@ -1428,10 +1386,18 @@ addAssociatedClassesAndNamespaces(QualType T, Sema::AssociatedNamespaceSet &AssociatedNamespaces, Sema::AssociatedClassSet &AssociatedClasses); -static void CollectNamespace(Sema::AssociatedNamespaceSet &Namespaces, - DeclContext *Ctx) { +static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, + DeclContext *Ctx) { + // Add the associated namespace for this class. + + // We don't use DeclContext::getEnclosingNamespaceContext() as this may + // be a locally scoped record. + + while (Ctx->isRecord() || Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + if (Ctx->isFileContext()) - Namespaces.insert(Ctx); + Namespaces.insert(Ctx->getPrimaryContext()); } // \brief Add the associated classes and namespaces for argument-dependent @@ -1467,9 +1433,7 @@ addAssociatedClassesAndNamespaces(const TemplateArgument &Arg, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); } break; } @@ -1513,9 +1477,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); // Add the class itself. If we've already seen this class, we don't // need to visit base classes. @@ -1537,9 +1499,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -1580,9 +1540,7 @@ addAssociatedClassesAndNamespaces(CXXRecordDecl *Class, if (AssociatedClasses.insert(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); - while (BaseCtx->isRecord()) - BaseCtx = BaseCtx->getParent(); - CollectNamespace(AssociatedNamespaces, BaseCtx); + CollectEnclosingNamespace(AssociatedNamespaces, BaseCtx); // Make sure we visit the bases of this base class. if (BaseDecl->bases_begin() != BaseDecl->bases_end()) @@ -1657,9 +1615,7 @@ addAssociatedClassesAndNamespaces(QualType T, AssociatedClasses.insert(EnclosingClass); // Add the associated namespace for this class. - while (Ctx->isRecord()) - Ctx = Ctx->getParent(); - CollectNamespace(AssociatedNamespaces, Ctx); + CollectEnclosingNamespace(AssociatedNamespaces, Ctx); return; } @@ -1825,16 +1781,19 @@ IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn, } NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl) { - LookupResult R(*this, Name, SourceLocation(), NameKind, Redecl); + LookupResult R(*this, Name, Loc, NameKind, Redecl); LookupName(R, S); return R.getAsSingle<NamedDecl>(); } /// \brief Find the protocol with the given name, if any. -ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II) { - Decl *D = LookupSingleName(TUScope, II, LookupObjCProtocolName); +ObjCProtocolDecl *Sema::LookupProtocol(IdentifierInfo *II, + SourceLocation IdLoc) { + Decl *D = LookupSingleName(TUScope, II, IdLoc, + LookupObjCProtocolName); return cast_or_null<ObjCProtocolDecl>(D); } @@ -1864,16 +1823,17 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end(); Op != OpEnd; ++Op) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*Op)) { + NamedDecl *Found = (*Op)->getUnderlyingDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) { if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context)) - Functions.addDecl(FD, Op.getAccess()); // FIXME: canonical FD + Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD } else if (FunctionTemplateDecl *FunTmpl - = dyn_cast<FunctionTemplateDecl>(*Op)) { + = dyn_cast<FunctionTemplateDecl>(Found)) { // FIXME: friend operators? // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate, // later? if (!FunTmpl->getDeclContext()->isRecord()) - Functions.addDecl(FunTmpl, Op.getAccess()); + Functions.addDecl(*Op, Op.getAccess()); } } } @@ -2137,7 +2097,7 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) { IEnd = Pos->second.end(); I != IEnd; ++I) { // A tag declaration does not hide a non-tag declaration. - if ((*I)->getIdentifierNamespace() == Decl::IDNS_Tag && + if ((*I)->hasTagIdentifierNamespace() && (IDNS & (Decl::IDNS_Member | Decl::IDNS_Ordinary | Decl::IDNS_ObjCProtocol))) continue; @@ -2276,6 +2236,14 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup, true, Consumer, Visited); } + + // If there is an implementation, traverse it. We do this to find + // synthesized ivars. + if (IFace->getImplementation()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(IFace->getImplementation(), Result, + QualifiedNameLookup, true, Consumer, Visited); + } } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) { for (ObjCProtocolDecl::protocol_iterator I = Protocol->protocol_begin(), E = Protocol->protocol_end(); I != E; ++I) { @@ -2290,6 +2258,13 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); } + + // If there is an implementation, traverse it. + if (Category->getImplementation()) { + ShadowContextRAII Shadow(Visited); + LookupVisibleDecls(Category->getImplementation(), Result, + QualifiedNameLookup, true, Consumer, Visited); + } } } @@ -2421,6 +2396,9 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { /// found (so far) with the typo name. llvm::SmallVector<NamedDecl *, 4> BestResults; + /// \brief The keywords that have the smallest edit distance. + llvm::SmallVector<IdentifierInfo *, 4> BestKeywords; + /// \brief The best edit distance found so far. unsigned BestEditDistance; @@ -2429,13 +2407,23 @@ public: : Typo(Typo->getName()) { } virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, bool InBaseClass); + void addKeywordResult(ASTContext &Context, llvm::StringRef Keyword); typedef llvm::SmallVector<NamedDecl *, 4>::const_iterator iterator; iterator begin() const { return BestResults.begin(); } iterator end() const { return BestResults.end(); } - bool empty() const { return BestResults.empty(); } - - unsigned getBestEditDistance() const { return BestEditDistance; } + void clear_decls() { BestResults.clear(); } + + bool empty() const { return BestResults.empty() && BestKeywords.empty(); } + + typedef llvm::SmallVector<IdentifierInfo *, 4>::const_iterator + keyword_iterator; + keyword_iterator keyword_begin() const { return BestKeywords.begin(); } + keyword_iterator keyword_end() const { return BestKeywords.end(); } + bool keyword_empty() const { return BestKeywords.empty(); } + unsigned keyword_size() const { return BestKeywords.size(); } + + unsigned getBestEditDistance() const { return BestEditDistance; } }; } @@ -2457,11 +2445,12 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, // entity. If this edit distance is not worse than the best edit // distance we've seen so far, add it to the list of results. unsigned ED = Typo.edit_distance(Name->getName()); - if (!BestResults.empty()) { + if (!BestResults.empty() || !BestKeywords.empty()) { if (ED < BestEditDistance) { // This result is better than any we've seen before; clear out // the previous results. BestResults.clear(); + BestKeywords.clear(); BestEditDistance = ED; } else if (ED > BestEditDistance) { // This result is worse than the best results we've seen so far; @@ -2474,6 +2463,28 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, BestResults.push_back(ND); } +void TypoCorrectionConsumer::addKeywordResult(ASTContext &Context, + llvm::StringRef Keyword) { + // Compute the edit distance between the typo and this keyword. + // If this edit distance is not worse than the best edit + // distance we've seen so far, add it to the list of results. + unsigned ED = Typo.edit_distance(Keyword); + if (!BestResults.empty() || !BestKeywords.empty()) { + if (ED < BestEditDistance) { + BestResults.clear(); + BestKeywords.clear(); + BestEditDistance = ED; + } else if (ED > BestEditDistance) { + // This result is worse than the best results we've seen so far; + // ignore it. + return; + } + } else + BestEditDistance = ED; + + BestKeywords.push_back(&Context.Idents.get(Keyword)); +} + /// \brief Try to "correct" a typo in the source code by finding /// visible declarations whose names are similar to the name that was /// present in the source code. @@ -2494,42 +2505,50 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, /// \param EnteringContext whether we're entering the context described by /// the nested-name-specifier SS. /// +/// \param CTC The context in which typo correction occurs, which impacts the +/// set of keywords permitted. +/// /// \param OPT when non-NULL, the search for visible declarations will /// also walk the protocols in the qualified interfaces of \p OPT. /// -/// \returns true if the typo was corrected, in which case the \p Res -/// structure will contain the results of name lookup for the -/// corrected name. Otherwise, returns false. -bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, - DeclContext *MemberContext, bool EnteringContext, - const ObjCObjectPointerType *OPT) { +/// \returns the corrected name if the typo was corrected, otherwise returns an +/// empty \c DeclarationName. When a typo was corrected, the result structure +/// may contain the results of name lookup for the correct name or it may be +/// empty. +DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, + DeclContext *MemberContext, + bool EnteringContext, + CorrectTypoContext CTC, + const ObjCObjectPointerType *OPT) { if (Diags.hasFatalErrorOccurred()) - return false; + return DeclarationName(); // Provide a stop gap for files that are just seriously broken. Trying // to correct all typos can turn into a HUGE performance penalty, causing // some files to take minutes to get rejected by the parser. // FIXME: Is this the right solution? if (TyposCorrected == 20) - return false; + return DeclarationName(); ++TyposCorrected; // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = Res.getLookupName().getAsIdentifierInfo(); if (!Typo) - return false; + return DeclarationName(); // If the scope specifier itself was invalid, don't try to correct // typos. if (SS && SS->isInvalid()) - return false; + return DeclarationName(); // Never try to correct typos during template deduction or // instantiation. if (!ActiveTemplateInstantiations.empty()) - return false; - + return DeclarationName(); + TypoCorrectionConsumer Consumer(Typo); + + // Perform name lookup to find visible, similarly-named entities. if (MemberContext) { LookupVisibleDecls(MemberContext, Res.getLookupKind(), Consumer); @@ -2543,45 +2562,239 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, } else if (SS && SS->isSet()) { DeclContext *DC = computeDeclContext(*SS, EnteringContext); if (!DC) - return false; + return DeclarationName(); LookupVisibleDecls(DC, Res.getLookupKind(), Consumer); } else { LookupVisibleDecls(S, Res.getLookupKind(), Consumer); } + // Add context-dependent keywords. + bool WantTypeSpecifiers = false; + bool WantExpressionKeywords = false; + bool WantCXXNamedCasts = false; + bool WantRemainingKeywords = false; + switch (CTC) { + case CTC_Unknown: + WantTypeSpecifiers = true; + WantExpressionKeywords = true; + WantCXXNamedCasts = true; + WantRemainingKeywords = true; + break; + + case CTC_NoKeywords: + break; + + case CTC_Type: + WantTypeSpecifiers = true; + break; + + case CTC_ObjCMessageReceiver: + Consumer.addKeywordResult(Context, "super"); + // Fall through to handle message receivers like expressions. + + case CTC_Expression: + if (getLangOptions().CPlusPlus) + WantTypeSpecifiers = true; + WantExpressionKeywords = true; + // Fall through to get C++ named casts. + + case CTC_CXXCasts: + WantCXXNamedCasts = true; + break; + + case CTC_MemberLookup: + if (getLangOptions().CPlusPlus) + Consumer.addKeywordResult(Context, "template"); + break; + } + + if (WantTypeSpecifiers) { + // Add type-specifier keywords to the set of results. + const char *CTypeSpecs[] = { + "char", "const", "double", "enum", "float", "int", "long", "short", + "signed", "struct", "union", "unsigned", "void", "volatile", "_Bool", + "_Complex", "_Imaginary", + // storage-specifiers as well + "extern", "inline", "static", "typedef" + }; + + const unsigned NumCTypeSpecs = sizeof(CTypeSpecs) / sizeof(CTypeSpecs[0]); + for (unsigned I = 0; I != NumCTypeSpecs; ++I) + Consumer.addKeywordResult(Context, CTypeSpecs[I]); + + if (getLangOptions().C99) + Consumer.addKeywordResult(Context, "restrict"); + if (getLangOptions().Bool || getLangOptions().CPlusPlus) + Consumer.addKeywordResult(Context, "bool"); + + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "class"); + Consumer.addKeywordResult(Context, "typename"); + Consumer.addKeywordResult(Context, "wchar_t"); + + if (getLangOptions().CPlusPlus0x) { + Consumer.addKeywordResult(Context, "char16_t"); + Consumer.addKeywordResult(Context, "char32_t"); + Consumer.addKeywordResult(Context, "constexpr"); + Consumer.addKeywordResult(Context, "decltype"); + Consumer.addKeywordResult(Context, "thread_local"); + } + } + + if (getLangOptions().GNUMode) + Consumer.addKeywordResult(Context, "typeof"); + } + + if (WantCXXNamedCasts) { + Consumer.addKeywordResult(Context, "const_cast"); + Consumer.addKeywordResult(Context, "dynamic_cast"); + Consumer.addKeywordResult(Context, "reinterpret_cast"); + Consumer.addKeywordResult(Context, "static_cast"); + } + + if (WantExpressionKeywords) { + Consumer.addKeywordResult(Context, "sizeof"); + if (getLangOptions().Bool || getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "false"); + Consumer.addKeywordResult(Context, "true"); + } + + if (getLangOptions().CPlusPlus) { + const char *CXXExprs[] = { + "delete", "new", "operator", "throw", "typeid" + }; + const unsigned NumCXXExprs = sizeof(CXXExprs) / sizeof(CXXExprs[0]); + for (unsigned I = 0; I != NumCXXExprs; ++I) + Consumer.addKeywordResult(Context, CXXExprs[I]); + + if (isa<CXXMethodDecl>(CurContext) && + cast<CXXMethodDecl>(CurContext)->isInstance()) + Consumer.addKeywordResult(Context, "this"); + + if (getLangOptions().CPlusPlus0x) { + Consumer.addKeywordResult(Context, "alignof"); + Consumer.addKeywordResult(Context, "nullptr"); + } + } + } + + if (WantRemainingKeywords) { + if (getCurFunctionOrMethodDecl() || getCurBlock()) { + // Statements. + const char *CStmts[] = { + "do", "else", "for", "goto", "if", "return", "switch", "while" }; + const unsigned NumCStmts = sizeof(CStmts) / sizeof(CStmts[0]); + for (unsigned I = 0; I != NumCStmts; ++I) + Consumer.addKeywordResult(Context, CStmts[I]); + + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "catch"); + Consumer.addKeywordResult(Context, "try"); + } + + if (S && S->getBreakParent()) + Consumer.addKeywordResult(Context, "break"); + + if (S && S->getContinueParent()) + Consumer.addKeywordResult(Context, "continue"); + + if (!getSwitchStack().empty()) { + Consumer.addKeywordResult(Context, "case"); + Consumer.addKeywordResult(Context, "default"); + } + } else { + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "namespace"); + Consumer.addKeywordResult(Context, "template"); + } + + if (S && S->isClassScope()) { + Consumer.addKeywordResult(Context, "explicit"); + Consumer.addKeywordResult(Context, "friend"); + Consumer.addKeywordResult(Context, "mutable"); + Consumer.addKeywordResult(Context, "private"); + Consumer.addKeywordResult(Context, "protected"); + Consumer.addKeywordResult(Context, "public"); + Consumer.addKeywordResult(Context, "virtual"); + } + } + + if (getLangOptions().CPlusPlus) { + Consumer.addKeywordResult(Context, "using"); + + if (getLangOptions().CPlusPlus0x) + Consumer.addKeywordResult(Context, "static_assert"); + } + } + + // If we haven't found anything, we're done. if (Consumer.empty()) - return false; + return DeclarationName(); // Only allow a single, closest name in the result set (it's okay to // have overloads of that name, though). - TypoCorrectionConsumer::iterator I = Consumer.begin(); - DeclarationName BestName = (*I)->getDeclName(); - - // If we've found an Objective-C ivar or property, don't perform - // name lookup again; we'll just return the result directly. - NamedDecl *FoundBest = 0; - if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) - FoundBest = *I; - ++I; - for(TypoCorrectionConsumer::iterator IEnd = Consumer.end(); I != IEnd; ++I) { - if (BestName != (*I)->getDeclName()) - return false; - - // FIXME: If there are both ivars and properties of the same name, - // don't return both because the callee can't handle two - // results. We really need to separate ivar lookup from property - // lookup to avoid this problem. - FoundBest = 0; + DeclarationName BestName; + NamedDecl *BestIvarOrPropertyDecl = 0; + bool FoundIvarOrPropertyDecl = false; + + // Check all of the declaration results to find the best name so far. + for (TypoCorrectionConsumer::iterator I = Consumer.begin(), + IEnd = Consumer.end(); + I != IEnd; ++I) { + if (!BestName) + BestName = (*I)->getDeclName(); + else if (BestName != (*I)->getDeclName()) + return DeclarationName(); + + // \brief Keep track of either an Objective-C ivar or a property, but not + // both. + if (isa<ObjCIvarDecl>(*I) || isa<ObjCPropertyDecl>(*I)) { + if (FoundIvarOrPropertyDecl) + BestIvarOrPropertyDecl = 0; + else { + BestIvarOrPropertyDecl = *I; + FoundIvarOrPropertyDecl = true; + } + } } + // Now check all of the keyword results to find the best name. + switch (Consumer.keyword_size()) { + case 0: + // No keywords matched. + break; + + case 1: + // If we already have a name + if (!BestName) { + // We did not have anything previously, + BestName = *Consumer.keyword_begin(); + } else if (BestName.getAsIdentifierInfo() == *Consumer.keyword_begin()) { + // We have a declaration with the same name as a context-sensitive + // keyword. The keyword takes precedence. + BestIvarOrPropertyDecl = 0; + FoundIvarOrPropertyDecl = false; + Consumer.clear_decls(); + } else { + // Name collision; we will not correct typos. + return DeclarationName(); + } + break; + + default: + // Name collision; we will not correct typos. + return DeclarationName(); + } + // BestName is the closest viable name to what the user // typed. However, to make sure that we don't pick something that's // way off, make sure that the user typed at least 3 characters for // each correction. unsigned ED = Consumer.getBestEditDistance(); - if (ED == 0 || (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) - return false; + if (ED == 0 || !BestName.getAsIdentifierInfo() || + (BestName.getAsIdentifierInfo()->getName().size() / ED) < 3) + return DeclarationName(); // Perform name lookup again with the name we chose, and declare // success if we found something that was not ambiguous. @@ -2590,11 +2803,14 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, // If we found an ivar or property, add that result; no further // lookup is required. - if (FoundBest) - Res.addDecl(FoundBest); + if (BestIvarOrPropertyDecl) + Res.addDecl(BestIvarOrPropertyDecl); // If we're looking into the context of a member, perform qualified // name lookup on the best name. - else if (MemberContext) + else if (!Consumer.keyword_empty()) { + // The best match was a keyword. Return it. + return BestName; + } else if (MemberContext) LookupQualifiedName(Res, MemberContext); // Perform lookup as if we had just parsed the best name. else @@ -2603,8 +2819,11 @@ bool Sema::CorrectTypo(LookupResult &Res, Scope *S, const CXXScopeSpec *SS, if (Res.isAmbiguous()) { Res.suppressDiagnostics(); - return false; + return DeclarationName(); } - return Res.getResultKind() != LookupResult::NotFound; + if (Res.getResultKind() != LookupResult::NotFound) + return BestName; + + return DeclarationName(); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index cda1f0b..b73739f 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -204,7 +204,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, ObjCInterfaceDecl *IDecl = OIT->getDecl(); if (IDecl) if (ObjCProtocolDecl* PNSCopying = - LookupProtocol(&Context.Idents.get("NSCopying"))) + LookupProtocol(&Context.Idents.get("NSCopying"), AtLoc)) if (IDecl->ClassImplementsProtocol(PNSCopying, true)) Diag(AtLoc, diag::warn_implements_nscopying) << PropertyId; } @@ -356,7 +356,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(SourceLocation AtLoc, if (!Ivar) { Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyIvar, PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, + ObjCIvarDecl::Protected, (Expr *)0); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); @@ -719,7 +719,10 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, // scan through class's protocols. for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), E = IDecl->protocol_end(); PI != E; ++PI) - CollectImmediateProperties((*PI), PropMap); + // Exclude property for protocols which conform to class's super-class, + // as super-class has to implement the property. + if (!ProtocolConformsToSuperClass(IDecl, (*PI))) + CollectImmediateProperties((*PI), PropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { if (!CATDecl->IsClassExtension()) @@ -748,6 +751,33 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } +/// ProtocolConformsToSuperClass - Returns true if class's given protocol +/// conforms to one of its super class's protocols. +bool Sema::ProtocolConformsToSuperClass(const ObjCInterfaceDecl *IDecl, + const ObjCProtocolDecl *PDecl) { + if (const ObjCInterfaceDecl *CDecl = IDecl->getSuperClass()) { + for (ObjCInterfaceDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) { + if (ProtocolConformsToProtocol((*PI), PDecl)) + return true; + return ProtocolConformsToSuperClass(CDecl, PDecl); + } + } + return false; +} + +bool Sema::ProtocolConformsToProtocol(const ObjCProtocolDecl *NestedProtocol, + const ObjCProtocolDecl *PDecl) { + if (PDecl->getIdentifier() == NestedProtocol->getIdentifier()) + return true; + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + if (ProtocolConformsToProtocol(NestedProtocol, (*PI))) + return true; + return false; +} + /// LookupPropertyDecl - Looks up a property in the current class and all /// its protocols. ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, @@ -810,9 +840,9 @@ void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop)) continue; - if (LangOpts.ObjCNonFragileABI2) { + if (LangOpts.ObjCNonFragileABI2 && !isa<ObjCCategoryImplDecl>(IMPDecl)) { ActOnPropertyImplDecl(IMPDecl->getLocation(), - SourceLocation(), + IMPDecl->getLocation(), true, DeclPtrTy::make(IMPDecl), Prop->getIdentifier(), Prop->getIdentifier()); @@ -953,8 +983,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getType(), /*TInfo=*/0, VarDecl::None, + VarDecl::None, 0); - SetterMethod->setMethodParams(Context, &Argument, 1); + SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); } else // A user declared setter will be synthesize when @synthesize of @@ -1066,21 +1097,3 @@ void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, && PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); } - -ObjCIvarDecl* -Sema::SynthesizeNewPropertyIvar(ObjCInterfaceDecl *IDecl, - IdentifierInfo *NameII) { - ObjCIvarDecl *Ivar = 0; - ObjCPropertyDecl *Prop = LookupPropertyDecl(IDecl, NameII); - if (Prop && !Prop->isInvalidDecl()) { - QualType PropType = Context.getCanonicalType(Prop->getType()); - Ivar = ObjCIvarDecl::Create(Context, IDecl, Prop->getLocation(), NameII, - PropType, /*Dinfo=*/0, - ObjCIvarDecl::Public, (Expr *)0); - Ivar->setLexicalDeclContext(IDecl); - IDecl->addDecl(Ivar); - Prop->setPropertyIvarDecl(Ivar); - } - return Ivar; -} - diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index bc10a58..21f2a51 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -226,7 +226,7 @@ void UserDefinedConversionSequence::DebugPrint() const { Before.DebugPrint(); OS << " -> "; } - OS << "'" << ConversionFunction->getNameAsString() << "'"; + OS << '\'' << ConversionFunction << '\''; if (After.First || After.Second || After.Third) { OS << " -> "; After.DebugPrint(); @@ -374,8 +374,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { if (OldQType != NewQType && (OldType->getNumArgs() != NewType->getNumArgs() || OldType->isVariadic() != NewType->isVariadic() || - !std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), - NewType->arg_type_begin()))) + !FunctionArgTypesAreEqual(OldType, NewType))) return true; // C++ [temp.over.link]p4: @@ -436,16 +435,11 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old) { /// not permitted. /// If @p AllowExplicit, then explicit user-defined conversions are /// permitted. -/// If @p ForceRValue, then overloading is performed as if From was an rvalue, -/// no matter its actual lvalueness. -/// If @p UserCast, the implicit conversion is being done for a user-specified -/// cast. ImplicitConversionSequence Sema::TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, bool ForceRValue, - bool InOverloadResolution, - bool UserCast) { + bool AllowExplicit, + bool InOverloadResolution) { ImplicitConversionSequence ICS; if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) { ICS.setStandard(); @@ -457,11 +451,47 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } + if (SuppressUserConversions) { + // C++ [over.ics.user]p4: + // A conversion of an expression of class type to the same class + // type is given Exact Match rank, and a conversion of an + // expression of class type to a base class of that type is + // given Conversion rank, in spite of the fact that a copy/move + // constructor (i.e., a user-defined conversion function) is + // called for those cases. + QualType FromType = From->getType(); + if (!ToType->getAs<RecordType>() || !FromType->getAs<RecordType>() || + !(Context.hasSameUnqualifiedType(FromType, ToType) || + IsDerivedFrom(FromType, ToType))) { + // We're not in the case above, so there is no conversion that + // we can perform. + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); + return ICS; + } + + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + ICS.Standard.setFromType(FromType); + ICS.Standard.setAllToTypes(ToType); + + // We don't actually check at this point whether there is a valid + // copy/move constructor, since overloading just assumes that it + // exists. When we actually perform initialization, we'll find the + // appropriate constructor to copy the returned object, if needed. + ICS.Standard.CopyConstructor = 0; + + // Determine whether this is considered a derived-to-base conversion. + if (!Context.hasSameUnqualifiedType(FromType, ToType)) + ICS.Standard.Second = ICK_Derived_To_Base; + + return ICS; + } + + // Attempt user-defined conversion. OverloadCandidateSet Conversions(From->getExprLoc()); OverloadingResult UserDefResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, - !SuppressUserConversions, AllowExplicit, - ForceRValue, UserCast); + AllowExplicit); if (UserDefResult == OR_Success) { ICS.setUserDefined(); @@ -516,6 +546,30 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +/// PerformImplicitConversion - Perform an implicit conversion of the +/// expression From to the type ToType. Returns true if there was an +/// error, false otherwise. The expression From is replaced with the +/// converted expression. Flavor is the kind of conversion we're +/// performing, used in the error message. If @p AllowExplicit, +/// explicit user-defined conversions are permitted. +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + AssignmentAction Action, bool AllowExplicit) { + ImplicitConversionSequence ICS; + return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); +} + +bool +Sema::PerformImplicitConversion(Expr *&From, QualType ToType, + AssignmentAction Action, bool AllowExplicit, + ImplicitConversionSequence& ICS) { + ICS = TryImplicitConversion(From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*InOverloadResolution=*/false); + return PerformImplicitConversion(From, ToType, ICS, Action); +} + /// \brief Determine whether the conversion from FromType to ToType is a valid /// conversion that strips "noreturn" off the nested function type. static bool IsNoReturnConversion(ASTContext &Context, QualType FromType, @@ -567,8 +621,36 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). - DeclAccessPair AccessPair; - + if (FromType == Context.OverloadTy) { + DeclAccessPair AccessPair; + if (FunctionDecl *Fn + = ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { + // We were able to resolve the address of the overloaded function, + // so we can convert to the type of that function. + FromType = Fn->getType(); + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { + if (!Method->isStatic()) { + Type *ClassType + = Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FromType = Context.getMemberPointerType(FromType, ClassType); + } + } + + // If the "from" expression takes the address of the overloaded + // function, update the type of the resulting expression accordingly. + if (FromType->getAs<FunctionType>()) + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens())) + if (UnOp->getOpcode() == UnaryOperator::AddrOf) + FromType = Context.getPointerType(FromType); + + // Check that we've computed the proper type after overload resolution. + assert(Context.hasSameType(FromType, + FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); + } else { + return false; + } + } // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. @@ -613,31 +695,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); - } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false, - AccessPair)) { - // Address of overloaded function (C++ [over.over]). - SCS.First = ICK_Function_To_Pointer; - - // We were able to resolve the address of the overloaded function, - // so we can convert to the type of that function. - FromType = Fn->getType(); - if (ToType->isLValueReferenceType()) - FromType = Context.getLValueReferenceType(FromType); - else if (ToType->isRValueReferenceType()) - FromType = Context.getRValueReferenceType(FromType); - else if (ToType->isMemberPointerType()) { - // Resolve address only succeeds if both sides are member pointers, - // but it doesn't have to be the same class. See DR 247. - // Note that this means that the type of &Derived::fn can be - // Ret (Base::*)(Args) if the fn overload actually found is from the - // base class, even if it was brought into the derived class via a - // using declaration. The standard isn't clear on this issue at all. - CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); - FromType = Context.getMemberPointerType(FromType, - Context.getTypeDeclType(M->getParent()).getTypePtr()); - } else - FromType = Context.getPointerType(FromType); } else { // We don't require any conversions for the first step. SCS.First = ICK_Identity; @@ -1274,6 +1331,47 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, return false; } + +/// FunctionArgTypesAreEqual - This routine checks two function proto types +/// for equlity of their argument types. Caller has already checked that +/// they have same number of arguments. This routine assumes that Objective-C +/// pointer types which only differ in their protocol qualifiers are equal. +bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, + FunctionProtoType* NewType){ + if (!getLangOptions().ObjC1) + return std::equal(OldType->arg_type_begin(), OldType->arg_type_end(), + NewType->arg_type_begin()); + + for (FunctionProtoType::arg_type_iterator O = OldType->arg_type_begin(), + N = NewType->arg_type_begin(), + E = OldType->arg_type_end(); O && (O != E); ++O, ++N) { + QualType ToType = (*O); + QualType FromType = (*N); + if (ToType != FromType) { + if (const PointerType *PTTo = ToType->getAs<PointerType>()) { + if (const PointerType *PTFr = FromType->getAs<PointerType>()) + if (PTTo->getPointeeType()->isObjCQualifiedIdType() && + PTFr->getPointeeType()->isObjCQualifiedIdType() || + PTTo->getPointeeType()->isObjCQualifiedClassType() && + PTFr->getPointeeType()->isObjCQualifiedClassType()) + continue; + } + else if (ToType->isObjCObjectPointerType() && + FromType->isObjCObjectPointerType()) { + QualType ToInterfaceTy = ToType->getPointeeType(); + QualType FromInterfaceTy = FromType->getPointeeType(); + if (const ObjCInterfaceType *OITTo = + ToInterfaceTy->getAs<ObjCInterfaceType>()) + if (const ObjCInterfaceType *OITFr = + FromInterfaceTy->getAs<ObjCInterfaceType>()) + if (OITTo->getDecl() == OITFr->getDecl()) + continue; + } + return false; + } + } + return true; +} /// CheckPointerConversion - Check the pointer conversion from the /// expression From to the type ToType. This routine checks for @@ -1283,6 +1381,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, /// error, or returns false otherwise. bool Sema::CheckPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray& BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); @@ -1297,7 +1396,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // ambiguous or inaccessible conversion. if (CheckDerivedToBaseConversion(FromPointeeType, ToPointeeType, From->getExprLoc(), - From->getSourceRange(), + From->getSourceRange(), &BasePath, IgnoreBaseAccess)) return true; @@ -1368,6 +1467,7 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, CastExpr::CastKind &Kind, + CXXBaseSpecifierArray &BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); const MemberPointerType *FromPtrType = FromType->getAs<MemberPointerType>(); @@ -1391,7 +1491,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, assert(FromClass->isRecordType() && "Pointer into non-class."); assert(ToClass->isRecordType() && "Pointer into non-class."); - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/ true, + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); assert(DerivationOkay && @@ -1419,6 +1519,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, diag::err_downcast_from_inaccessible_base); // Must be a base to derived member conversion. + BuildBasePathArray(Paths, BasePath); Kind = CastExpr::CK_BaseToDerivedMemberPointer; return false; } @@ -1482,48 +1583,39 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// and this routine will return true. Otherwise, this routine returns /// false and User is unspecified. /// -/// \param AllowConversionFunctions true if the conversion should -/// consider conversion functions at all. If false, only constructors -/// will be considered. -/// /// \param AllowExplicit true if the conversion should consider C++0x /// "explicit" conversion functions as well as non-explicit conversion /// functions (C++0x [class.conv.fct]p2). -/// -/// \param ForceRValue true if the expression should be treated as an rvalue -/// for overload resolution. -/// \param UserCast true if looking for user defined conversion for a static -/// cast. OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowConversionFunctions, - bool AllowExplicit, - bool ForceRValue, - bool UserCast) { + OverloadCandidateSet& CandidateSet, + bool AllowExplicit) { + // Whether we will only visit constructors. + bool ConstructorsOnly = false; + + // If the type we are conversion to is a class type, enumerate its + // constructors. if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { + // C++ [over.match.ctor]p1: + // When objects of class type are direct-initialized (8.5), or + // copy-initialized from an expression of the same or a + // derived class type (8.5), overload resolution selects the + // constructor. [...] For copy-initialization, the candidate + // functions are all the converting constructors (12.3.1) of + // that class. The argument list is the expression-list within + // the parentheses of the initializer. + if (Context.hasSameUnqualifiedType(ToType, From->getType()) || + (From->getType()->getAs<RecordType>() && + IsDerivedFrom(From->getType(), ToType))) + ConstructorsOnly = true; + if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { // We're not going to find any constructors. } else if (CXXRecordDecl *ToRecordDecl = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { - // C++ [over.match.ctor]p1: - // When objects of class type are direct-initialized (8.5), or - // copy-initialized from an expression of the same or a - // derived class type (8.5), overload resolution selects the - // constructor. [...] For copy-initialization, the candidate - // functions are all the converting constructors (12.3.1) of - // that class. The argument list is the expression-list within - // the parentheses of the initializer. - bool SuppressUserConversions = !UserCast; - if (Context.hasSameUnqualifiedType(ToType, From->getType()) || - IsDerivedFrom(From->getType(), ToType)) { - SuppressUserConversions = false; - AllowConversionFunctions = false; - } - DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(ToType).getUnqualifiedType()); + Context.getCanonicalType(ToType).getUnqualifiedType()); DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = ToRecordDecl->lookup(ConstructorName); @@ -1547,26 +1639,25 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &From, 1, CandidateSet, - SuppressUserConversions, ForceRValue); + /*SuppressUserConversions=*/!ConstructorsOnly); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). AddOverloadCandidate(Constructor, FoundDecl, &From, 1, CandidateSet, - SuppressUserConversions, ForceRValue); + /*SuppressUserConversions=*/!ConstructorsOnly); } } } } - if (!AllowConversionFunctions) { - // Don't allow any conversion functions to enter the overload set. + // Enumerate conversion functions, if we're allowed to. + if (ConstructorsOnly) { } else if (RequireCompleteType(From->getLocStart(), From->getType(), - PDiag(0) - << From->getSourceRange())) { + PDiag(0) << From->getSourceRange())) { // No conversion functions from incomplete types. } else if (const RecordType *FromRecordType - = From->getType()->getAs<RecordType>()) { + = From->getType()->getAs<RecordType>()) { if (CXXRecordDecl *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. @@ -1672,7 +1763,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { OverloadCandidateSet CandidateSet(From->getExprLoc()); OverloadingResult OvResult = IsUserDefinedConversion(From, ToType, ICS.UserDefined, - CandidateSet, true, false, false); + CandidateSet, false); if (OvResult == OR_Ambiguous) Diag(From->getSourceRange().getBegin(), diag::err_typecheck_ambiguous_condition) @@ -1708,15 +1799,14 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // described in 13.3.3.2, the ambiguous conversion sequence is // treated as a user-defined sequence that is indistinguishable // from any other user-defined conversion sequence. - if (ICS1.getKind() < ICS2.getKind()) { - if (!(ICS1.isUserDefined() && ICS2.isAmbiguous())) - return ImplicitConversionSequence::Better; - } else if (ICS2.getKind() < ICS1.getKind()) { - if (!(ICS2.isUserDefined() && ICS1.isAmbiguous())) - return ImplicitConversionSequence::Worse; - } + if (ICS1.getKindRank() < ICS2.getKindRank()) + return ImplicitConversionSequence::Better; + else if (ICS2.getKindRank() < ICS1.getKindRank()) + return ImplicitConversionSequence::Worse; - if (ICS1.isAmbiguous() || ICS2.isAmbiguous()) + // The following checks require both conversion sequences to be of + // the same kind. + if (ICS1.getKind() != ICS2.getKind()) return ImplicitConversionSequence::Indistinguishable; // Two implicit conversion sequences of the same form are @@ -2143,9 +2233,7 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, } } - if ((SCS1.ReferenceBinding || SCS1.CopyConstructor) && - (SCS2.ReferenceBinding || SCS2.CopyConstructor) && - SCS1.Second == ICK_Derived_To_Base) { + if (SCS1.Second == ICK_Derived_To_Base) { // -- conversion of C to B is better than conversion of C to A, // -- binding of an expression of type C to a reference of type // B& is better than binding an expression of type C to a @@ -2174,34 +2262,353 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, return ImplicitConversionSequence::Indistinguishable; } +/// CompareReferenceRelationship - Compare the two types T1 and T2 to +/// determine whether they are reference-related, +/// reference-compatible, reference-compatible with added +/// qualification, or incompatible, for use in C++ initialization by +/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference +/// type, and the first type (T1) is the pointee type of the reference +/// type being initialized. +Sema::ReferenceCompareResult +Sema::CompareReferenceRelationship(SourceLocation Loc, + QualType OrigT1, QualType OrigT2, + bool& DerivedToBase) { + assert(!OrigT1->isReferenceType() && + "T1 must be the pointee type of the reference type"); + assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); + + QualType T1 = Context.getCanonicalType(OrigT1); + QualType T2 = Context.getCanonicalType(OrigT2); + Qualifiers T1Quals, T2Quals; + QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); + + // C++ [dcl.init.ref]p4: + // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is + // reference-related to "cv2 T2" if T1 is the same type as T2, or + // T1 is a base class of T2. + if (UnqualT1 == UnqualT2) + DerivedToBase = false; + else if (!RequireCompleteType(Loc, OrigT1, PDiag()) && + !RequireCompleteType(Loc, OrigT2, PDiag()) && + IsDerivedFrom(UnqualT2, UnqualT1)) + DerivedToBase = true; + else + return Ref_Incompatible; + + // At this point, we know that T1 and T2 are reference-related (at + // least). + + // If the type is an array type, promote the element qualifiers to the type + // for comparison. + if (isa<ArrayType>(T1) && T1Quals) + T1 = Context.getQualifiedType(UnqualT1, T1Quals); + if (isa<ArrayType>(T2) && T2Quals) + T2 = Context.getQualifiedType(UnqualT2, T2Quals); + + // C++ [dcl.init.ref]p4: + // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is + // reference-related to T2 and cv1 is the same cv-qualification + // as, or greater cv-qualification than, cv2. For purposes of + // overload resolution, cases for which cv1 is greater + // cv-qualification than cv2 are identified as + // reference-compatible with added qualification (see 13.3.3.2). + if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) + return Ref_Compatible; + else if (T1.isMoreQualifiedThan(T2)) + return Ref_Compatible_With_Added_Qualification; + else + return Ref_Related; +} + +/// \brief Compute an implicit conversion sequence for reference +/// initialization. +static ImplicitConversionSequence +TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, + SourceLocation DeclLoc, + bool SuppressUserConversions, + bool AllowExplicit) { + assert(DeclType->isReferenceType() && "Reference init needs a reference"); + + // Most paths end in a failed conversion. + ImplicitConversionSequence ICS; + ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType); + + QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType(); + QualType T2 = Init->getType(); + + // If the initializer is the address of an overloaded function, try + // to resolve the overloaded function. If all goes well, T2 is the + // type of the resulting function. + if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + DeclAccessPair Found; + if (FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Init, DeclType, + false, Found)) + T2 = Fn->getType(); + } + + // Compute some basic properties of the types and the initializer. + bool isRValRef = DeclType->isRValueReferenceType(); + bool DerivedToBase = false; + Expr::isLvalueResult InitLvalue = Init->isLvalue(S.Context); + Sema::ReferenceCompareResult RefRelationship + = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); + + + // C++ [over.ics.ref]p3: + // Except for an implicit object parameter, for which see 13.3.1, + // a standard conversion sequence cannot be formed if it requires + // binding an lvalue reference to non-const to an rvalue or + // binding an rvalue reference to an lvalue. + // + // FIXME: DPG doesn't trust this code. It seems far too early to + // abort because of a binding of an rvalue reference to an lvalue. + if (isRValRef && InitLvalue == Expr::LV_Valid) + return ICS; + + // C++0x [dcl.init.ref]p16: + // A reference to type "cv1 T1" is initialized by an expression + // of type "cv2 T2" as follows: + + // -- If the initializer expression + // -- is an lvalue (but is not a bit-field), and "cv1 T1" is + // reference-compatible with "cv2 T2," or + // + // Per C++ [over.ics.ref]p4, we don't check the bit-field property here. + if (InitLvalue == Expr::LV_Valid && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // C++ [over.ics.ref]p1: + // When a parameter of reference type binds directly (8.5.3) + // to an argument expression, the implicit conversion sequence + // is the identity conversion, unless the argument expression + // has a type that is a derived class of the parameter type, + // in which case the implicit conversion sequence is a + // derived-to-base Conversion (13.3.3.1). + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = true; + ICS.Standard.RRefBinding = false; + ICS.Standard.CopyConstructor = 0; + + // Nothing more to do: the inaccessibility/ambiguity check for + // derived-to-base conversions is suppressed when we're + // computing the implicit conversion sequence (C++ + // [over.best.ics]p2). + return ICS; + } + + // -- has a class type (i.e., T2 is a class type), where T1 is + // not reference-related to T2, and can be implicitly + // converted to an lvalue of type "cv3 T3," where "cv1 T1" + // is reference-compatible with "cv3 T3" 92) (this + // conversion is selected by enumerating the applicable + // conversion functions (13.3.1.6) and choosing the best + // one through overload resolution (13.3)), + if (!isRValRef && !SuppressUserConversions && T2->isRecordType() && + !S.RequireCompleteType(DeclLoc, T2, 0) && + RefRelationship == Sema::Ref_Incompatible) { + CXXRecordDecl *T2RecordDecl + = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); + + OverloadCandidateSet CandidateSet(DeclLoc); + const UnresolvedSetImpl *Conversions + = T2RecordDecl->getVisibleConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { + NamedDecl *D = *I; + CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + FunctionTemplateDecl *ConvTemplate + = dyn_cast<FunctionTemplateDecl>(D); + CXXConversionDecl *Conv; + if (ConvTemplate) + Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl()); + else + Conv = cast<CXXConversionDecl>(D); + + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. + if (Conv->getConversionType()->isLValueReferenceType() && + (AllowExplicit || !Conv->isExplicit())) { + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, + Init, DeclType, CandidateSet); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, + DeclType, CandidateSet); + } + } + + OverloadCandidateSet::iterator Best; + switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + case OR_Success: + // C++ [over.ics.ref]p1: + // + // [...] If the parameter binds directly to the result of + // applying a conversion function to the argument + // expression, the implicit conversion sequence is a + // user-defined conversion sequence (13.3.3.1.2), with the + // second standard conversion sequence either an identity + // conversion or, if the conversion function returns an + // entity of a type that is a derived class of the parameter + // type, a derived-to-base Conversion. + if (!Best->FinalConversion.DirectBinding) + break; + + ICS.setUserDefined(); + ICS.UserDefined.Before = Best->Conversions[0].Standard; + ICS.UserDefined.After = Best->FinalConversion; + ICS.UserDefined.ConversionFunction = Best->Function; + ICS.UserDefined.EllipsisConversion = false; + assert(ICS.UserDefined.After.ReferenceBinding && + ICS.UserDefined.After.DirectBinding && + "Expected a direct reference binding!"); + return ICS; + + case OR_Ambiguous: + ICS.setAmbiguous(); + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); + Cand != CandidateSet.end(); ++Cand) + if (Cand->Viable) + ICS.Ambiguous.addConversion(Cand->Function); + return ICS; + + case OR_No_Viable_Function: + case OR_Deleted: + // There was no suitable conversion, or we found a deleted + // conversion; continue with other checks. + break; + } + } + + // -- Otherwise, the reference shall be to a non-volatile const + // type (i.e., cv1 shall be const), or the reference shall be an + // rvalue reference and the initializer expression shall be an rvalue. + // + // We actually handle one oddity of C++ [over.ics.ref] at this + // point, which is that, due to p2 (which short-circuits reference + // binding by only attempting a simple conversion for non-direct + // bindings) and p3's strange wording, we allow a const volatile + // reference to bind to an rvalue. Hence the check for the presence + // of "const" rather than checking for "const" being the only + // qualifier. + if (!isRValRef && !T1.isConstQualified()) + return ICS; + + // -- if T2 is a class type and + // -- the initializer expression is an rvalue and "cv1 T1" + // is reference-compatible with "cv2 T2," or + // + // -- T1 is not reference-related to T2 and the initializer + // expression can be implicitly converted to an rvalue + // of type "cv3 T3" (this conversion is selected by + // enumerating the applicable conversion functions + // (13.3.1.6) and choosing the best one through overload + // resolution (13.3)), + // + // then the reference is bound to the initializer + // expression rvalue in the first case and to the object + // that is the result of the conversion in the second case + // (or, in either case, to the appropriate base class + // subobject of the object). + // + // We're only checking the first case here, which is a direct + // binding in C++0x but not in C++03. + if (InitLvalue != Expr::LV_Valid && T2->isRecordType() && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; + ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.CopyConstructor = 0; + return ICS; + } + + // -- Otherwise, a temporary of type "cv1 T1" is created and + // initialized from the initializer expression using the + // rules for a non-reference copy initialization (8.5). The + // reference is then bound to the temporary. If T1 is + // reference-related to T2, cv1 must be the same + // cv-qualification as, or greater cv-qualification than, + // cv2; otherwise, the program is ill-formed. + if (RefRelationship == Sema::Ref_Related) { + // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then + // we would be reference-compatible or reference-compatible with + // added qualification. But that wasn't the case, so the reference + // initialization fails. + return ICS; + } + + // If at least one of the types is a class type, the types are not + // related, and we aren't allowed any user conversions, the + // reference binding fails. This case is important for breaking + // recursion, since TryImplicitConversion below will attempt to + // create a temporary through the use of a copy constructor. + if (SuppressUserConversions && RefRelationship == Sema::Ref_Incompatible && + (T1->isRecordType() || T2->isRecordType())) + return ICS; + + // C++ [over.ics.ref]p2: + // When a parameter of reference type is not bound directly to + // an argument expression, the conversion sequence is the one + // required to convert the argument expression to the + // underlying type of the reference according to + // 13.3.3.1. Conceptually, this conversion sequence corresponds + // to copy-initializing a temporary of the underlying type with + // the argument expression. Any difference in top-level + // cv-qualification is subsumed by the initialization itself + // and does not constitute a conversion. + ICS = S.TryImplicitConversion(Init, T1, SuppressUserConversions, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false); + + // Of course, that's still a reference binding. + if (ICS.isStandard()) { + ICS.Standard.ReferenceBinding = true; + ICS.Standard.RRefBinding = isRValRef; + } else if (ICS.isUserDefined()) { + ICS.UserDefined.After.ReferenceBinding = true; + ICS.UserDefined.After.RRefBinding = isRValRef; + } + return ICS; +} + /// TryCopyInitialization - Try to copy-initialize a value of type /// ToType from the expression From. Return the implicit conversion /// sequence required to pass this argument, which may be a bad /// conversion sequence (meaning that the argument cannot be passed to /// a parameter of this type). If @p SuppressUserConversions, then we -/// do not permit any user-defined conversion sequences. If @p ForceRValue, -/// then we treat @p From as an rvalue, even if it is an lvalue. -ImplicitConversionSequence -Sema::TryCopyInitialization(Expr *From, QualType ToType, - bool SuppressUserConversions, bool ForceRValue, - bool InOverloadResolution) { - if (ToType->isReferenceType()) { - ImplicitConversionSequence ICS; - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - CheckReferenceInit(From, ToType, - /*FIXME:*/From->getLocStart(), - SuppressUserConversions, - /*AllowExplicit=*/false, - ForceRValue, - &ICS); - return ICS; - } else { - return TryImplicitConversion(From, ToType, +/// do not permit any user-defined conversion sequences. +static ImplicitConversionSequence +TryCopyInitialization(Sema &S, Expr *From, QualType ToType, + bool SuppressUserConversions, + bool InOverloadResolution) { + if (ToType->isReferenceType()) + return TryReferenceInit(S, From, ToType, + /*FIXME:*/From->getLocStart(), + SuppressUserConversions, + /*AllowExplicit=*/false); + + return S.TryImplicitConversion(From, ToType, SuppressUserConversions, /*AllowExplicit=*/false, - ForceRValue, InOverloadResolution); - } } /// TryObjectArgumentInitialization - Try to initialize the object @@ -2310,7 +2717,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, if (!Context.hasSameType(From->getType(), DestType)) ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, - /*isLvalue=*/!From->getType()->getAs<PointerType>()); + /*isLvalue=*/!From->getType()->isPointerType()); return false; } @@ -2321,7 +2728,6 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); } @@ -2343,9 +2749,6 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// candidate functions, using the given function call arguments. If /// @p SuppressUserConversions, then don't allow user-defined /// conversions via constructors or conversion operators. -/// If @p ForceRValue, treat all arguments as rvalues. This is a slightly -/// hacky way to implement the overloading rules for elidable copy -/// initialization in C++0x (C++0x 12.8p15). /// /// \para PartialOverloading true if we are performing "partial" overloading /// based on an incomplete set of function arguments. This feature is used by @@ -2356,7 +2759,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, - bool ForceRValue, bool PartialOverloading) { const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>()); @@ -2375,7 +2777,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // is irrelevant. AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Args, NumArgs, CandidateSet, - SuppressUserConversions, ForceRValue); + SuppressUserConversions); return; } // We treat a constructor like a non-member function, since its object @@ -2445,8 +2847,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx].isBad()) { Candidate.Viable = false; @@ -2504,7 +2906,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, bool ForceRValue) { + bool SuppressUserConversions) { NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); @@ -2518,12 +2920,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, /*ExplicitArgs*/ 0, ObjectType, Args, NumArgs, CandidateSet, - SuppressUserConversions, - ForceRValue); + SuppressUserConversions); } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions, ForceRValue); + CandidateSet, SuppressUserConversions); } } @@ -2533,15 +2934,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, /// @c o.f(a1,a2), @c Object will contain @c o and @c Args will contain /// both @c a1 and @c a2. If @p SuppressUserConversions, then don't /// allow user-defined conversions via constructors or conversion -/// operators. If @p ForceRValue, treat all arguments as rvalues. This is -/// a slightly hacky way to implement the overloading rules for elidable copy -/// initialization in C++0x (C++0x 12.8p15). +/// operators. void Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, bool ForceRValue) { + bool SuppressUserConversions) { const FunctionProtoType* Proto = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>()); assert(Proto && "Methods without a prototype cannot be overloaded"); @@ -2614,8 +3013,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, - SuppressUserConversions, ForceRValue, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, + SuppressUserConversions, /*InOverloadResolution=*/true); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -2642,8 +3041,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool ForceRValue) { + bool SuppressUserConversions) { if (!CandidateSet.isNewCandidate(MethodTmpl)) return; @@ -2674,7 +3072,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, "Specialization is not a member function?"); AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, Args, NumArgs, - CandidateSet, SuppressUserConversions, ForceRValue); + CandidateSet, SuppressUserConversions); } /// \brief Add a C++ function template specialization as a candidate @@ -2686,8 +3084,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions, - bool ForceRValue) { + bool SuppressUserConversions) { if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; @@ -2724,7 +3121,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet, - SuppressUserConversions, ForceRValue); + SuppressUserConversions); } /// AddConversionCandidate - Add a C++ conversion function as a @@ -2741,7 +3138,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, OverloadCandidateSet& CandidateSet) { assert(!Conversion->getDescribedFunctionTemplate() && "Conversion function templates use AddTemplateConversionCandidate"); - + QualType ConvType = Conversion->getConversionType().getNonReferenceType(); if (!CandidateSet.isNewCandidate(Conversion)) return; @@ -2756,7 +3153,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); - Candidate.FinalConversion.setFromType(Conversion->getConversionType()); + Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); // Determine the implicit conversion sequence for the implicit @@ -2789,7 +3186,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, return; } - // To determine what the conversion from the result of calling the // conversion function to the type we're eventually trying to // convert to (ToType), we need to synthesize a call to the @@ -2802,7 +3198,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, From->getLocStart()); ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), CastExpr::CK_FunctionToPointerDecay, - &ConversionRef, false); + &ConversionRef, CXXBaseSpecifierArray(), false); // Note that it is safe to allocate CallExpr on the stack here because // there are 0 arguments (i.e., nothing is allocated using ASTContext's @@ -2811,14 +3207,24 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Conversion->getConversionType().getNonReferenceType(), From->getLocStart()); ImplicitConversionSequence ICS = - TryCopyInitialization(&Call, ToType, + TryCopyInitialization(*this, &Call, ToType, /*SuppressUserConversions=*/true, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; + + // C++ [over.ics.user]p3: + // If the user-defined conversion is specified by a specialization of a + // conversion function template, the second standard conversion sequence + // shall have exact match rank. + if (Conversion->getPrimaryTemplate() && + GetConversionRank(ICS.Standard.Second) != ICR_Exact_Match) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_final_conversion_not_exact; + } + break; case ImplicitConversionSequence::BadConversion: @@ -2948,9 +3354,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // parameter of F. QualType ParamType = Proto->getArgType(ArgIdx); Candidate.Conversions[ArgIdx + 1] - = TryCopyInitialization(Args[ArgIdx], ParamType, + = TryCopyInitialization(*this, Args[ArgIdx], ParamType, /*SuppressUserConversions=*/false, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); if (Candidate.Conversions[ArgIdx + 1].isBad()) { Candidate.Viable = false; @@ -2966,31 +3371,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } -// FIXME: This will eventually be removed, once we've migrated all of the -// operator overloading logic over to the scheme used by binary operators, which -// works for template instantiation. -void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange) { - UnresolvedSet<16> Fns; - - QualType T1 = Args[0]->getType(); - QualType T2; - if (NumArgs > 1) - T2 = Args[1]->getType(); - - DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); - if (S) - LookupOverloadedOperatorName(Op, S, T1, T2, Fns); - AddFunctionCandidates(Fns, Args, NumArgs, CandidateSet, false); - AddArgumentDependentLookupCandidates(OpName, false, Args, NumArgs, 0, - CandidateSet); - AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange); - AddBuiltinOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet); -} - /// \brief Add overload candidates for overloaded operators that are /// member functions. /// @@ -3092,9 +3472,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]); } else { Candidate.Conversions[ArgIdx] - = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], + = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx], ArgIdx == 0 && IsAssignmentOperator, - /*ForceRValue=*/false, /*InOverloadResolution=*/false); } if (Candidate.Conversions[ArgIdx].isBad()) { @@ -3362,7 +3741,7 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { const RecordType *TyRec; if (const MemberPointerType *RHSMPType = ArgExpr->getType()->getAs<MemberPointerType>()) - TyRec = cast<RecordType>(RHSMPType->getClass()); + TyRec = RHSMPType->getClass()->getAs<RecordType>(); else TyRec = ArgExpr->getType()->getAs<RecordType>(); if (!TyRec) { @@ -4161,7 +4540,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, continue; AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, - false, false, PartialOverloading); + false, PartialOverloading); } else AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, @@ -4628,6 +5007,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: + case ovl_fail_final_conversion_not_exact: return S.NoteOverloadCandidate(Fn); case ovl_fail_bad_conversion: { @@ -4823,10 +5203,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(!Cand->Conversions[ConvIdx].isInitialized() && "remaining conversion is initialized?"); - // FIXME: these should probably be preserved from the overload + // FIXME: this should probably be preserved from the overload // operation somehow. bool SuppressUserConversions = false; - bool ForceRValue = false; const FunctionProtoType* Proto; unsigned ArgIdx = ConvIdx; @@ -4848,10 +5227,10 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(ConvCount <= 3); for (; ConvIdx != ConvCount; ++ConvIdx) Cand->Conversions[ConvIdx] - = S.TryCopyInitialization(Args[ConvIdx], - Cand->BuiltinTypes.ParamTypes[ConvIdx], - SuppressUserConversions, ForceRValue, - /*InOverloadResolution*/ true); + = TryCopyInitialization(S, Args[ConvIdx], + Cand->BuiltinTypes.ParamTypes[ConvIdx], + SuppressUserConversions, + /*InOverloadResolution*/ true); return; } @@ -4860,9 +5239,9 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { if (ArgIdx < NumArgsInProto) Cand->Conversions[ConvIdx] - = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx), - SuppressUserConversions, ForceRValue, - /*InOverloadResolution=*/true); + = TryCopyInitialization(S, Args[ArgIdx], Proto->getArgType(ArgIdx), + SuppressUserConversions, + /*InOverloadResolution=*/true); else Cand->Conversions[ConvIdx].setEllipsis(); } @@ -4966,15 +5345,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, IsMember = true; } - // We only look at pointers or references to functions. - FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); - if (!FunctionType->isFunctionType()) - return 0; - - // Find the actual overloaded function declaration. - if (From->getType() != Context.OverloadTy) - return 0; - // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] @@ -4987,6 +5357,18 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); ExplicitTemplateArgs = &ETABuffer; } + + // We expect a pointer or reference to function, or a function pointer. + FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); + if (!FunctionType->isFunctionType()) { + if (Complain) + Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref) + << OvlExpr->getName() << ToType; + + return 0; + } + + assert(From->getType() == Context.OverloadTy); // Look through all of the overloaded functions, searching for one // whose type matches exactly. @@ -5068,9 +5450,19 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // If there were 0 or 1 matches, we're done. - if (Matches.empty()) + if (Matches.empty()) { + if (Complain) { + Diag(From->getLocStart(), diag::err_addr_ovl_no_viable) + << OvlExpr->getName() << FunctionType; + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); + I != E; ++I) + if (FunctionDecl *F = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) + NoteOverloadCandidate(F); + } + return 0; - else if (Matches.size() == 1) { + } else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); @@ -5223,7 +5615,7 @@ static void AddOverloadedCallCandidate(Sema &S, if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { assert(!ExplicitTemplateArgs && "Explicit template arguments?"); S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet, - false, false, PartialOverloading); + false, PartialOverloading); return; } @@ -5310,7 +5702,7 @@ static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn, /// /// Returns true if new candidates were found. static Sema::OwningExprResult -BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, +BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -5332,7 +5724,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); - if (SemaRef.DiagnoseEmptyLookup(/*Scope=*/0, SS, R)) + if (SemaRef.DiagnoseEmptyLookup(S, SS, R)) return Destroy(SemaRef, Fn, Args, NumArgs); assert(!R.empty() && "lookup results empty despite recovery"); @@ -5368,7 +5760,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Expr *Fn, /// resolution. Otherwise, emits diagnostics, deletes all of the /// arguments and Fn, and returns NULL. Sema::OwningExprResult -Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, +Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -5401,7 +5793,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, // AddRecoveryCallCandidates diagnoses the error itself, so we just // bailout out if it fails. if (CandidateSet.empty()) - return BuildRecoveryCallExpr(*this, Fn, ULE, LParenLoc, Args, NumArgs, + return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, CommaLocs, RParenLoc); OverloadCandidateSet::iterator Best; @@ -6003,7 +6395,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemberExpr *MemExpr; CXXMethodDecl *Method = 0; - NamedDecl *FoundDecl = 0; + DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); NestedNameSpecifier *Qualifier = 0; if (isa<MemberExpr>(NakedMemExpr)) { MemExpr = cast<MemberExpr>(NakedMemExpr); @@ -6281,7 +6673,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), - CommaLocs, RParenLoc).release(); + CommaLocs, RParenLoc).result(); } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); @@ -6385,7 +6777,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (CheckFunctionCall(Method, TheCall.get())) return true; - return MaybeBindToTemporary(TheCall.release()).release(); + return MaybeBindToTemporary(TheCall.release()).result(); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> @@ -6486,7 +6878,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, +Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), @@ -6508,7 +6900,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, return new (Context) ImplicitCastExpr(ICE->getType(), ICE->getCastKind(), - SubExpr, + SubExpr, CXXBaseSpecifierArray(), ICE->isLvalueCast()); } @@ -6619,7 +7011,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, } Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, - NamedDecl *Found, + DeclAccessPair Found, FunctionDecl *Fn) { return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index cff4774..5e61111 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -34,7 +34,7 @@ namespace clang { OR_Success, ///< Overload resolution succeeded. OR_No_Viable_Function, ///< No viable function found. OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Overload resoltuion refers to a deleted function. + OR_Deleted ///< Succeeded, but refers to a deleted function. }; /// ImplicitConversionKind - The kind of implicit conversion used to @@ -381,6 +381,33 @@ namespace clang { assert(isInitialized() && "querying uninitialized conversion"); return Kind(ConversionKind); } + + /// \brief Return a ranking of the implicit conversion sequence + /// kind, where smaller ranks represent better conversion + /// sequences. + /// + /// In particular, this routine gives user-defined conversion + /// sequences and ambiguous conversion sequences the same rank, + /// per C++ [over.best.ics]p10. + unsigned getKindRank() const { + switch (getKind()) { + case StandardConversion: + return 0; + + case UserDefinedConversion: + case AmbiguousConversion: + return 1; + + case EllipsisConversion: + return 2; + + case BadConversion: + return 3; + } + + return 3; + } + bool isBad() const { return getKind() == BadConversion; } bool isStandard() const { return getKind() == StandardConversion; } bool isEllipsis() const { return getKind() == EllipsisConversion; } @@ -440,7 +467,11 @@ namespace clang { /// This conversion candidate is not viable because its result /// type is not implicitly convertible to the desired type. - ovl_fail_bad_final_conversion + ovl_fail_bad_final_conversion, + + /// This conversion function template specialization candidate is not + /// viable because the final conversion was not an exact match. + ovl_fail_final_conversion_not_exact }; /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 791de8c..9d6132d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/STLExtras.h" @@ -125,7 +126,27 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; return; } + } else if (const CXXFunctionalCastExpr *FC + = dyn_cast<CXXFunctionalCastExpr>(E)) { + if (isa<CXXConstructExpr>(FC->getSubExpr()) || + isa<CXXTemporaryObjectExpr>(FC->getSubExpr())) + return; + } + // Diagnose "(void*) blah" as a typo for "(void) blah". + else if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E)) { + TypeSourceInfo *TI = CE->getTypeInfoAsWritten(); + QualType T = TI->getType(); + + // We really do want to use the non-canonical type here. + if (T == Context.VoidPtrTy) { + PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc()); + + Diag(Loc, diag::warn_unused_voidptr) + << FixItHint::CreateRemoval(TL.getStarLoc()); + return; + } } + Diag(Loc, DiagID) << R1 << R2; } @@ -572,7 +593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, return StmtError(); } - if (CondTypeBeforePromotion->isBooleanType()) { + if (CondExpr->isKnownToHaveBooleanValue()) { // switch(bool_expr) {...} is often a programmer error, e.g. // switch(n && mask) { ... } // Doh - should be "n & mask". // One can always use an if statement instead of switch(bool_expr). @@ -967,19 +988,22 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, return StmtError(Diag(VD->getLocation(), diag::err_non_variable_decl_in_for)); } else { - if (cast<Expr>(First)->isLvalue(Context) != Expr::LV_Valid) + Expr *FirstE = cast<Expr>(First); + if (!FirstE->isTypeDependent() && + FirstE->isLvalue(Context) != Expr::LV_Valid) return StmtError(Diag(First->getLocStart(), diag::err_selector_element_not_lvalue) << First->getSourceRange()); FirstType = static_cast<Expr*>(First)->getType(); } - if (!FirstType->isObjCObjectPointerType() && + if (!FirstType->isDependentType() && + !FirstType->isObjCObjectPointerType() && !FirstType->isBlockPointerType()) Diag(ForLoc, diag::err_selector_element_type) << FirstType << First->getSourceRange(); } - if (Second) { + if (Second && !Second->isTypeDependent()) { DefaultFunctionArrayLvalueConversion(Second); QualType SecondType = Second->getType(); if (!SecondType->isObjCObjectPointerType()) @@ -1422,53 +1446,72 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, if (Context.hasSameType(InTy, OutTy)) continue; // All types can be tied to themselves. - // Int/ptr operands have some special cases that we allow. - if ((OutTy->isIntegerType() || OutTy->isPointerType()) && - (InTy->isIntegerType() || InTy->isPointerType())) { - - // They are ok if they are the same size. Tying void* to int is ok if - // they are the same size, for example. This also allows tying void* to - // int*. - uint64_t OutSize = Context.getTypeSize(OutTy); - uint64_t InSize = Context.getTypeSize(InTy); - if (OutSize == InSize) - continue; - - // If the smaller input/output operand is not mentioned in the asm string, - // then we can promote it and the asm string won't notice. Check this - // case now. - bool SmallerValueMentioned = false; - for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { - AsmStmt::AsmStringPiece &Piece = Pieces[p]; - if (!Piece.isOperand()) continue; - - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (Piece.getOperandNo() == i+NumOutputs) { - if (InSize < OutSize) { - SmallerValueMentioned = true; - break; - } - } + // Decide if the input and output are in the same domain (integer/ptr or + // floating point. + enum AsmDomain { + AD_Int, AD_FP, AD_Other + } InputDomain, OutputDomain; + + if (InTy->isIntegerType() || InTy->isPointerType()) + InputDomain = AD_Int; + else if (InTy->isFloatingType()) + InputDomain = AD_FP; + else + InputDomain = AD_Other; - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (Piece.getOperandNo() == TiedTo) { - if (InSize > OutSize) { - SmallerValueMentioned = true; - break; - } + if (OutTy->isIntegerType() || OutTy->isPointerType()) + OutputDomain = AD_Int; + else if (OutTy->isFloatingType()) + OutputDomain = AD_FP; + else + OutputDomain = AD_Other; + + // They are ok if they are the same size and in the same domain. This + // allows tying things like: + // void* to int* + // void* to int if they are the same size. + // double to long double if they are the same size. + // + uint64_t OutSize = Context.getTypeSize(OutTy); + uint64_t InSize = Context.getTypeSize(InTy); + if (OutSize == InSize && InputDomain == OutputDomain && + InputDomain != AD_Other) + continue; + + // If the smaller input/output operand is not mentioned in the asm string, + // then we can promote it and the asm string won't notice. Check this + // case now. + bool SmallerValueMentioned = false; + for (unsigned p = 0, e = Pieces.size(); p != e; ++p) { + AsmStmt::AsmStringPiece &Piece = Pieces[p]; + if (!Piece.isOperand()) continue; + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == i+NumOutputs) { + if (InSize < OutSize) { + SmallerValueMentioned = true; + break; } } - // If the smaller value wasn't mentioned in the asm string, and if the - // output was a register, just extend the shorter one to the size of the - // larger one. - if (!SmallerValueMentioned && - OutputConstraintInfos[TiedTo].allowsRegister()) - continue; + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == TiedTo) { + if (InSize > OutSize) { + SmallerValueMentioned = true; + break; + } + } } + // If the smaller value wasn't mentioned in the asm string, and if the + // output was a register, just extend the shorter one to the size of the + // larger one. + if (!SmallerValueMentioned && InputDomain != AD_Other && + OutputConstraintInfos[TiedTo].allowsRegister()) + continue; + Diag(InputExpr->getLocStart(), diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() @@ -1483,27 +1526,13 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, Action::OwningStmtResult Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, DeclPtrTy Parm, - StmtArg Body, StmtArg catchList) { - Stmt *CatchList = catchList.takeAs<Stmt>(); - ParmVarDecl *PVD = cast_or_null<ParmVarDecl>(Parm.getAs<Decl>()); - - // PVD == 0 implies @catch(...). - if (PVD) { - // If we already know the decl is invalid, reject it. - if (PVD->isInvalidDecl()) - return StmtError(); - - if (!PVD->getType()->isObjCObjectPointerType()) - return StmtError(Diag(PVD->getLocation(), - diag::err_catch_param_not_objc_type)); - if (PVD->getType()->isObjCQualifiedIdType()) - return StmtError(Diag(PVD->getLocation(), - diag::err_illegal_qualifiers_on_catch_parm)); - } - - ObjCAtCatchStmt *CS = new (Context) ObjCAtCatchStmt(AtLoc, RParen, - PVD, Body.takeAs<Stmt>(), CatchList); - return Owned(CatchList ? CatchList : CS); + StmtArg Body) { + VarDecl *Var = cast_or_null<VarDecl>(Parm.getAs<Decl>()); + if (Var && Var->isInvalidDecl()) + return StmtError(); + + return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, + Body.takeAs<Stmt>())); } Action::OwningStmtResult @@ -1513,18 +1542,38 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { } Action::OwningStmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, StmtArg Catch, StmtArg Finally) { +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, + MultiStmtArg CatchStmts, StmtArg Finally) { FunctionNeedsScopeChecking() = true; - return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(), - Catch.takeAs<Stmt>(), - Finally.takeAs<Stmt>())); + unsigned NumCatchStmts = CatchStmts.size(); + return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(), + (Stmt **)CatchStmts.release(), + NumCatchStmts, + Finally.takeAs<Stmt>())); +} + +Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg ThrowE) { + Expr *Throw = static_cast<Expr *>(ThrowE.get()); + if (Throw) { + QualType ThrowType = Throw->getType(); + // Make sure the expression type is an ObjC pointer or "void *". + if (!ThrowType->isDependentType() && + !ThrowType->isObjCObjectPointerType()) { + const PointerType *PT = ThrowType->getAs<PointerType>(); + if (!PT || !PT->getPointeeType()->isVoidType()) + return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) + << Throw->getType() << Throw->getSourceRange()); + } + } + + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>())); } Action::OwningStmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { - Expr *ThrowExpr = expr.takeAs<Expr>(); - if (!ThrowExpr) { +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, + Scope *CurScope) { + if (!Throw.get()) { // @throw without an expression designates a rethrow (which much occur // in the context of an @catch clause). Scope *AtCatchParent = CurScope; @@ -1532,17 +1581,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); - } else { - QualType ThrowType = ThrowExpr->getType(); - // Make sure the expression type is an ObjC pointer or "void *". - if (!ThrowType->isObjCObjectPointerType()) { - const PointerType *PT = ThrowType->getAs<PointerType>(); - if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) - << ThrowExpr->getType() << ThrowExpr->getSourceRange()); - } - } - return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr)); + } + + return BuildObjCAtThrowStmt(AtLoc, move(Throw)); } Action::OwningStmtResult @@ -1552,7 +1593,8 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, // Make sure the expression type is an ObjC pointer or "void *". Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get()); - if (!SyncExpr->getType()->isObjCObjectPointerType()) { + if (!SyncExpr->getType()->isDependentType() && + !SyncExpr->getType()->isObjCObjectPointerType()) { const PointerType *PT = SyncExpr->getType()->getAs<PointerType>(); if (!PT || !PT->getPointeeType()->isVoidType()) return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 40ec4bcb..694b21c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -63,20 +63,40 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { } static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { + // The set of class templates we've already seen. + llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl()); if (!Repl) filter.erase(); - else if (Repl != Orig) + else if (Repl != Orig) { + + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in an + // ambiguity in certain cases (for example, if it is found in more than + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not + // ambiguous. + // + // FIXME: Will we eventually have to do the same for alias templates? + if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) + if (!ClassTemplates.insert(ClassTmpl)) { + filter.erase(); + continue; + } + filter.replace(Repl); + } } filter.done(); } TemplateNameKind Sema::isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, @@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupOrdinaryName); R.suppressDiagnostics(); LookupTemplateName(R, S, SS, ObjectType, EnteringContext); - if (R.empty()) + if (R.empty() || R.isAmbiguous()) return TNK_Non_template; TemplateName Template; @@ -169,7 +189,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, } void Sema::LookupTemplateName(LookupResult &Found, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext) { // Determine where to perform name lookup @@ -190,7 +210,7 @@ void Sema::LookupTemplateName(LookupResult &Found, isDependent = isDependentScopeSpecifier(SS); // The declaration context must be complete. - if (LookupCtx && RequireCompleteDeclContext(SS)) + if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return; } @@ -227,14 +247,11 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupName(Found, S); } - // FIXME: Cope with ambiguous name-lookup results. - assert(!Found.isAmbiguous() && - "Cannot handle template name-lookup ambiguities"); - if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (CorrectTypo(Found, S, &SS, LookupCtx)) { + if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, + false, CTC_CXXCasts)) { FilterAcceptableTemplateNames(Context, Found); if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) { if (LookupCtx) @@ -271,8 +288,7 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupOrdinaryName); LookupName(FoundOuter, S); FilterAcceptableTemplateNames(Context, FoundOuter); - // FIXME: Handle ambiguities in this lookup better - + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise @@ -439,7 +455,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, bool Invalid = false; if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc, + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, PrevDecl); @@ -560,7 +578,9 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdentifierInfo *ParamName = D.getIdentifier(); if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -705,7 +725,7 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { Sema::DeclResult Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, @@ -733,25 +753,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, ForRedeclaration); if (SS.isNotEmpty() && !SS.isInvalid()) { - if (RequireCompleteDeclContext(SS)) - return true; - SemanticContext = computeDeclContext(SS, true); if (!SemanticContext) { // FIXME: Produce a reasonable diagnostic here return true; } + if (RequireCompleteDeclContext(SS, SemanticContext)) + return true; + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; LookupName(Previous, S); } - assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); + if (Previous.isAmbiguous()) + return true; + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) - PrevDecl = *Previous.begin(); + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. @@ -779,22 +801,24 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // declared as a friend, and when the name of the friend class or // function is neither a qualified name nor a template-id, scopes outside // the innermost enclosing namespace scope are not considered. - DeclContext *OutermostContext = CurContext; - while (!OutermostContext->isFileContext()) - OutermostContext = OutermostContext->getLookupParent(); - - if (PrevDecl && - (OutermostContext->Equals(PrevDecl->getDeclContext()) || - OutermostContext->Encloses(PrevDecl->getDeclContext()))) { - SemanticContext = PrevDecl->getDeclContext(); - } else { - // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semantic context for our new - // declaration. - PrevDecl = PrevClassTemplate = 0; - SemanticContext = OutermostContext; + if (!SS.isSet()) { + DeclContext *OutermostContext = CurContext; + while (!OutermostContext->isFileContext()) + OutermostContext = OutermostContext->getLookupParent(); + + if (PrevDecl && + (OutermostContext->Equals(PrevDecl->getDeclContext()) || + OutermostContext->Encloses(PrevDecl->getDeclContext()))) { + SemanticContext = PrevDecl->getDeclContext(); + } else { + // Declarations in outer scopes don't matter. However, the outermost + // context we computed is the semantic context for our new + // declaration. + PrevDecl = PrevClassTemplate = 0; + SemanticContext = OutermostContext; + } } - + if (CurContext->isDependentContext()) { // If this is a dependent context, we don't want to link the friend // class template to the template in scope, because that would perform @@ -804,7 +828,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -861,9 +885,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, TPC_ClassTemplate)) Invalid = true; - // FIXME: If we had a scope specifier, we better have a previous template - // declaration! - + if (SS.isSet()) { + // If the name of the template was qualified, we must be defining the + // template out-of-line. + if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && + !(TUK == TUK_Friend && CurContext->isDependentContext())) + Diag(NameLoc, diag::err_member_def_does_not_match) + << Name << SemanticContext << SS.getRange(); + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -1206,6 +1236,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, /// /// \param NumParamLists the number of template parameter lists in ParamLists. /// +/// \param IsFriend Whether to apply the slightly different rules for +/// matching template parameters to scope specifiers in friend +/// declarations. +/// /// \param IsExplicitSpecialization will be set true if the entity being /// declared is an explicit specialization, false otherwise. /// @@ -1220,6 +1254,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization) { IsExplicitSpecialization = false; @@ -1285,6 +1320,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (Idx >= NumParamLists) { // We have a template-id without a corresponding template parameter // list. + + // ...which is fine if this is a friend declaration. + if (IsFriend) { + IsExplicitSpecialization = true; + break; + } + if (DependentTemplateId) { // FIXME: the location information here isn't great. Diag(SS.getRange().getBegin(), @@ -1302,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // Check the template parameter list against its corresponding template-id. if (DependentTemplateId) { - TemplateDecl *Template - = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); - - if (ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>(Template)) { - TemplateParameterList *ExpectedTemplateParams = 0; - // Is this template-id naming the primary template? - if (Context.hasSameType(TemplateId, - ClassTemplate->getInjectedClassNameSpecialization(Context))) - ExpectedTemplateParams = ClassTemplate->getTemplateParameters(); - // ... or a partial specialization? - else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(TemplateId)) - ExpectedTemplateParams = PartialSpec->getTemplateParameters(); - - if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[Idx], - ExpectedTemplateParams, - true, TPL_TemplateMatch); + TemplateParameterList *ExpectedTemplateParams = 0; + + // Are there cases in (e.g.) friends where this won't match? + if (const InjectedClassNameType *Injected + = TemplateId->getAs<InjectedClassNameType>()) { + CXXRecordDecl *Record = Injected->getDecl(); + if (ClassTemplatePartialSpecializationDecl *Partial = + dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) + ExpectedTemplateParams = Partial->getTemplateParameters(); + else + ExpectedTemplateParams = Record->getDescribedClassTemplate() + ->getTemplateParameters(); } + if (ExpectedTemplateParams) + TemplateParameterListsAreEqual(ParamLists[Idx], + ExpectedTemplateParams, + true, TPL_TemplateMatch); + CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember); } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), @@ -1388,6 +1428,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, "Converted template argument list is too short!"); QualType CanonType; + bool IsCurrentInstantiation = false; if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( @@ -1409,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // In the future, we need to teach getTemplateSpecializationType to only // build the canonical type and return that to us. CanonType = Context.getCanonicalType(CanonType); + + // This might work out to be a current instantiation, in which + // case the canonical type needs to be the InjectedClassNameType. + // + // TODO: in theory this could be a simple hashtable lookup; most + // changes to CurContext don't change the set of current + // instantiations. + if (isa<ClassTemplateDecl>(Template)) { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { + // If we get out to a namespace, we're done. + if (Ctx->isFileContext()) break; + + // If this isn't a record, keep looking. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) continue; + + // Look for one of the two cases with InjectedClassNameTypes + // and check whether it's the same template. + if (!isa<ClassTemplatePartialSpecializationDecl>(Record) && + !Record->getDescribedClassTemplate()) + continue; + + // Fetch the injected class name type and check whether its + // injected type is equal to the type we just built. + QualType ICNT = Context.getTypeDeclType(Record); + QualType Injected = cast<InjectedClassNameType>(ICNT) + ->getInjectedSpecializationType(); + + if (CanonType != Injected->getCanonicalTypeInternal()) + continue; + + // If so, the canonical type of this TST is the injected + // class name type of the record we just found. + assert(ICNT.isCanonical()); + CanonType = ICNT; + IsCurrentInstantiation = true; + break; + } + } } else if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that @@ -1442,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType, + IsCurrentInstantiation); } Action::TypeResult @@ -1545,14 +1626,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // We actually only call this from template instantiation. Sema::OwningExprResult -Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, +Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &TemplateArgs) { DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext() || - RequireCompleteDeclContext(SS)) + RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); @@ -1586,7 +1667,7 @@ Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, /// of the "template" keyword, and "apply" is the \p Name. Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { @@ -1663,11 +1744,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. - if (Arg.getKind() != TemplateArgument::Type) { + switch(Arg.getKind()) { + case TemplateArgument::Type: // C++ [temp.arg.type]p1: // A template-argument for a template-parameter which is a // type shall be a type-id. + break; + case TemplateArgument::Template: { + // We have a template type parameter but the template argument + // is a template without any arguments. + SourceRange SR = AL.getSourceRange(); + TemplateName Name = Arg.getAsTemplate(); + Diag(SR.getBegin(), diag::err_template_missing_args) + << Name << SR; + if (TemplateDecl *Decl = Name.getAsTemplateDecl()) + Diag(Decl->getLocation(), diag::note_template_decl_here); + return true; + } + default: { // We have a template type parameter but the template argument // is not a type. SourceRange SR = AL.getSourceRange(); @@ -1676,6 +1771,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } + } if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; @@ -2317,14 +2413,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, DRE = dyn_cast<DeclRefExpr>(Arg); if (!DRE) { - if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) { - S.Diag(Arg->getLocStart(), - diag::err_template_arg_unresolved_overloaded_function) - << ParamType << Arg->getSourceRange(); - } else { - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); - } + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -2525,6 +2615,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Create the template argument. Converted = TemplateArgument(Entity->getCanonicalDecl()); + S.MarkDeclarationReferenced(Arg->getLocStart(), Entity); return false; } @@ -2797,16 +2888,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ParamType->getAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + if (!ParamType->isMemberPointerType()) return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, @@ -2851,17 +2945,20 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, - ParamRefType->getPointeeType(), - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); @@ -2964,9 +3061,21 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, return ExprError(); RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + + // We might need to perform a trailing qualification conversion, since + // the element type on the parameter could be more qualified than the + // element type in the expression we constructed. + if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), + ParamType.getUnqualifiedType())) { + Expr *RefE = RefExpr.takeAs<Expr>(); + ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), + CastExpr::CK_NoOp); + RefExpr = Owned(RefE); + } + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), - ParamType)); + ParamType.getUnqualifiedType())); return move(RefExpr); } } @@ -3467,7 +3576,7 @@ Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -3500,6 +3609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization); if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -3683,6 +3793,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); + unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber() + : ClassTemplate->getPartialSpecializations().size(); ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), @@ -3692,7 +3804,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted, TemplateArgs, CanonType, - PrevPartial); + PrevPartial, + SequenceNumber); SetNestedNameSpecifier(Partial, SS); if (PrevPartial) { @@ -4032,7 +4145,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // instantiation has no effect. // // In C++98/03 mode, we only give an extension warning here, because it - // is not not harmful to try to explicitly instantiate something that + // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. if (!getLangOptions().CPlusPlus0x) { Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) @@ -4068,6 +4181,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } +/// \brief Perform semantic analysis for the given dependent function +/// template specialization. The only possible way to get a dependent +/// function template specialization is with a friend declaration, +/// like so: +/// +/// template <class T> void foo(T); +/// template <class T> class A { +/// friend void foo<>(T); +/// }; +/// +/// There really isn't any useful analysis we can do here, so we +/// just store the information. +bool +Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous) { + // Remove anything from Previous that isn't a function template in + // the correct context. + DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next()->getUnderlyingDecl(); + if (!isa<FunctionTemplateDecl>(D) || + !FDLookupContext->Equals(D->getDeclContext()->getLookupContext())) + F.erase(); + } + F.done(); + + // Should this be diagnosed here? + if (Previous.empty()) return true; + + FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(), + ExplicitTemplateArgs); + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -4153,6 +4302,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + Specialization->setLocation(FD->getLocation()); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -4227,7 +4377,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); - + // Try to find the member we are instantiating. NamedDecl *Instantiation = 0; NamedDecl *InstantiatedFrom = 0; @@ -4273,6 +4423,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // this mismatch later. return false; } + + // If this is a friend, just bail out here before we start turning + // things into explicit specializations. + if (Member->getFriendObjectKind() != Decl::FOK_None) { + // Preserve instantiation information. + if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) { + cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), + cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind()); + } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) { + cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), + cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind()); + } + + Previous.clear(); + Previous.addDecl(Instantiation); + return false; + } // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { @@ -4612,7 +4781,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr) { @@ -5001,9 +5170,30 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } assert(Keyword != ETK_None && "Invalid tag kind!"); + if (TUK == TUK_Declaration || TUK == TUK_Definition) { + Diag(NameLoc, diag::err_dependent_tag_decl) + << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) + << SS.getRange(); + return true; + } + return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); } +static void FillTypeLoc(DependentNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + +static void FillTypeLoc(QualifiedNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { @@ -5012,10 +5202,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (!NNS) return true; - QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); + QualType T = CheckTypenameType(ETK_Typename, NNS, II, + SourceRange(TypenameLoc, IdLoc)); if (T.isNull()) return true; - return T.getAsOpaquePtr(); + + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } else { + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } + + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } Sema::TypeResult @@ -5034,48 +5237,49 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, // track of the nested-name-specifier. // FIXME: Note that the QualifiedNameType had the "typename" keyword! - return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); + + T = Context.getQualifiedNameType(NNS, T); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } - return Context.getDependentNameType(ETK_Typename, NNS, TemplateId) - .getAsOpaquePtr(); + T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range) { - CXXRecordDecl *CurrentInstantiation = 0; - if (NNS->isDependent()) { - CurrentInstantiation = getCurrentInstantiationOf(NNS); - - // If the nested-name-specifier does not refer to the current - // instantiation, then build a typename type. - if (!CurrentInstantiation) - return Context.getDependentNameType(ETK_Typename, NNS, &II); - - // The nested-name-specifier refers to the current instantiation, so the - // "typename" keyword itself is superfluous. In C++03, the program is - // actually ill-formed. However, DR 382 (in C++0x CD1) allows such - // extraneous "typename" keywords, and we retroactively apply this DR to - // C++03 code. + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + + DeclContext *Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(NNS->isDependent()); + return Context.getDependentNameType(Keyword, NNS, &II); } - DeclContext *Ctx = 0; + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code. In any case we continue. - if (CurrentInstantiation) - Ctx = CurrentInstantiation; - else { - CXXScopeSpec SS; - SS.setScopeRep(NNS); - SS.setRange(Range); - if (RequireCompleteDeclContext(SS)) - return QualType(); - - Ctx = computeDeclContext(SS); - } - assert(Ctx && "No declaration context?"); + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); DeclarationName Name(&II); LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); @@ -5089,7 +5293,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(ETK_Typename, NNS, &II); + return Context.getDependentNameType(Keyword, NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { @@ -5133,6 +5337,8 @@ namespace { DeclarationName Entity; public: + typedef TreeTransform<CurrentInstantiationRebuilder> inherited; + CurrentInstantiationRebuilder(Sema &SemaRef, SourceLocation Loc, DeclarationName Entity) @@ -5168,7 +5374,7 @@ namespace { /// FIXME: This is completely unsafe; we will need to actually clone the /// expressions. Sema::OwningExprResult TransformExpr(Expr *E) { - return getSema().Owned(E); + return getSema().Owned(E->Retain()); } /// \brief Transforms a typename type by determining whether the type now @@ -5256,15 +5462,30 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, /// in X<T> and returning a QualifiedNameType whose canonical type is the same /// as the canonical type of T*, allowing the return types of the out-of-line /// definition and the declaration to match. -QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, - DeclarationName Name) { - if (T.isNull() || !T->isDependentType()) +TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name) { + if (!T || !T->getType()->isDependentType()) return T; CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name); return Rebuilder.TransformType(T); } +bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { + if (SS.isInvalid()) return true; + + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), + DeclarationName()); + NestedNameSpecifier *Rebuilt = + Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); + if (!Rebuilt) return true; + + SS.setScopeRep(Rebuilt); + return false; +} + /// \brief Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string @@ -5344,8 +5565,15 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } case TemplateArgument::Expression: { - assert(false && "No expressions in deduced template arguments!"); - Result += "<expression>"; + // FIXME: This is non-optimal, since we're regurgitating the + // expression we were given. + std::string Str; + { + llvm::raw_string_ostream OS(Str); + Args[I].getAsExpr()->printPretty(OS, Context, 0, + Context.PrintingPolicy); + } + Result += Str; break; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index d61a767..2bb97eb 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -638,7 +638,8 @@ DeduceTemplateArguments(Sema &S, case Type::InjectedClassName: { // Treat a template's injected-class-name as if the template // specialization type had been used. - Param = cast<InjectedClassNameType>(Param)->getUnderlyingType(); + Param = cast<InjectedClassNameType>(Param) + ->getInjectedSpecializationType(); assert(isa<TemplateSpecializationType>(Param) && "injected class name is not a template specialization type"); // fall through @@ -960,32 +961,18 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); } -/// \brief Perform template argument deduction to determine whether -/// the given template arguments match the given class template -/// partial specialization per C++ [temp.class.spec.match]. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs, - TemplateDeductionInfo &Info) { - // C++ [temp.class.spec.match]p2: - // A partial specialization matches a given actual template - // argument list if the template arguments of the partial - // specialization can be deduced from the actual template argument - // list (14.8.2). - SFINAETrap Trap(*this); - llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; - Deduced.resize(Partial->getTemplateParameters()->size()); - if (TemplateDeductionResult Result - = ::DeduceTemplateArguments(*this, - Partial->getTemplateParameters(), - Partial->getTemplateArgs(), - TemplateArgs, Info, Deduced)) - return Result; - - InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, - Deduced.data(), Deduced.size()); - if (Inst) - return TDK_InstantiationDepth; +/// Complete template argument deduction for a class template partial +/// specialization. +static Sema::TemplateDeductionResult +FinishTemplateArgumentDeduction(Sema &S, + ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, + Sema::TemplateDeductionInfo &Info) { + // Trap errors. + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, Partial); // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor @@ -995,18 +982,19 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { if (Deduced[I].isNull()) { Decl *Param - = const_cast<NamedDecl *>( + = const_cast<NamedDecl *>( Partial->getTemplateParameters()->getParam(I)); Info.Param = makeTemplateParameter(Param); - return TDK_Incomplete; + return Sema::TDK_Incomplete; } - + Builder.Append(Deduced[I]); } - + // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + = new (S.Context) TemplateArgumentList(S.Context, Builder, + /*TakeArgs=*/true); Info.reset(DeducedArgumentList); // Substitute the deduced template arguments into the template @@ -1016,7 +1004,7 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, // to the class template. // FIXME: Do we have to correct the types of deduced non-type template // arguments (in particular, integral non-type template arguments?). - Sema::LocalInstantiationScope InstScope(*this); + Sema::LocalInstantiationScope InstScope(S); ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); const TemplateArgumentLoc *PartialTemplateArgs = Partial->getTemplateArgsAsWritten(); @@ -1029,11 +1017,11 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Decl *Param = const_cast<NamedDecl *>( ClassTemplate->getTemplateParameters()->getParam(I)); TemplateArgumentLoc InstArg; - if (Subst(PartialTemplateArgs[I], InstArg, - MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + if (S.Subst(PartialTemplateArgs[I], InstArg, + MultiLevelTemplateArgumentList(*DeducedArgumentList))) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[I].getArgument(); - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } InstArgs.addArgument(InstArg); } @@ -1041,10 +1029,10 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, TemplateArgumentListBuilder ConvertedInstArgs( ClassTemplate->getTemplateParameters(), N); - if (CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), + if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), InstArgs, false, ConvertedInstArgs)) { // FIXME: fail with more useful information? - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } for (unsigned I = 0, E = ConvertedInstArgs.flatSize(); I != E; ++I) { @@ -1060,26 +1048,60 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Expr *InstExpr = InstArg.getAsExpr(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { + if (S.CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Partial->getTemplateArgs()[I]; - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; } } } - if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) { + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; - return TDK_NonDeducedMismatch; + return Sema::TDK_NonDeducedMismatch; } } if (Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; + return Sema::TDK_SubstitutionFailure; - return TDK_Success; + return Sema::TDK_Success; +} + +/// \brief Perform template argument deduction to determine whether +/// the given template arguments match the given class template +/// partial specialization per C++ [temp.class.spec.match]. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info) { + // C++ [temp.class.spec.match]p2: + // A partial specialization matches a given actual template + // argument list if the template arguments of the partial + // specialization can be deduced from the actual template argument + // list (14.8.2). + SFINAETrap Trap(*this); + llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(*this, + Partial->getTemplateParameters(), + Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) + return Result; + + InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, + Deduced.data(), Deduced.size()); + if (Inst) + return TDK_InstantiationDepth; + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + Deduced, Info); } /// \brief Determine whether the given type T is a simple-template-id type. @@ -1162,6 +1184,8 @@ Sema::SubstituteExplicitTemplateArguments( if (Inst) return TDK_InstantiationDepth; + ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); + if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), ExplicitTemplateArgs, @@ -1310,6 +1334,8 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (Inst) return TDK_InstantiationDepth; + ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); + // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. @@ -1416,9 +1442,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. + DeclContext *Owner = FunctionTemplate->getDeclContext(); + if (FunctionTemplate->getFriendObjectKind()) + Owner = FunctionTemplate->getLexicalDeclContext(); Specialization = cast_or_null<FunctionDecl>( - SubstDecl(FunctionTemplate->getTemplatedDecl(), - FunctionTemplate->getDeclContext(), + SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, MultiLevelTemplateArgumentList(*DeducedArgumentList))); if (!Specialization) return TDK_SubstitutionFailure; @@ -2332,35 +2360,49 @@ Sema::getMoreSpecializedPartialSpecialization( // whose type is a class template specialization with the template // arguments of the second partial specialization. // - // Rather than synthesize function templates, we merely perform the - // equivalent partial ordering by performing deduction directly on the - // template arguments of the class template partial specializations. This - // computation is slightly simpler than the general problem of function - // template partial ordering, because class template partial specializations - // are more constrained. We know that every template parameter is deduc + // Rather than synthesize function templates, we merely perform the + // equivalent partial ordering by performing deduction directly on + // the template arguments of the class template partial + // specializations. This computation is slightly simpler than the + // general problem of function template partial ordering, because + // class template partial specializations are more constrained. We + // know that every template parameter is deducible from the class + // template partial specialization's template arguments, for + // example. llvm::SmallVector<DeducedTemplateArgument, 4> Deduced; Sema::TemplateDeductionInfo Info(Context, Loc); + + QualType PT1 = PS1->getInjectedSpecializationType(); + QualType PT2 = PS2->getInjectedSpecializationType(); // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS2->getTemplateParameters(), - Context.getTypeDeclType(PS2), - Context.getTypeDeclType(PS1), + PT2, + PT1, Info, Deduced, 0); - + if (Better1) + Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, + PS1->getTemplateArgs(), + Deduced, Info); + // Determine whether PS2 is at least as specialized as PS1 Deduced.clear(); Deduced.resize(PS1->getTemplateParameters()->size()); bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this, PS1->getTemplateParameters(), - Context.getTypeDeclType(PS1), - Context.getTypeDeclType(PS2), + PT1, + PT2, Info, Deduced, 0); + if (Better2) + Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, + PS2->getTemplateArgs(), + Deduced, Info); if (Better1 == Better2) return 0; @@ -2537,6 +2579,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, break; } + case Type::InjectedClassName: + T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); + // fall through + case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec = cast<TemplateSpecializationType>(T); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d21862b..14bd243 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -38,10 +38,16 @@ using namespace clang; /// arguments relative to the primary template, even when we're /// dealing with a specialization. This is only relevant for function /// template specializations. +/// +/// \param Pattern If non-NULL, indicates the pattern from which we will be +/// instantiating the definition of the given declaration, \p D. This is +/// used to determine the proper set of template instantiation arguments for +/// friend function template specializations. MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary) { + bool RelativeToPrimary, + const FunctionDecl *Pattern) { // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -89,9 +95,11 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, // If this is a friend declaration and it declares an entity at // namespace scope, take arguments from its lexical parent - // instead of its semantic parent. + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! if (Function->getFriendObjectKind() && - Function->getDeclContext()->isFileContext()) { + Function->getDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { Ctx = Function->getLexicalDeclContext(); RelativeToPrimary = false; continue; @@ -339,12 +347,32 @@ bool Sema::InstantiatingTemplate::CheckInstantiationDepth( /// \brief Prints the current instantiation stack through a series of /// notes. void Sema::PrintInstantiationStack() { + // Determine which template instantiations to skip, if any. + unsigned SkipStart = ActiveTemplateInstantiations.size(), SkipEnd = SkipStart; + unsigned Limit = Diags.getTemplateBacktraceLimit(); + if (Limit && Limit < ActiveTemplateInstantiations.size()) { + SkipStart = Limit / 2 + Limit % 2; + SkipEnd = ActiveTemplateInstantiations.size() - Limit / 2; + } + // FIXME: In all of these cases, we need to show the template arguments + unsigned InstantiationIdx = 0; for (llvm::SmallVector<ActiveTemplateInstantiation, 16>::reverse_iterator Active = ActiveTemplateInstantiations.rbegin(), ActiveEnd = ActiveTemplateInstantiations.rend(); Active != ActiveEnd; - ++Active) { + ++Active, ++InstantiationIdx) { + // Skip this instantiation? + if (InstantiationIdx >= SkipStart && InstantiationIdx < SkipEnd) { + if (InstantiationIdx == SkipStart) { + // Note that we're skipping instantiations. + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_instantiation_contexts_suppressed) + << unsigned(ActiveTemplateInstantiations.size() - Limit); + } + continue; + } + switch (Active->Kind) { case ActiveTemplateInstantiation::TemplateInstantiation: { Decl *D = reinterpret_cast<Decl *>(Active->Entity); @@ -512,8 +540,7 @@ bool Sema::isSFINAEContext() const { // Template Instantiation for Types //===----------------------------------------------------------------------===/ namespace { - class TemplateInstantiator - : public TreeTransform<TemplateInstantiator> { + class TemplateInstantiator : public TreeTransform<TemplateInstantiator> { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; @@ -569,6 +596,11 @@ namespace { IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); + /// \brief Rebuild the Objective-C exception declaration and register the + /// declaration as an instantiated local. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, QualType T); + /// \brief Check for tag mismatches when instantiating an /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); @@ -579,13 +611,9 @@ namespace { Sema::OwningExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); - /// \brief Transforms a function proto type by performing - /// substitution in the function parameters, possibly adjusting - /// their types and marking default arguments as uninstantiated. - bool TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars); - + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm); /// \brief Transforms a template type parameter type by performing @@ -667,7 +695,16 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, SourceRange TypeRange) { VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator, Name, Loc, TypeRange); - if (Var && !Var->isInvalidDecl()) + if (Var) + getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + return Var; +} + +VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, + QualType T) { + VarDecl *Var = inherited::RebuildObjCExceptionDecl(ExceptionDecl, TSInfo, T); + if (Var) getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); return Var; } @@ -791,63 +828,17 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( E->getParam()); } - -bool -TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL, - llvm::SmallVectorImpl<QualType> &PTypes, - llvm::SmallVectorImpl<ParmVarDecl*> &PVars) { - // Create a local instantiation scope for the parameters. - // FIXME: When we implement the C++0x late-specified return type, - // we will need to move this scope out to the function type itself. - bool IsTemporaryScope = (SemaRef.CurrentInstantiationScope != 0); - Sema::LocalInstantiationScope Scope(SemaRef, IsTemporaryScope, - IsTemporaryScope); - - if (TreeTransform<TemplateInstantiator>:: - TransformFunctionTypeParams(TL, PTypes, PVars)) - return true; - - // Check instantiated parameters. - if (SemaRef.CheckInstantiatedParams(PVars)) - return true; - - return false; +QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, + FunctionProtoTypeLoc TL, + QualType ObjectType) { + // We need a local instantiation scope for this function prototype. + Sema::LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return inherited::TransformFunctionProtoType(TLB, TL, ObjectType); } ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) { - TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); - TypeSourceInfo *NewDI = getDerived().TransformType(OldDI); - if (!NewDI) - return 0; - - // TODO: do we have to clone this decl if the types match and - // there's no default argument? - - ParmVarDecl *NewParm - = ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - /* DefArg */ NULL); - - // Maybe adjust new parameter type. - NewParm->setType(SemaRef.adjustParameterType(NewParm->getType())); - - // Mark the (new) default argument as uninstantiated (if any). - if (OldParm->hasUninstantiatedDefaultArg()) { - Expr *Arg = OldParm->getUninstantiatedDefaultArg(); - NewParm->setUninstantiatedDefaultArg(Arg); - } else if (Expr *Arg = OldParm->getDefaultArg()) - NewParm->setUninstantiatedDefaultArg(Arg); - - NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); - - SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); - return NewParm; + return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs); } QualType @@ -959,6 +950,91 @@ QualType Sema::SubstType(QualType T, return Instantiator.TransformType(T); } +static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { + if (T->getType()->isDependentType()) + return true; + + TypeLoc TL = T->getTypeLoc(); + if (!isa<FunctionProtoTypeLoc>(TL)) + return false; + + FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL); + for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) { + ParmVarDecl *P = FP.getArg(I); + + // TODO: currently we always rebuild expressions. When we + // properly get lazier about this, we should use the same + // logic to avoid rebuilding prototypes here. + if (P->hasInit()) + return true; + } + + return false; +} + +/// A form of SubstType intended specifically for instantiating the +/// type of a FunctionDecl. Its purpose is solely to force the +/// instantiation of default-argument expressions. +TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &Args, + SourceLocation Loc, + DeclarationName Entity) { + assert(!ActiveTemplateInstantiations.empty() && + "Cannot perform an instantiation without some context on the " + "instantiation stack"); + + if (!NeedsInstantiationAsFunctionType(T)) + return T; + + TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + + TypeLocBuilder TLB; + + TypeLoc TL = T->getTypeLoc(); + TLB.reserve(TL.getFullDataSize()); + + QualType Result = Instantiator.TransformType(TLB, TL, QualType()); + if (Result.isNull()) + return 0; + + return TLB.getTypeSourceInfo(Context, Result); +} + +ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, + const MultiLevelTemplateArgumentList &TemplateArgs) { + TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); + TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(), + OldParm->getDeclName()); + if (!NewDI) + return 0; + + if (NewDI->getType()->isVoidType()) { + Diag(OldParm->getLocation(), diag::err_param_with_void_type); + return 0; + } + + ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(), + NewDI, NewDI->getType(), + OldParm->getIdentifier(), + OldParm->getLocation(), + OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten()); + if (!NewParm) + return 0; + + // Mark the (new) default argument as uninstantiated (if any). + if (OldParm->hasUninstantiatedDefaultArg()) { + Expr *Arg = OldParm->getUninstantiatedDefaultArg(); + NewParm->setUninstantiatedDefaultArg(Arg); + } else if (Expr *Arg = OldParm->getDefaultArg()) + NewParm->setUninstantiatedDefaultArg(Arg); + + NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); + + CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm); + return NewParm; +} + /// \brief Perform substitution on the base class specifiers of the /// given class template specialization. /// @@ -1083,8 +1159,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - DeclContext *PreviousContext = CurContext; - CurContext = Instantiation; + ContextRAII SavedContext(*this, Instantiation); // If this is an instantiation of a local class, merge this local // instantiation scope with the enclosing scope. Otherwise, every @@ -1120,12 +1195,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, ActOnFields(0, Instantiation->getLocation(), DeclPtrTy::make(Instantiation), Fields.data(), Fields.size(), SourceLocation(), SourceLocation(), 0); - CheckCompletedCXXClass(Instantiation); + CheckCompletedCXXClass(/*Scope=*/0, Instantiation); if (Instantiation->isInvalidDecl()) Invalid = true; // Exit the scope of this instantiation. - CurContext = PreviousContext; + SavedContext.pop(); // If this is a polymorphic C++ class without a key function, we'll // have to mark all of the virtual members to allow emission of a vtable @@ -1195,21 +1270,20 @@ Sema::InstantiateClassTemplateSpecialization( typedef std::pair<ClassTemplatePartialSpecializationDecl *, TemplateArgumentList *> MatchResult; llvm::SmallVector<MatchResult, 4> Matched; - for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator - Partial = Template->getPartialSpecializations().begin(), - PartialEnd = Template->getPartialSpecializations().end(); - Partial != PartialEnd; - ++Partial) { + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + Template->getPartialSpecializations(PartialSpecs); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; TemplateDeductionInfo Info(Context, PointOfInstantiation); if (TemplateDeductionResult Result - = DeduceTemplateArguments(&*Partial, + = DeduceTemplateArguments(Partial, ClassTemplateSpec->getTemplateArgs(), Info)) { // FIXME: Store the failed-deduction information for use in // diagnostics, later. (void)Result; } else { - Matched.push_back(std::make_pair(&*Partial, Info.take())); + Matched.push_back(std::make_pair(Partial, Info.take())); } } @@ -1331,6 +1405,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, MemberSpecializationInfo *MSInfo = Function->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Function, MSInfo->getTemplateSpecializationKind(), @@ -1363,6 +1441,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Var->isStaticDataMember()) { MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Var, MSInfo->getTemplateSpecializationKind(), @@ -1389,11 +1471,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, } } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { - if (Record->isInjectedClassName()) + // Always skip the injected-class-name, along with any + // redeclarations of nested classes, since both would cause us + // to try to instantiate the members of a class twice. + if (Record->isInjectedClassName() || Record->getPreviousDeclaration()) continue; MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); assert(MSInfo && "No member specialization information?"); + + if (MSInfo->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + continue; + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Record, MSInfo->getTemplateSpecializationKind(), @@ -1502,3 +1592,29 @@ bool Sema::Subst(const TemplateArgumentLoc &Input, TemplateArgumentLoc &Output, return Instantiator.TransformTemplateArgument(Input, Output); } + +Decl *Sema::LocalInstantiationScope::getInstantiationOf(const Decl *D) { + for (LocalInstantiationScope *Current = this; Current; + Current = Current->Outer) { + // Check if we found something within this scope. + llvm::DenseMap<const Decl *, Decl *>::iterator Found + = Current->LocalDecls.find(D); + if (Found != Current->LocalDecls.end()) + return Found->second; + + // If we aren't combined with our outer scope, we're done. + if (!Current->CombineWithOuterScope) + break; + } + + assert(D->isInvalidDecl() && + "declaration was not instantiated in this scope!"); + return 0; +} + +void Sema::LocalInstantiationScope::InstantiatedLocal(const Decl *D, + Decl *Inst) { + Decl *&Stored = LocalDecls[D]; + assert((!Stored || Stored == Inst)&& "Already instantiated this local"); + Stored = Inst; +} diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3375ccc..8b851b2 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -200,12 +200,22 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { if (Invalid) Typedef->setInvalidDecl(); + if (const TagType *TT = DI->getType()->getAs<TagType>()) { + TagDecl *TD = TT->getDecl(); + + // If the TagDecl that the TypedefDecl points to is an anonymous decl + // keep track of the TypedefDecl. + if (!TD->getIdentifier() && !TD->getTypedefForAnonDecl()) + TD->setTypedefForAnonDecl(Typedef); + } + if (TypedefDecl *Prev = D->getPreviousDeclaration()) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); @@ -322,7 +332,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), DI->getType(), DI, - D->getStorageClass()); + D->getStorageClass(), + D->getStorageClassAsWritten()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); @@ -354,6 +365,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Owner->makeDeclVisibleInContext(Var); } else { Owner->addDecl(Var); + + if (Owner->isFunctionOrMethod()) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); } // Link instantiations of static data members back to the template from @@ -476,47 +490,37 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { - FriendDecl::FriendUnion FU; - // Handle friend type expressions by simply substituting template - // parameters into the pattern type. + // parameters into the pattern type and checking the result. if (TypeSourceInfo *Ty = D->getFriendType()) { TypeSourceInfo *InstTy = SemaRef.SubstType(Ty, TemplateArgs, D->getLocation(), DeclarationName()); - if (!InstTy) return 0; - - // This assertion is valid because the source type was necessarily - // an elaborated-type-specifier with a record tag. - assert(getLangOptions().CPlusPlus0x || InstTy->getType()->isRecordType()); - - FU = InstTy; - - // Handle everything else by appropriate substitution. - } else { - NamedDecl *ND = D->getFriendDecl(); - assert(ND && "friend decl must be a decl or a type!"); - - // FIXME: We have a problem here, because the nested call to Visit(ND) - // will inject the thing that the friend references into the current - // owner, which is wrong. - Decl *NewND; + if (!InstTy) + return 0; - // Hack to make this work almost well pending a rewrite. - if (D->wasSpecialization()) { - // Totally egregious hack to work around PR5866 + FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); + if (!FD) return 0; - } else { - NewND = Visit(ND); - } - if (!NewND) return 0; + + FD->setAccess(AS_public); + Owner->addDecl(FD); + return FD; + } + + NamedDecl *ND = D->getFriendDecl(); + assert(ND && "friend decl must be a decl or a type!"); - FU = cast<NamedDecl>(NewND); - } + // All of the Visit implementations for the various potential friend + // declarations have to be carefully written to work for friend + // objects, with the most important detail being that the target + // decl should almost certainly not be placed in Owner. + Decl *NewND = Visit(ND); + if (!NewND) return 0; FriendDecl *FD = - FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU, - D->getFriendLoc()); + FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), + cast<NamedDecl>(NewND), D->getFriendLoc()); FD->setAccess(AS_public); Owner->addDecl(FD); return FD; @@ -619,21 +623,6 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } -namespace { - class SortDeclByLocation { - SourceManager &SourceMgr; - - public: - explicit SortDeclByLocation(SourceManager &SourceMgr) - : SourceMgr(SourceMgr) { } - - bool operator()(const Decl *X, const Decl *Y) const { - return SourceMgr.isBeforeInTranslationUnit(X->getLocation(), - Y->getLocation()); - } - }; -} - Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); @@ -698,19 +687,52 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return 0; } + bool AdoptedPreviousTemplateParams = false; if (PrevClassTemplate) { + bool Complain = true; + + // HACK: libstdc++ 4.2.1 contains an ill-formed friend class + // template for struct std::tr1::__detail::_Map_base, where the + // template parameters of the friend declaration don't match the + // template parameters of the original declaration. In this one + // case, we don't complain about the ill-formed friend + // declaration. + if (isFriend && Pattern->getIdentifier() && + Pattern->getIdentifier()->isStr("_Map_base") && + DC->isNamespace() && + cast<NamespaceDecl>(DC)->getIdentifier() && + cast<NamespaceDecl>(DC)->getIdentifier()->isStr("__detail")) { + DeclContext *DCParent = DC->getParent(); + if (DCParent->isNamespace() && + cast<NamespaceDecl>(DCParent)->getIdentifier() && + cast<NamespaceDecl>(DCParent)->getIdentifier()->isStr("tr1")) { + DeclContext *DCParent2 = DCParent->getParent(); + if (DCParent2->isNamespace() && + cast<NamespaceDecl>(DCParent2)->getIdentifier() && + cast<NamespaceDecl>(DCParent2)->getIdentifier()->isStr("std") && + DCParent2->getParent()->isTranslationUnit()) + Complain = false; + } + } + TemplateParameterList *PrevParams = PrevClassTemplate->getTemplateParameters(); // Make sure the parameter lists match. if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, - /*Complain=*/true, - Sema::TPL_TemplateMatch)) - return 0; + Complain, + Sema::TPL_TemplateMatch)) { + if (Complain) + return 0; + + AdoptedPreviousTemplateParams = true; + InstParams = PrevParams; + } // Do some additional validation, then merge default arguments // from the existing declarations. - if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams, + if (!AdoptedPreviousTemplateParams && + SemaRef.CheckTemplateParameterList(InstParams, PrevParams, Sema::TPC_ClassTemplate)) return 0; } @@ -730,7 +752,13 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { D->getIdentifier(), InstParams, RecordInst, PrevClassTemplate); RecordInst->setDescribedClassTemplate(Inst); + if (isFriend) { + if (PrevClassTemplate) + Inst->setAccess(PrevClassTemplate->getAccess()); + else + Inst->setAccess(D->getAccess()); + Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); // TODO: do we want to track the instantiation progeny of this // friend target decl? @@ -742,29 +770,19 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { // Trigger creation of the type for the instantiation. SemaRef.Context.getInjectedClassNameType(RecordInst, Inst->getInjectedClassNameSpecialization(SemaRef.Context)); - + // Finish handling of friends. if (isFriend) { DC->makeDeclVisibleInContext(Inst, /*Recoverable*/ false); return Inst; } - Inst->setAccess(D->getAccess()); Owner->addDecl(Inst); - // First, we sort the partial specializations by location, so - // that we instantiate them in the order they were declared. - llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; - for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator - P = D->getPartialSpecializations().begin(), - PEnd = D->getPartialSpecializations().end(); - P != PEnd; ++P) - PartialSpecs.push_back(&*P); - std::sort(PartialSpecs.begin(), PartialSpecs.end(), - SortDeclByLocation(SemaRef.SourceMgr)); - // Instantiate all of the partial specializations of this member class // template. + llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; + D->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); @@ -807,7 +825,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // merged with the local instantiation scope for the function template // itself. Sema::LocalInstantiationScope Scope(SemaRef); - + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -963,7 +981,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), D->getDeclName(), T, TInfo, - D->getStorageClass(), + D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); if (Qualifier) @@ -1027,11 +1045,47 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; + bool isExplicitSpecialization = false; LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (TemplateParams || !FunctionTemplate) { + if (DependentFunctionTemplateSpecializationInfo *Info + = D->getDependentSpecializationInfo()) { + assert(isFriend && "non-friend has dependent specialization info?"); + + // This needs to be set now for future sanity. + Function->setObjectOfFriendDecl(/*HasPrevious*/ true); + + // Instantiate the explicit template arguments. + TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), + Info->getRAngleLoc()); + for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) { + TemplateArgumentLoc Loc; + if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs)) + return 0; + + ExplicitArgs.addArgument(Loc); + } + + // Map the candidate templates to their instantiations. + for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { + Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), + Info->getTemplate(I), + TemplateArgs); + if (!Temp) return 0; + + Previous.addDecl(cast<FunctionTemplateDecl>(Temp)); + } + + if (SemaRef.CheckFunctionTemplateSpecialization(Function, + &ExplicitArgs, + Previous)) + Function->setInvalidDecl(); + + isExplicitSpecialization = true; + + } else if (TemplateParams || !FunctionTemplate) { // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. @@ -1046,25 +1100,30 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - false, Redeclaration, + isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); + NamedDecl *PrincipalDecl = (TemplateParams + ? cast<NamedDecl>(FunctionTemplate) + : Function); + // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. if (isFriend) { - NamedDecl *ToFriendD = 0; NamedDecl *PrevDecl; - if (TemplateParams) { - ToFriendD = cast<NamedDecl>(FunctionTemplate); + if (TemplateParams) PrevDecl = FunctionTemplate->getPreviousDeclaration(); - } else { - ToFriendD = Function; + else PrevDecl = Function->getPreviousDeclaration(); - } - ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL); - DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false); + + PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); + DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false); } + if (Function->isOverloadedOperator() && !DC->isRecord() && + PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + PrincipalDecl->setNonMemberOperator(); + return Function; } @@ -1146,14 +1205,16 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->getLocation(), Name, T, TInfo, Constructor->isExplicit(), - Constructor->isInlineSpecified(), false); + Constructor->isInlineSpecified(), + false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { QualType ClassTy = SemaRef.Context.getTypeDeclType(Record); Name = SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType(ClassTy)); Method = CXXDestructorDecl::Create(SemaRef.Context, Record, Destructor->getLocation(), Name, - T, Destructor->isInlineSpecified(), false); + T, Destructor->isInlineSpecified(), + false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { CanQualType ConvTy = SemaRef.Context.getCanonicalType( @@ -1168,7 +1229,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), D->getDeclName(), T, TInfo, - D->isStatic(), D->isInlineSpecified()); + D->isStatic(), + D->getStorageClassAsWritten(), + D->isInlineSpecified()); } if (Qualifier) @@ -1279,41 +1342,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - QualType T; - TypeSourceInfo *DI = D->getTypeSourceInfo(); - if (DI) { - DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(), - D->getDeclName()); - if (DI) T = DI->getType(); - } else { - T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), - D->getDeclName()); - DI = 0; - } - - if (T.isNull()) - return 0; - - T = SemaRef.adjustParameterType(T); - - // Allocate the parameter - ParmVarDecl *Param - = ParmVarDecl::Create(SemaRef.Context, - SemaRef.Context.getTranslationUnitDecl(), - D->getLocation(), - D->getIdentifier(), T, DI, D->getStorageClass(), 0); - - // Mark the default argument as being uninstantiated. - if (D->hasUninstantiatedDefaultArg()) - Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg()); - else if (Expr *Arg = D->getDefaultArg()) - Param->setUninstantiatedDefaultArg(Arg); - - // Note: we don't try to instantiate function parameters until after - // we've instantiated the function's type. Therefore, we don't have - // to check for 'void' parameter types here. - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); - return Param; + return SemaRef.SubstParmVarDecl(D, TemplateArgs); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( @@ -1718,7 +1747,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( Converted, InstTemplateArgs, CanonType, - 0); + 0, + ClassTemplate->getPartialSpecializations().size()); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) return 0; @@ -1733,48 +1763,50 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return false; } -bool -Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) { - bool Invalid = false; - for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i) - if (ParmVarDecl *PInst = Params[i]) { - if (PInst->isInvalidDecl()) - Invalid = true; - else if (PInst->getType()->isVoidType()) { - Diag(PInst->getLocation(), diag::err_param_with_void_type); - PInst->setInvalidDecl(); - Invalid = true; - } - else if (RequireNonAbstractType(PInst->getLocation(), - PInst->getType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType)) { - PInst->setInvalidDecl(); - Invalid = true; - } - } - return Invalid; -} - TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, llvm::SmallVectorImpl<ParmVarDecl *> &Params) { TypeSourceInfo *OldTInfo = D->getTypeSourceInfo(); assert(OldTInfo && "substituting function without type source info"); assert(Params.empty() && "parameter vector is non-empty at start"); - TypeSourceInfo *NewTInfo = SemaRef.SubstType(OldTInfo, TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName()); + TypeSourceInfo *NewTInfo + = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, + D->getTypeSpecStartLoc(), + D->getDeclName()); if (!NewTInfo) return 0; - // Get parameters from the new type info. - TypeLoc NewTL = NewTInfo->getTypeLoc(); - FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); - assert(NewProtoLoc && "Missing prototype?"); - for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) - Params.push_back(NewProtoLoc->getArg(i)); - + if (NewTInfo != OldTInfo) { + // Get parameters from the new type info. + TypeLoc OldTL = OldTInfo->getTypeLoc(); + if (FunctionProtoTypeLoc *OldProtoLoc + = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { + TypeLoc NewTL = NewTInfo->getTypeLoc(); + FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL); + assert(NewProtoLoc && "Missing prototype?"); + for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) { + // FIXME: Variadic templates will break this. + Params.push_back(NewProtoLoc->getArg(i)); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + OldProtoLoc->getArg(i), + NewProtoLoc->getArg(i)); + } + } + } else { + // The function type itself was not dependent and therefore no + // substitution occurred. However, we still need to instantiate + // the function parameters themselves. + TypeLoc OldTL = OldTInfo->getTypeLoc(); + if (FunctionProtoTypeLoc *OldProtoLoc + = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) { + for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) { + ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i)); + if (!Parm) + return 0; + Params.push_back(Parm); + } + } + } return NewTInfo; } @@ -1938,8 +1970,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) - return; - + return; + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, // while we're still within our own instantiation context. @@ -1971,7 +2003,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, CurContext = Function; MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function); + getTemplateInstantiationArgs(Function, 0, false, PatternDecl); // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = @@ -2459,7 +2491,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, T = Context.getTypeDeclType(Record); assert(isa<InjectedClassNameType>(T) && "type of partial specialization is not an InjectedClassNameType"); - T = cast<InjectedClassNameType>(T)->getUnderlyingType(); + T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); } if (!T.isNull()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8278691..d1a74be 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -81,9 +81,12 @@ static void ProcessDelayedFnAttrs(Sema &S, QualType &Type, DelayedAttributeSet &Attrs) { for (DelayedAttributeSet::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) - if (ProcessFnAttr(S, Type, *I->first)) + if (ProcessFnAttr(S, Type, *I->first)) { S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) << I->first->getName() << I->second; + // Avoid any further processing of this attribute. + I->first->setInvalid(); + } Attrs.clear(); } @@ -92,6 +95,8 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { E = Attrs.end(); I != E; ++I) { S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) << I->first->getName() << I->second; + // Avoid any further processing of this attribute. + I->first->setInvalid(); } Attrs.clear(); } @@ -280,6 +285,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (TheSema.getLangOptions().CPlusPlus) { TagDecl::TagKind Tag = TagDecl::getTagKindForTypeSpec(DS.getTypeSpecType()); + Result = TheSema.getQualifiedNameType(DS.getTypeSpecScope(), Result); Result = Context.getElaboratedType(Result, Tag); } @@ -498,6 +504,8 @@ QualType Sema::BuildPointerType(QualType T, unsigned Quals, Qs.removeRestrict(); } + assert(!T->isObjCInterfaceType() && "Should build ObjCObjectPointerType"); + // Build the pointer type. return Context.getQualifiedType(Context.getPointerType(T), Qs); } @@ -604,15 +612,31 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, SourceRange Brackets, DeclarationName Entity) { SourceLocation Loc = Brackets.getBegin(); - // C99 6.7.5.2p1: If the element type is an incomplete or function type, - // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - // Not in C++, though. There we only dislike void. if (getLangOptions().CPlusPlus) { + // C++ [dcl.array]p1: + // T is called the array element type; this type shall not be a reference + // type, the (possibly cv-qualified) type void, a function type or an + // abstract class type. + // + // Note: function types are handled in the common path with C. + if (T->isReferenceType()) { + Diag(Loc, diag::err_illegal_decl_array_of_references) + << getPrintableNameForEntity(Entity) << T; + return QualType(); + } + if (T->isVoidType()) { Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; return QualType(); } + + if (RequireNonAbstractType(Brackets.getBegin(), T, + diag::err_array_of_abstract_type)) + return QualType(); + } else { + // C99 6.7.5.2p1: If the element type is an incomplete or function type, + // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) if (RequireCompleteType(Loc, T, diag::err_illegal_decl_array_incomplete_type)) return QualType(); @@ -624,13 +648,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - // C++ 8.3.2p4: There shall be no ... arrays of references ... - if (T->isReferenceType()) { - Diag(Loc, diag::err_illegal_decl_array_of_references) - << getPrintableNameForEntity(Entity) << T; - return QualType(); - } - if (Context.getCanonicalType(T) == Context.UndeducedAutoTy) { Diag(Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Entity); @@ -922,7 +939,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Determine the type of the declarator. Not all forms of declarator // have a type. QualType T; - + TypeSourceInfo *ReturnTypeInfo = 0; + llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec; switch (D.getName().getKind()) { @@ -948,12 +966,17 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Constructors and destructors don't have return types. Use // "void" instead. T = Context.VoidTy; + + if (TInfo) + ReturnTypeInfo = Context.getTrivialTypeSourceInfo(T, + D.getName().StartLocation); break; case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. - T = GetTypeFromParser(D.getName().ConversionFunctionId); + T = GetTypeFromParser(D.getName().ConversionFunctionId, + TInfo? &ReturnTypeInfo : 0); break; } @@ -1036,7 +1059,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (getLangOptions().ObjC1 && T->isObjCInterfaceType()) { const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>(); T = Context.getObjCObjectPointerType(T, - (ObjCProtocolDecl **)OIT->qual_begin(), + const_cast<ObjCProtocolDecl **>( + OIT->qual_begin()), OIT->getNumProtocols(), DeclType.Ptr.TypeQuals); break; @@ -1253,8 +1277,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } // The scope spec must refer to a class, or be dependent. QualType ClsType; - if (isDependentScopeSpecifier(DeclType.Mem.Scope()) - || dyn_cast_or_null<CXXRecordDecl>( + if (DeclType.Mem.Scope().isInvalid()) { + // Avoid emitting extra errors if we already errored on the scope. + D.setInvalidType(true); + } else if (isDependentScopeSpecifier(DeclType.Mem.Scope()) + || dyn_cast_or_null<CXXRecordDecl>( computeDeclContext(DeclType.Mem.Scope()))) { NestedNameSpecifier *NNS = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); @@ -1353,7 +1380,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.isInvalidType()) *TInfo = 0; else - *TInfo = GetTypeSourceInfoForDeclarator(D, T); + *TInfo = GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo); } return T; @@ -1538,8 +1565,14 @@ namespace { /// \brief Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. +/// +/// \param ReturnTypeInfo For declarators whose return type does not show +/// up in the normal place in the declaration specifiers (such as a C++ +/// conversion function), this pointer will refer to a type source information +/// for that return type. TypeSourceInfo * -Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { +Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo) { TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); @@ -1549,7 +1582,18 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T) { } TypeSpecLocFiller(D.getDeclSpec()).Visit(CurrTL); - + + // We have source information for the return type that was not in the + // declaration specifiers; copy that information into the current type + // location so that it will be retained. This occurs, for example, with + // a C++ conversion function, where the return type occurs within the + // declarator-id rather than in the declaration specifiers. + if (ReturnTypeInfo && D.getDeclSpec().getTypeSpecType() == TST_unspecified) { + TypeLoc TL = ReturnTypeInfo->getTypeLoc(); + assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); + memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); + } + return TInfo; } @@ -1648,12 +1692,14 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, // for two or more different address spaces." if (Type.getAddressSpace()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_multiple_qualifiers); + Attr.setInvalid(); return; } // Check the attribute arguments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } Expr *ASArgExpr = static_cast<Expr *>(Attr.getArg(0)); @@ -1661,6 +1707,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (!ASArgExpr->isIntegerConstantExpr(addrSpace, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_not_int) << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1669,6 +1716,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (addrSpace.isNegative()) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_negative) << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } addrSpace.setIsSigned(false); @@ -1678,6 +1726,7 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, if (addrSpace > max) { S.Diag(Attr.getLoc(), diag::err_attribute_address_space_too_high) << Qualifiers::MaxAddressSpace << ASArgExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1691,6 +1740,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type, const AttributeList &Attr, Sema &S) { if (Type.getObjCGCAttr() != Qualifiers::GCNone) { S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); + Attr.setInvalid(); return; } @@ -1698,11 +1748,13 @@ static void HandleObjCGCTypeAttribute(QualType &Type, if (!Attr.getParameterName()) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; + Attr.setInvalid(); return; } Qualifiers::GC GCAttr; if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } if (Attr.getParameterName()->isStr("weak")) @@ -1712,6 +1764,7 @@ static void HandleObjCGCTypeAttribute(QualType &Type, else { S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) << "objc_gc" << Attr.getParameterName(); + Attr.setInvalid(); return; } @@ -1725,6 +1778,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { // Complain immediately if the arg count is wrong. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + Attr.setInvalid(); return false; } @@ -1766,6 +1820,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { // Otherwise, a calling convention. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + Attr.setInvalid(); return false; } @@ -1788,13 +1843,17 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { CallingConv CCOld = Fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == - S.Context.getCanonicalCallConv(CCOld)) return false; + S.Context.getCanonicalCallConv(CCOld)) { + Attr.setInvalid(); + return false; + } if (CCOld != CC_Default) { // Should we diagnose reapplications of the same convention? S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) << FunctionType::getNameForCallConv(CC) << FunctionType::getNameForCallConv(CCOld); + Attr.setInvalid(); return false; } @@ -1803,6 +1862,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { if (isa<FunctionNoProtoType>(Fn)) { S.Diag(Attr.getLoc(), diag::err_cconv_knr) << FunctionType::getNameForCallConv(CC); + Attr.setInvalid(); return false; } @@ -1810,6 +1870,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { if (FnP->isVariadic()) { S.Diag(Attr.getLoc(), diag::err_cconv_varargs) << FunctionType::getNameForCallConv(CC); + Attr.setInvalid(); return false; } } @@ -1829,6 +1890,7 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S // Check the attribute arugments. if (Attr.getNumArgs() != 1) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); return; } Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); @@ -1836,12 +1898,14 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) << "vector_size" << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } // the base type must be integer or float, and can't already be a vector. if (CurType->isVectorType() || (!CurType->isIntegerType() && !CurType->isRealFloatingType())) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; + Attr.setInvalid(); return; } unsigned typeSize = static_cast<unsigned>(S.Context.getTypeSize(CurType)); @@ -1852,11 +1916,13 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S if (vectorSize % typeSize) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } if (vectorSize == 0) { S.Diag(Attr.getLoc(), diag::err_attribute_zero_size) << sizeExpr->getSourceRange(); + Attr.setInvalid(); return; } @@ -1873,8 +1939,12 @@ void ProcessTypeAttributeList(Sema &S, QualType &Result, // type, but others can be present in the type specifiers even though they // apply to the decl. Here we apply type attributes and ignore the rest. for (; AL; AL = AL->getNext()) { - // If this is an attribute we can handle, do so now, otherwise, add it to - // the LeftOverAttrs list for rechaining. + // Skip attributes that were marked to be invalid. + if (AL->isInvalid()) + continue; + + // If this is an attribute we can handle, do so now, + // otherwise, add it to the FnAttrs list for rechaining. switch (AL->getKind()) { default: break; @@ -2029,7 +2099,10 @@ QualType Sema::BuildTypeofExprType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization, Specialization); + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); if (!E) return QualType(); } else { @@ -2049,7 +2122,10 @@ QualType Sema::BuildDecltypeType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization, Specialization); + // The access doesn't really matter in this case. + DeclAccessPair Found = DeclAccessPair::make(Specialization, + Specialization->getAccess()); + E = FixOverloadedFunctionReference(E, Found, Specialization); if (!E) return QualType(); } else { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f9ffd3f..5ce268b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -338,6 +338,7 @@ public: QualType ObjectType); OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); + OwningExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E); #define STMT(Node, Parent) \ OwningStmtResult Transform##Node(Node *S); @@ -378,10 +379,6 @@ public: QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); - /// \brief Build a new Objective C object pointer type. - QualType RebuildObjCObjectPointerType(QualType PointeeType, - SourceLocation Sigil); - /// \brief Build a new array type given the element type, size /// modifier, size of the array (if known), size expression, and index type /// qualifiers. @@ -577,10 +574,9 @@ public: TagDecl::TagKind Kind = TagDecl::TK_enum; switch (Keyword) { case ETK_None: - // FIXME: Note the lack of the "typename" specifier! - // Fall through + // Fall through. case ETK_Typename: - return SemaRef.CheckTypenameType(NNS, *Id, SR); + return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR); case ETK_Class: Kind = TagDecl::TK_class; break; case ETK_Struct: Kind = TagDecl::TK_struct; break; @@ -892,6 +888,88 @@ public: move(Exprs), move(AsmString), move(Clobbers), RParenLoc, MSAsm); } + + /// \brief Build a new Objective-C @try statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtTryStmt(SourceLocation AtLoc, + StmtArg TryBody, + MultiStmtArg CatchStmts, + StmtArg Finally) { + return getSema().ActOnObjCAtTryStmt(AtLoc, move(TryBody), move(CatchStmts), + move(Finally)); + } + + /// \brief Rebuild an Objective-C exception declaration. + /// + /// By default, performs semantic analysis to build the new declaration. + /// Subclasses may override this routine to provide different behavior. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TInfo, QualType T) { + return getSema().BuildObjCExceptionDecl(TInfo, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation()); + } + + /// \brief Build a new Objective-C @catch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParenLoc, + VarDecl *Var, + StmtArg Body) { + return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc, + Sema::DeclPtrTy::make(Var), + move(Body)); + } + + /// \brief Build a new Objective-C @finally statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtFinallyStmt(SourceLocation AtLoc, + StmtArg Body) { + return getSema().ActOnObjCAtFinallyStmt(AtLoc, move(Body)); + } + + /// \brief Build a new Objective-C @throw statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Operand) { + return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand)); + } + + /// \brief Build a new Objective-C @synchronized statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc, + ExprArg Object, + StmtArg Body) { + return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object), + move(Body)); + } + + /// \brief Build a new Objective-C fast enumeration statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCForCollectionStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + StmtArg Element, + ExprArg Collection, + SourceLocation RParenLoc, + StmtArg Body) { + return getSema().ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + move(Element), + move(Collection), + RParenLoc, + move(Body)); + } /// \brief Build a new C++ exception declaration. /// @@ -989,6 +1067,19 @@ public: return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr)); } + /// \brief Build a new builtin offsetof expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc, + TypeSourceInfo *Type, + Action::OffsetOfComponent *Components, + unsigned NumComponents, + SourceLocation RParenLoc) { + return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components, + NumComponents, RParenLoc); + } + /// \brief Build a new sizeof or alignof expression with a type argument. /// /// By default, performs semantic analysis to build the new expression. @@ -1421,30 +1512,24 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, - SourceLocation LParenLoc, - QualType T, + OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, SourceLocation RParenLoc) { - return getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, true, - T.getAsOpaquePtr(), RParenLoc); + return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, Operand, + RParenLoc); } /// \brief Build a new C++ typeid(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCXXTypeidExpr(SourceLocation TypeidLoc, - SourceLocation LParenLoc, + OwningExprResult RebuildCXXTypeidExpr(QualType TypeInfoType, + SourceLocation TypeidLoc, ExprArg Operand, SourceLocation RParenLoc) { - OwningExprResult Result - = getSema().ActOnCXXTypeid(TypeidLoc, LParenLoc, false, Operand.get(), - RParenLoc); - if (Result.isInvalid()) - return getSema().ExprError(); - - Operand.release(); // FIXME: since ActOnCXXTypeid silently took ownership - return move(Result); + return getSema().BuildCXXTypeId(TypeInfoType, TypeidLoc, move(Operand), + RParenLoc); } /// \brief Build a new C++ "this" expression. @@ -1688,29 +1773,147 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildObjCEncodeExpr(SourceLocation AtLoc, - QualType T, + TypeSourceInfo *EncodeTypeInfo, SourceLocation RParenLoc) { - return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, T, + return SemaRef.Owned(SemaRef.BuildObjCEncodeExpression(AtLoc, EncodeTypeInfo, RParenLoc)); } - /// \brief Build a new Objective-C protocol expression. + /// \brief Build a new Objective-C class message. + OwningExprResult RebuildObjCMessageExpr(TypeSourceInfo *ReceiverTypeInfo, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + MultiExprArg Args, + SourceLocation RBracLoc) { + return SemaRef.BuildClassMessage(ReceiverTypeInfo, + ReceiverTypeInfo->getType(), + /*SuperLoc=*/SourceLocation(), + Sel, Method, LBracLoc, RBracLoc, + move(Args)); + } + + /// \brief Build a new Objective-C instance message. + OwningExprResult RebuildObjCMessageExpr(ExprArg Receiver, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + MultiExprArg Args, + SourceLocation RBracLoc) { + QualType ReceiverType = static_cast<Expr *>(Receiver.get())->getType(); + return SemaRef.BuildInstanceMessage(move(Receiver), + ReceiverType, + /*SuperLoc=*/SourceLocation(), + Sel, Method, LBracLoc, RBracLoc, + move(Args)); + } + + /// \brief Build a new Objective-C ivar reference expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildObjCProtocolExpr(ObjCProtocolDecl *Protocol, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - return SemaRef.Owned(SemaRef.ParseObjCProtocolExpression( - Protocol->getIdentifier(), - AtLoc, - ProtoLoc, - LParenLoc, - RParenLoc)); + OwningExprResult RebuildObjCIvarRefExpr(ExprArg BaseArg, ObjCIvarDecl *Ivar, + SourceLocation IvarLoc, + bool IsArrow, bool IsFreeIvar) { + // FIXME: We lose track of the IsFreeIvar bit. + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IvarLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IvarLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + + /// \brief Build a new Objective-C property reference expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCPropertyRefExpr(ExprArg BaseArg, + ObjCPropertyDecl *Property, + SourceLocation PropertyLoc) { + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), Property->getDeclName(), PropertyLoc, + Sema::LookupMemberName); + bool IsArrow = false; + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/PropertyLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/PropertyLoc, IsArrow, + SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + + /// \brief Build a new Objective-C implicit setter/getter reference + /// expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCImplicitSetterGetterRefExpr( + ObjCMethodDecl *Getter, + QualType T, + ObjCMethodDecl *Setter, + SourceLocation NameLoc, + ExprArg Base) { + // Since these expressions can only be value-dependent, we do not need to + // perform semantic analysis again. + return getSema().Owned( + new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T, + Setter, + NameLoc, + Base.takeAs<Expr>())); } + /// \brief Build a new Objective-C "isa" expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCIsaExpr(ExprArg BaseArg, SourceLocation IsaLoc, + bool IsArrow) { + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IsaLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IsaLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + /// \brief Build a new shuffle vector expression. /// /// By default, performs semantic analysis to build the new expression. @@ -2225,29 +2428,6 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { return T.getType(); } -// Ugly metaprogramming macros because I couldn't be bothered to make -// the equivalent template version work. -#define TransformPointerLikeType(TypeClass) do { \ - QualType PointeeType \ - = getDerived().TransformType(TLB, TL.getPointeeLoc()); \ - if (PointeeType.isNull()) \ - return QualType(); \ - \ - QualType Result = TL.getType(); \ - if (getDerived().AlwaysRebuild() || \ - PointeeType != TL.getPointeeLoc().getType()) { \ - Result = getDerived().Rebuild##TypeClass(PointeeType, \ - TL.getSigilLoc()); \ - if (Result.isNull()) \ - return QualType(); \ - } \ - \ - TypeClass##Loc NewT = TLB.push<TypeClass##Loc>(Result); \ - NewT.setSigilLoc(TL.getSigilLoc()); \ - \ - return Result; \ -} while(0) - template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T, @@ -2271,7 +2451,42 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL, QualType ObjectType) { - TransformPointerLikeType(PointerType); + QualType PointeeType + = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (PointeeType->isObjCInterfaceType()) { + // A dependent pointer type 'T *' has is being transformed such + // that an Objective-C class type is being replaced for 'T'. The + // resulting pointer type is an ObjCObjectPointerType, not a + // PointerType. + const ObjCInterfaceType *IFace = PointeeType->getAs<ObjCInterfaceType>(); + Result = SemaRef.Context.getObjCObjectPointerType(PointeeType, + const_cast<ObjCProtocolDecl **>( + IFace->qual_begin()), + IFace->getNumProtocols()); + + ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result); + NewT.setStarLoc(TL.getSigilLoc()); + NewT.setHasProtocolsAsWritten(false); + NewT.setLAngleLoc(SourceLocation()); + NewT.setRAngleLoc(SourceLocation()); + NewT.setHasBaseTypeAsWritten(true); + return Result; + } + + if (getDerived().AlwaysRebuild() || + PointeeType != TL.getPointeeLoc().getType()) { + Result = getDerived().RebuildPointerType(PointeeType, TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + PointerTypeLoc NewT = TLB.push<PointerTypeLoc>(Result); + NewT.setSigilLoc(TL.getSigilLoc()); + return Result; } template<typename Derived> @@ -2279,7 +2494,23 @@ QualType TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, BlockPointerTypeLoc TL, QualType ObjectType) { - TransformPointerLikeType(BlockPointerType); + QualType PointeeType + = getDerived().TransformType(TLB, TL.getPointeeLoc()); + if (PointeeType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + PointeeType != TL.getPointeeLoc().getType()) { + Result = getDerived().RebuildBlockPointerType(PointeeType, + TL.getSigilLoc()); + if (Result.isNull()) + return QualType(); + } + + BlockPointerTypeLoc NewT = TLB.push<BlockPointerTypeLoc>(Result); + NewT.setSigilLoc(TL.getSigilLoc()); + return Result; } /// Transforms a reference type. Note that somewhat paradoxically we @@ -2630,6 +2861,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm) { NewDI->getType(), NewDI, OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten(), /* DefArg */ NULL); } @@ -2675,17 +2907,19 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, QualType ObjectType) { - FunctionProtoType *T = TL.getTypePtr(); - QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); - if (ResultType.isNull()) - return QualType(); - - // Transform the parameters. + // Transform the parameters. We do this first for the benefit of template + // instantiations, so that the ParmVarDecls get/ placed into the template + // instantiation scope before we transform the function type. llvm::SmallVector<QualType, 4> ParamTypes; llvm::SmallVector<ParmVarDecl*, 4> ParamDecls; if (getDerived().TransformFunctionTypeParams(TL, ParamTypes, ParamDecls)) return QualType(); - + + FunctionProtoType *T = TL.getTypePtr(); + QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); + if (ResultType.isNull()) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getResultType() || @@ -3117,8 +3351,8 @@ QualType TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, ObjCInterfaceTypeLoc TL, QualType ObjectType) { - assert(false && "TransformObjCInterfaceType unimplemented"); - return QualType(); + // ObjCInterfaceType is never dependent. + return TL.getType(); } template<typename Derived> @@ -3126,8 +3360,8 @@ QualType TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB, ObjCObjectPointerTypeLoc TL, QualType ObjectType) { - assert(false && "TransformObjCObjectPointerType unimplemented"); - return QualType(); + // ObjCObjectPointerType is never dependent. + return TL.getType(); } //===----------------------------------------------------------------------===// @@ -3587,51 +3821,172 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @try statement"); - return SemaRef.Owned(S->Retain()); + // Transform the body of the @try. + OwningStmtResult TryBody = getDerived().TransformStmt(S->getTryBody()); + if (TryBody.isInvalid()) + return SemaRef.StmtError(); + + // Transform the @catch statements (if present). + bool AnyCatchChanged = false; + ASTOwningVector<&ActionBase::DeleteStmt> CatchStmts(SemaRef); + for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { + OwningStmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I)); + if (Catch.isInvalid()) + return SemaRef.StmtError(); + if (Catch.get() != S->getCatchStmt(I)) + AnyCatchChanged = true; + CatchStmts.push_back(Catch.release()); + } + + // Transform the @finally statement (if present). + OwningStmtResult Finally(SemaRef); + if (S->getFinallyStmt()) { + Finally = getDerived().TransformStmt(S->getFinallyStmt()); + if (Finally.isInvalid()) + return SemaRef.StmtError(); + } + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + TryBody.get() == S->getTryBody() && + !AnyCatchChanged && + Finally.get() == S->getFinallyStmt()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), move(TryBody), + move_arg(CatchStmts), move(Finally)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @catch statement"); - return SemaRef.Owned(S->Retain()); + // Transform the @catch parameter, if there is one. + VarDecl *Var = 0; + if (VarDecl *FromVar = S->getCatchParamDecl()) { + TypeSourceInfo *TSInfo = 0; + if (FromVar->getTypeSourceInfo()) { + TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo()); + if (!TSInfo) + return SemaRef.StmtError(); + } + + QualType T; + if (TSInfo) + T = TSInfo->getType(); + else { + T = getDerived().TransformType(FromVar->getType()); + if (T.isNull()) + return SemaRef.StmtError(); + } + + Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T); + if (!Var) + return SemaRef.StmtError(); + } + + OwningStmtResult Body = getDerived().TransformStmt(S->getCatchBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(), + S->getRParenLoc(), + Var, move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @finally statement"); - return SemaRef.Owned(S->Retain()); + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getFinallyBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Body.get() == S->getFinallyBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtFinallyStmt(S->getAtFinallyLoc(), + move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @throw statement"); - return SemaRef.Owned(S->Retain()); + OwningExprResult Operand(SemaRef); + if (S->getThrowExpr()) { + Operand = getDerived().TransformExpr(S->getThrowExpr()); + if (Operand.isInvalid()) + return getSema().StmtError(); + } + + if (!getDerived().AlwaysRebuild() && + Operand.get() == S->getThrowExpr()) + return getSema().Owned(S->Retain()); + + return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCAtSynchronizedStmt( ObjCAtSynchronizedStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @synchronized statement"); - return SemaRef.Owned(S->Retain()); + // Transform the object we are locking. + OwningExprResult Object = getDerived().TransformExpr(S->getSynchExpr()); + if (Object.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getSynchBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing change, just retain the current statement. + if (!getDerived().AlwaysRebuild() && + Object.get() == S->getSynchExpr() && + Body.get() == S->getSynchBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(), + move(Object), move(Body)); } template<typename Derived> Sema::OwningStmtResult TreeTransform<Derived>::TransformObjCForCollectionStmt( ObjCForCollectionStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C for-each statement"); - return SemaRef.Owned(S->Retain()); + // Transform the element statement. + OwningStmtResult Element = getDerived().TransformStmt(S->getElement()); + if (Element.isInvalid()) + return SemaRef.StmtError(); + + // Transform the collection expression. + OwningExprResult Collection = getDerived().TransformExpr(S->getCollection()); + if (Collection.isInvalid()) + return SemaRef.StmtError(); + + // Transform the body. + OwningStmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // If nothing changed, just retain this statement. + if (!getDerived().AlwaysRebuild() && + Element.get() == S->getElement() && + Collection.get() == S->getCollection() && + Body.get() == S->getBody()) + return SemaRef.Owned(S->Retain()); + + // Build a new statement. + return getDerived().RebuildObjCForCollectionStmt(S->getForLoc(), + /*FIXME:*/S->getForLoc(), + move(Element), + move(Collection), + S->getRParenLoc(), + move(Body)); } @@ -3828,6 +4183,72 @@ TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { template<typename Derived> Sema::OwningExprResult +TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { + // Transform the type. + TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo()); + if (!Type) + return getSema().ExprError(); + + // Transform all of the components into components similar to what the + // parser uses. + // FIXME: It would be slightly more efficient in the non-dependent case to + // just map FieldDecls, rather than requiring the rebuilder to look for + // the fields again. However, __builtin_offsetof is rare enough in + // template code that we don't care. + bool ExprChanged = false; + typedef Action::OffsetOfComponent Component; + typedef OffsetOfExpr::OffsetOfNode Node; + llvm::SmallVector<Component, 4> Components; + for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { + const Node &ON = E->getComponent(I); + Component Comp; + Comp.isBrackets = true; + Comp.LocStart = ON.getRange().getBegin(); + Comp.LocEnd = ON.getRange().getEnd(); + switch (ON.getKind()) { + case Node::Array: { + Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex()); + OwningExprResult Index = getDerived().TransformExpr(FromIndex); + if (Index.isInvalid()) + return getSema().ExprError(); + + ExprChanged = ExprChanged || Index.get() != FromIndex; + Comp.isBrackets = true; + Comp.U.E = Index.takeAs<Expr>(); // FIXME: leaked + break; + } + + case Node::Field: + case Node::Identifier: + Comp.isBrackets = false; + Comp.U.IdentInfo = ON.getFieldName(); + if (!Comp.U.IdentInfo) + continue; + + break; + + case Node::Base: + // Will be recomputed during the rebuild. + continue; + } + + Components.push_back(Comp); + } + + // If nothing changed, retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Type == E->getTypeSourceInfo() && + !ExprChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new offsetof expression. + return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type, + Components.data(), Components.size(), + E->getRParenLoc()); +} + +template<typename Derived> +Sema::OwningExprResult TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); @@ -4597,19 +5018,18 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { if (E->isTypeOperand()) { - TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName()); - - QualType T = getDerived().TransformType(E->getTypeOperand()); - if (T.isNull()) + TypeSourceInfo *TInfo + = getDerived().TransformType(E->getTypeOperandSourceInfo()); + if (!TInfo) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getTypeOperand()) + TInfo == E->getTypeOperandSourceInfo()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), - /*FIXME:*/E->getLocStart(), - T, + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), + TInfo, E->getLocEnd()); } @@ -4627,8 +5047,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { SubExpr.get() == E->getExprOperand()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCXXTypeidExpr(E->getLocStart(), - /*FIXME:*/E->getLocStart(), + return getDerived().RebuildCXXTypeidExpr(E->getType(), + E->getLocStart(), move(SubExpr), E->getLocEnd()); } @@ -4997,6 +5417,17 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( SS.setScopeRep(Qualifier); SS.setRange(Old->getQualifierRange()); + } + + if (Old->getNamingClass()) { + CXXRecordDecl *NamingClass + = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + Old->getNameLoc(), + Old->getNamingClass())); + if (!NamingClass) + return SemaRef.ExprError(); + + R.setNamingClass(NamingClass); } // If we have no template arguments, it's a normal declaration name. @@ -5423,6 +5854,18 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) R.resolveKind(); + // Determine the naming class. + if (!Old->getNamingClass()) { + CXXRecordDecl *NamingClass + = cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + Old->getMemberLoc(), + Old->getNamingClass())); + if (!NamingClass) + return SemaRef.ExprError(); + + R.setNamingClass(NamingClass); + } + TemplateArgumentListInfo TransArgs; if (Old->hasExplicitTemplateArgs()) { TransArgs.setLAngleLoc(Old->getLAngleLoc()); @@ -5463,27 +5906,76 @@ TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCEncodeExpr(ObjCEncodeExpr *E) { - // FIXME: poor source location - TemporaryBase Rebase(*this, E->getAtLoc(), DeclarationName()); - QualType EncodedType = getDerived().TransformType(E->getEncodedType()); - if (EncodedType.isNull()) + TypeSourceInfo *EncodedTypeInfo + = getDerived().TransformType(E->getEncodedTypeSourceInfo()); + if (!EncodedTypeInfo) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - EncodedType == E->getEncodedType()) + EncodedTypeInfo == E->getEncodedTypeSourceInfo()) return SemaRef.Owned(E->Retain()); return getDerived().RebuildObjCEncodeExpr(E->getAtLoc(), - EncodedType, + EncodedTypeInfo, E->getRParenLoc()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform arguments. + bool ArgChanged = false; + ASTOwningVector<&ActionBase::DeleteExpr> Args(SemaRef); + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + OwningExprResult Arg = getDerived().TransformExpr(E->getArg(I)); + if (Arg.isInvalid()) + return SemaRef.ExprError(); + + ArgChanged = ArgChanged || Arg.get() != E->getArg(I); + Args.push_back(Arg.takeAs<Expr>()); + } + + if (E->getReceiverKind() == ObjCMessageExpr::Class) { + // Class message: transform the receiver type. + TypeSourceInfo *ReceiverTypeInfo + = getDerived().TransformType(E->getClassReceiverTypeInfo()); + if (!ReceiverTypeInfo) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing message send. + if (!getDerived().AlwaysRebuild() && + ReceiverTypeInfo == E->getClassReceiverTypeInfo() && !ArgChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new class message send. + return getDerived().RebuildObjCMessageExpr(ReceiverTypeInfo, + E->getSelector(), + E->getMethodDecl(), + E->getLeftLoc(), + move_arg(Args), + E->getRightLoc()); + } + + // Instance message: transform the receiver + assert(E->getReceiverKind() == ObjCMessageExpr::Instance && + "Only class and instance messages may be instantiated"); + OwningExprResult Receiver + = getDerived().TransformExpr(E->getInstanceReceiver()); + if (Receiver.isInvalid()) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing message send. + if (!getDerived().AlwaysRebuild() && + Receiver.get() == E->getInstanceReceiver() && !ArgChanged) + return SemaRef.Owned(E->Retain()); + + // Build a new instance message send. + return getDerived().RebuildObjCMessageExpr(move(Receiver), + E->getSelector(), + E->getMethodDecl(), + E->getLeftLoc(), + move_arg(Args), + E->getRightLoc()); } template<typename Derived> @@ -5495,64 +5987,100 @@ TreeTransform<Derived>::TransformObjCSelectorExpr(ObjCSelectorExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { - ObjCProtocolDecl *Protocol - = cast_or_null<ObjCProtocolDecl>( - getDerived().TransformDecl(E->getLocStart(), - E->getProtocol())); - if (!Protocol) - return SemaRef.ExprError(); - - if (!getDerived().AlwaysRebuild() && - Protocol == E->getProtocol()) - return SemaRef.Owned(E->Retain()); - - return getDerived().RebuildObjCProtocolExpr(Protocol, - E->getAtLoc(), - /*FIXME:*/E->getAtLoc(), - /*FIXME:*/E->getAtLoc(), - E->getRParenLoc()); - + return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the ivar; it will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCIvarRefExpr(move(Base), E->getDecl(), + E->getLocation(), + E->isArrow(), E->isFreeIvar()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the property; it will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCPropertyRefExpr(move(Base), E->getProperty(), + E->getLocation()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // If this implicit setter/getter refers to class methods, it cannot have any + // dependent parts. Just retain the existing declaration. + if (E->getInterfaceDecl()) + return SemaRef.Owned(E->Retain()); + + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the getters/setters; they will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCImplicitSetterGetterRefExpr( + E->getGetterMethod(), + E->getType(), + E->getSetterMethod(), + E->getLocation(), + move(Base)); + } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); + // Can never occur in a dependent context. return SemaRef.Owned(E->Retain()); } template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCIsaExpr(move(Base), E->getIsaMemberLoc(), + E->isArrow()); } template<typename Derived> @@ -5632,14 +6160,6 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, template<typename Derived> QualType -TreeTransform<Derived>::RebuildObjCObjectPointerType(QualType PointeeType, - SourceLocation Sigil) { - return SemaRef.BuildPointerType(PointeeType, Qualifiers(), Sigil, - getDerived().getBaseEntity()); -} - -template<typename Derived> -QualType TreeTransform<Derived>::RebuildArrayType(QualType ElementType, ArrayType::ArraySizeModifier SizeMod, const llvm::APInt *Size, @@ -5767,6 +6287,7 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); + // FIXME: Doesn't account for ObjCInterfaceDecl! TypeDecl *Ty; if (isa<UsingDecl>(D)) { UsingDecl *Using = cast<UsingDecl>(D); |