diff options
Diffstat (limited to 'lib')
106 files changed, 3755 insertions, 3808 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 76ec852..c1bc709 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1200,43 +1200,58 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } -QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { +static QualType getNoReturnCallConvType(ASTContext& Context, QualType T, + bool AddNoReturn, + CallingConv CallConv) { QualType ResultType; if (const PointerType *Pointer = T->getAs<PointerType>()) { QualType Pointee = Pointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getPointerType(ResultType); + + ResultType = Context.getPointerType(ResultType); } else if (const BlockPointerType *BlockPointer = T->getAs<BlockPointerType>()) { QualType Pointee = BlockPointer->getPointeeType(); - ResultType = getNoReturnType(Pointee, AddNoReturn); + ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn, + CallConv); if (ResultType == Pointee) return T; - - ResultType = getBlockPointerType(ResultType); - } else if (const FunctionType *F = T->getAs<FunctionType>()) { - if (F->getNoReturnAttr() == AddNoReturn) + + ResultType = Context.getBlockPointerType(ResultType); + } else if (const FunctionType *F = T->getAs<FunctionType>()) { + if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv) return T; - + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) { - ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn); + ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(), + AddNoReturn, CallConv); } else { const FunctionProtoType *FPT = cast<FunctionProtoType>(F); ResultType - = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), - FPT->getNumArgs(), FPT->isVariadic(), - FPT->getTypeQuals(), - FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(), - FPT->getNumExceptions(), FPT->exception_begin(), - AddNoReturn); + = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), FPT->isVariadic(), + FPT->getTypeQuals(), + FPT->hasExceptionSpec(), + FPT->hasAnyExceptionSpec(), + FPT->getNumExceptions(), + FPT->exception_begin(), + AddNoReturn, CallConv); } } else return T; - - return getQualifiedType(ResultType, T.getLocalQualifiers()); + + return Context.getQualifiedType(ResultType, T.getLocalQualifiers()); +} + +QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) { + return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv()); +} + +QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) { + return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv); } /// getComplexType - Return the uniqued reference to the type for a complex @@ -1679,9 +1694,16 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } +static CallingConv getCanonicalCallingConv(CallingConv CC) { + if (CC == CC_C) + return CC_Default; + return CC; +} + /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// -QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1693,8 +1715,10 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) { return QualType(FT, 0); QualType Canonical; - if (!ResultTy.isCanonical()) { - Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn); + if (!ResultTy.isCanonical() || + getCanonicalCallingConv(CallConv) != CallConv) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1715,7 +1739,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, unsigned NumArgs, bool isVariadic, unsigned TypeQuals, bool hasExceptionSpec, bool hasAnyExceptionSpec, unsigned NumExs, - const QualType *ExArray, bool NoReturn) { + const QualType *ExArray, bool NoReturn, + CallingConv CallConv) { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1737,7 +1762,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical) { + if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { llvm::SmallVector<QualType, 16> CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1746,7 +1771,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, Canonical = getFunctionType(getCanonicalType(ResultTy), CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, - false, 0, 0, NoReturn); + false, 0, 0, NoReturn, + getCanonicalCallingConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -1763,7 +1789,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, NumExs*sizeof(QualType), TypeAlignment); new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, - ExArray, NumExs, Canonical, NoReturn); + ExArray, NumExs, Canonical, NoReturn, CallConv); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -2101,7 +2127,8 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT, // No Match; ObjCObjectPointerType *QType = new (*this, TypeAlignment) - ObjCObjectPointerType(Canonical, InterfaceT, Protocols, NumProtocols); + ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols, + NumProtocols); Types.push_back(QType); ObjCObjectPointerTypes.InsertNode(QType, InsertPos); @@ -2135,7 +2162,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl, } ObjCInterfaceType *QType = new (*this, TypeAlignment) - ObjCInterfaceType(Canonical, const_cast<ObjCInterfaceDecl*>(Decl), + ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl), Protocols, NumProtocols); Types.push_back(QType); @@ -3733,8 +3760,8 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { /// \brief Retrieve the template name that corresponds to a non-empty /// lookup. -TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, - NamedDecl * const *End) { +TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { unsigned size = End - Begin; assert(size > 1 && "set is not overloaded!"); @@ -3743,7 +3770,7 @@ TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin, OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); NamedDecl **Storage = OT->getStorage(); - for (NamedDecl * const *I = Begin; I != End; ++I) { + for (UnresolvedSetIterator I = Begin; I != End; ++I) { NamedDecl *D = *I; assert(isa<FunctionTemplateDecl>(D) || (isa<UsingShadowDecl>(D) && @@ -4211,6 +4238,10 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } +static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); +} + QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); @@ -4232,6 +4263,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { allLTypes = false; if (NoReturn != rbase->getNoReturnAttr()) allRTypes = false; + CallingConv lcc = lbase->getCallConv(); + CallingConv rcc = rbase->getCallConv(); + // Compatible functions must have compatible calling conventions + if (!isSameCallingConvention(lcc, rcc)) + return QualType(); if (lproto && rproto) { // two C99 style function prototypes assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && @@ -4267,7 +4303,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, types.begin(), types.size(), lproto->isVariadic(), lproto->getTypeQuals(), - NoReturn); + NoReturn, lcc); } if (lproto) allRTypes = false; @@ -4294,12 +4330,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { if (allRTypes) return rhs; return getFunctionType(retType, proto->arg_type_begin(), proto->getNumArgs(), proto->isVariadic(), - proto->getTypeQuals(), NoReturn); + proto->getTypeQuals(), NoReturn, lcc); } if (allLTypes) return lhs; if (allRTypes) return rhs; - return getFunctionNoProtoType(retType, NoReturn); + return getFunctionNoProtoType(retType, NoReturn, lcc); } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 92a58b7..7208328 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -145,7 +145,11 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { bool FoundPath = false; - + + // The access of the path down to this record. + AccessSpecifier AccessToHere = Paths.ScratchPath.Access; + bool IsFirstStep = Paths.ScratchPath.empty(); + ASTContext &Context = getASTContext(); for (base_class_const_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { @@ -189,10 +193,31 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, else Element.SubobjectNumber = Subobjects.second; Paths.ScratchPath.push_back(Element); + + // Calculate the "top-down" access to this base class. + // The spec actually describes this bottom-up, but top-down is + // equivalent because the definition works out as follows: + // 1. Write down the access along each step in the inheritance + // chain, followed by the access of the decl itself. + // For example, in + // class A { public: int foo; }; + // class B : protected A {}; + // class C : public B {}; + // class D : private C {}; + // we would write: + // private public protected public + // 2. If 'private' appears anywhere except far-left, access is denied. + // 3. Otherwise, overall access is determined by the most restrictive + // access in the sequence. + if (IsFirstStep) + Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier(); + else + Paths.ScratchPath.Access + = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { - // We've found a path that terminates that this base. + // We've found a path that terminates at this base. FoundPath = true; if (Paths.isRecordingPaths()) { // We have a path. Make a copy of it before moving on. @@ -223,13 +248,18 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // Pop this base specifier off the current path (if we're // collecting paths). - if (Paths.isRecordingPaths()) + if (Paths.isRecordingPaths()) { Paths.ScratchPath.pop_back(); + } + // If we set a virtual earlier, and this isn't a path, forget it again. if (SetVirtual && !FoundPath) { Paths.DetectedVirtual = 0; } } + + // Reset the scratch path access. + Paths.ScratchPath.Access = AccessToHere; return FoundPath; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e77661a..794b14a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -629,9 +629,13 @@ VarDecl::~VarDecl() { } SourceRange VarDecl::getSourceRange() const { + SourceLocation Start = getTypeSpecStartLoc(); + if (Start.isInvalid()) + Start = getLocation(); + if (getInit()) - return SourceRange(getLocation(), getInit()->getLocEnd()); - return SourceRange(getLocation(), getLocation()); + return SourceRange(Start, getInit()->getLocEnd()); + return SourceRange(Start, getLocation()); } bool VarDecl::isOutOfLine() const { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 3afb4e4..84aa81c 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -102,6 +102,17 @@ bool Decl::isFunctionOrFunctionTemplate() const { return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); } +bool Decl::isDefinedOutsideFunctionOrMethod() const { + for (const DeclContext *DC = getDeclContext(); + DC && !DC->isTranslationUnit(); + DC = DC->getParent()) + if (DC->isFunctionOrMethod()) + return false; + + return true; +} + + //===----------------------------------------------------------------------===// // PrettyStackTraceDecl Implementation //===----------------------------------------------------------------------===// @@ -399,8 +410,13 @@ SourceLocation Decl::getBodyRBrace() const { #ifndef NDEBUG void Decl::CheckAccessDeclContext() const { - // If the decl is the toplevel translation unit or if we're not in a - // record decl context, we don't need to check anything. + // Suppress this check if any of the following hold: + // 1. this is the translation unit (and thus has no parent) + // 2. this is a template parameter (and thus doesn't belong to its context) + // 3. this is a ParmVarDecl (which can be in a record context during + // the brief period between its creation and the creation of the + // FunctionDecl) + // 4. the context is not a record if (isa<TranslationUnitDecl>(this) || !isa<CXXRecordDecl>(getDeclContext())) return; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 1cce35c..fe6064d 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -312,8 +312,9 @@ void CXXRecordDecl::collectConversionFunctions( llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const { - const UnresolvedSet *Cs = getConversionFunctions(); - for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + const UnresolvedSetImpl *Cs = getConversionFunctions(); + for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); + I != E; ++I) { NamedDecl *TopConv = *I; CanQualType TConvType; if (FunctionTemplateDecl *TConversionTemplate = @@ -344,10 +345,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { - const UnresolvedSet *Cs + const UnresolvedSetImpl *Cs = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); - for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) { + for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end(); + I != E; ++I) { NamedDecl *Conv = *I; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. @@ -410,7 +412,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() { +const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { // If root class, all conversions are visible. if (bases_begin() == bases_end()) return &Conversions; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 2506f27..ffda505 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -37,6 +37,21 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { memcpy(List, InList, sizeof(void*)*Elts); } +void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx) { + if (Elts == 0) + return; + + Locations = new (Ctx) SourceLocation[Elts]; + memcpy(Locations, Locs, sizeof(SourceLocation) * Elts); + set(InList, Elts, Ctx); +} + +void ObjCProtocolList::Destroy(ASTContext &Ctx) { + Ctx.Deallocate(Locations); + Locations = 0; + ObjCList<ObjCProtocolDecl>::Destroy(Ctx); +} //===----------------------------------------------------------------------===// // ObjCInterfaceDecl @@ -141,16 +156,18 @@ ObjCContainerDecl::FindPropertyVisibleInPrimaryClass( void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + const SourceLocation *Locs, ASTContext &C) { if (ReferencedProtocols.empty()) { - ReferencedProtocols.set(ExtList, ExtNum, C); + ReferencedProtocols.set(ExtList, ExtNum, Locs, C); return; } // Check for duplicate protocol in class's protocol list. // This is (O)2. But it is extremely rare and number of protocols in // class or its extension are very few. llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; for (unsigned i = 0; i < ExtNum; i++) { bool protocolExists = false; ObjCProtocolDecl *ProtoInExtension = ExtList[i]; @@ -164,18 +181,23 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( } // Do we want to warn on a protocol in extension class which // already exist in the class? Probably not. - if (!protocolExists) + if (!protocolExists) { ProtocolRefs.push_back(ProtoInExtension); + ProtocolLocs.push_back(Locs[i]); + } } if (ProtocolRefs.empty()) return; // Merge ProtocolRefs into class's protocol list; + protocol_loc_iterator pl = protocol_loc_begin(); for (protocol_iterator p = protocol_begin(), e = protocol_end(); - p != e; p++) + p != e; ++p, ++pl) { ProtocolRefs.push_back(*p); + ProtocolLocs.push_back(*pl); + } ReferencedProtocols.Destroy(C); unsigned NumProtoRefs = ProtocolRefs.size(); - setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C); + setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C); } ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, @@ -627,9 +649,9 @@ SourceRange ObjCClassDecl::getSourceRange() const { ObjCForwardProtocolDecl:: ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, unsigned nElts, - ASTContext &C) + const SourceLocation *Locs, ASTContext &C) : Decl(ObjCForwardProtocol, DC, L) { - ReferencedProtocols.set(Elts, nElts, C); + ReferencedProtocols.set(Elts, nElts, Locs, C); } @@ -637,8 +659,9 @@ ObjCForwardProtocolDecl * ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, ObjCProtocolDecl *const *Elts, - unsigned NumElts) { - return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C); + unsigned NumElts, + const SourceLocation *Locs) { + return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C); } void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { @@ -651,9 +674,11 @@ void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { //===----------------------------------------------------------------------===// ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, IdentifierInfo *Id) { - return new (C) ObjCCategoryDecl(DC, L, Id); + return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id); } ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { @@ -765,9 +790,10 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation AtLoc, QualType T, PropertyControl propControl) { - return new (C) ObjCPropertyDecl(DC, L, Id, T); + return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 4c3046b..fa44b51 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -98,10 +98,12 @@ void DeclRefExpr::computeDependence() { // initialized with an expression that is value-dependent. else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { if (Var->getType()->isIntegralType() && - Var->getType().getCVRQualifiers() == Qualifiers::Const && - Var->getInit() && - Var->getInit()->isValueDependent()) - ValueDependent = true; + Var->getType().getCVRQualifiers() == Qualifiers::Const) { + const VarDecl *Def = 0; + if (const Expr *Init = Var->getDefinition(Def)) + if (Init->isValueDependent()) + ValueDependent = true; + } } // (TD) - a nested-name-specifier or a qualified-id that names a // member of an unknown specialization. diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 81584b7..a6574ef 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -135,10 +135,11 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, return ULE; } -bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin, - NamedDecl * const *End, - const TemplateArgumentListInfo *Args) { - for (NamedDecl * const *I = Begin; I != End; ++I) +bool UnresolvedLookupExpr:: + ComputeDependence(UnresolvedSetImpl::const_iterator Begin, + UnresolvedSetImpl::const_iterator End, + const TemplateArgumentListInfo *Args) { + for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) if ((*I)->getDeclContext()->isDependentContext()) return true; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index dfff209..086249c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -506,7 +506,9 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) { APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { if (E->isBuiltinCall(Info.Ctx) == - Builtin::BI__builtin___CFStringMakeConstantString) + Builtin::BI__builtin___CFStringMakeConstantString || + E->isBuiltinCall(Info.Ctx) == + Builtin::BI__builtin___NSStringMakeConstantString) return APValue(E); return APValue(); } @@ -971,6 +973,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_object_size: { const Expr *Arg = E->getArg(0)->IgnoreParens(); Expr::EvalResult Base; + + // TODO: Perhaps we should let LLVM lower this? if (Arg->EvaluateAsAny(Base, Info.Ctx) && Base.Val.getKind() == APValue::LValue && !Base.HasSideEffects) @@ -992,7 +996,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { } } - // TODO: Perhaps we should let LLVM lower this? + // If evaluating the argument has side-effects we can't determine + // the size of the object and lower it to unknown now. if (E->getArg(0)->HasSideEffects(Info.Ctx)) { if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1) return Success(-1ULL, E); diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index cfd89ea..0aa0180 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -119,6 +119,11 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, return; } } + if (i->isVirtual()) { + SelectPrimaryVBase(Base, FirstPrimary); + if (PrimaryBase.getBase()) + return; + } } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e0055f1..edfb580 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -339,6 +339,25 @@ const RecordType *Type::getAsUnionType() const { return 0; } +ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical, + ObjCInterfaceDecl *D, + ObjCProtocolDecl **Protos, unsigned NumP) : + Type(ObjCInterface, Canonical, /*Dependent=*/false), + Decl(D), Protocols(0), NumProtocols(NumP) +{ + if (NumProtocols) { + Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; + memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); + } +} + +void ObjCInterfaceType::Destroy(ASTContext& C) { + if (Protocols) + C.Deallocate(Protocols); + this->~ObjCInterfaceType(); + C.Deallocate(this); +} + const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCInterfaceType's, just return the canonical // type pointer if it is the right class. There is no typedef information to @@ -353,6 +372,26 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } +ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx, + QualType Canonical, QualType T, + ObjCProtocolDecl **Protos, + unsigned NumP) : + Type(ObjCObjectPointer, Canonical, /*Dependent=*/false), + PointeeType(T), Protocols(NULL), NumProtocols(NumP) +{ + if (NumProtocols) { + Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols]; + memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols)); + } +} + +void ObjCObjectPointerType::Destroy(ASTContext& C) { + if (Protocols) + C.Deallocate(Protocols); + this->~ObjCObjectPointerType(); + C.Deallocate(this); +} + const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 0840c52..fd9fbc1 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -14,6 +14,7 @@ #include "llvm/Support/raw_ostream.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/AST/Expr.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -135,3 +136,56 @@ SourceRange TypeOfExprTypeLoc::getSourceRange() const { return SourceRange(getTypeofLoc(), getUnderlyingExpr()->getSourceRange().getEnd()); } + + +TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type); + else { + switch (getTypePtr()->getKind()) { + case BuiltinType::Void: + return TST_void; + case BuiltinType::Bool: + return TST_bool; + case BuiltinType::Char_U: + case BuiltinType::Char_S: + return TST_char; + case BuiltinType::Char16: + return TST_char16; + case BuiltinType::Char32: + return TST_char32; + case BuiltinType::WChar: + return TST_wchar; + case BuiltinType::UndeducedAuto: + return TST_auto; + + case BuiltinType::UChar: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + llvm_unreachable("Builtin type needs extra local data!"); + // Fall through, if the impossible happens. + + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + return TST_unspecified; + } + } + + return TST_unspecified; +} diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 2093b5e..ad9f6dd 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -55,7 +55,7 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { CFG *AnalysisContext::getCFG() { if (!cfg) - cfg = CFG::buildCFG(getBody(), &D->getASTContext()); + cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges); return cfg; } diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp index 3d95ab1..49c8606 100644 --- a/lib/Analysis/ArrayBoundChecker.cpp +++ b/lib/Analysis/ArrayBoundChecker.cpp @@ -57,7 +57,8 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ // Get the size of the array. DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), + ER->getValueType(C.getASTContext())); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index eab7da7..5b8aeae 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -14,6 +14,7 @@ #include "clang/Analysis/Support/SaveAndRestore.h" #include "clang/Analysis/CFG.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/Support/GraphWriter.h" @@ -70,6 +71,7 @@ class CFGBuilder { CFGBlock* BreakTargetBlock; CFGBlock* SwitchTerminatedBlock; CFGBlock* DefaultCaseBlock; + CFGBlock* TryTerminatedBlock; // LabelMap records the mapping from Label expressions to their blocks. typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy; @@ -88,10 +90,12 @@ public: explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG Block(NULL), Succ(NULL), ContinueTargetBlock(NULL), BreakTargetBlock(NULL), - SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {} + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL), + TryTerminatedBlock(NULL) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(Stmt *Statement, ASTContext *C); + CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges, + bool AddScopes); private: // Visitors to walk an AST and construct the CFG. @@ -106,9 +110,9 @@ private: CFGBlock *VisitConditionalOperator(ConditionalOperator *C, AddStmtChoice asc); CFGBlock *VisitContinueStmt(ContinueStmt *C); - CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); } + CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S); CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); - CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); } + CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); CFGBlock *VisitDeclStmt(DeclStmt *DS); CFGBlock *VisitDeclSubExpr(Decl* D); CFGBlock *VisitDefaultStmt(DefaultStmt *D); @@ -139,6 +143,25 @@ private: return Block; } + CFGBlock *StartScope(Stmt *S, CFGBlock *B) { + if (!AddScopes) + return B; + + if (B == 0) + B = createBlock(); + B->StartScope(S, cfg->getBumpVectorContext()); + return B; + } + + void EndScope(Stmt *S) { + if (!AddScopes) + return; + + if (Block == 0) + Block = createBlock(); + Block->EndScope(S, cfg->getBumpVectorContext()); + } + void autoCreateBlock() { if (!Block) Block = createBlock(); } CFGBlock *createBlock(bool add_successor = true); bool FinishBlock(CFGBlock* B); @@ -186,6 +209,12 @@ private: } bool badCFG; + + // True iff EH edges on CallExprs should be added to the CFG. + bool AddEHEdges; + + // True iff scope start and scope end notes should be added to the CFG. + bool AddScopes; }; // FIXME: Add support for dependent-sized array types in C++? @@ -207,12 +236,15 @@ static VariableArrayType* FindVA(Type* t) { /// body (compound statement). The ownership of the returned CFG is /// transferred to the caller. If CFG construction fails, this method returns /// NULL. -CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { +CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, + bool addehedges, bool AddScopes) { + AddEHEdges = addehedges; Context = C; assert(cfg.get()); if (!Statement) return NULL; + this->AddScopes = AddScopes; badCFG = false; // Create an empty block that will serve as the exit block for the CFG. Since @@ -224,6 +256,11 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) { // Visit the statements and create the CFG. CFGBlock* B = addStmt(Statement); + + if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) { + // FIXME: Add code for base initializers and member initializers. + (void)CD; + } if (!B) B = Succ; @@ -329,6 +366,15 @@ tryAgain: case Stmt::ContinueStmtClass: return VisitContinueStmt(cast<ContinueStmt>(S)); + case Stmt::CXXCatchStmtClass: + return VisitCXXCatchStmt(cast<CXXCatchStmt>(S)); + + case Stmt::CXXThrowExprClass: + return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); + + case Stmt::CXXTryStmtClass: + return VisitCXXTryStmt(cast<CXXTryStmt>(S)); + case Stmt::DeclStmtClass: return VisitDeclStmt(cast<DeclStmt>(S)); @@ -356,9 +402,6 @@ tryAgain: case Stmt::ObjCAtCatchStmtClass: return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S)); - case Stmt::CXXThrowExprClass: - return VisitCXXThrowExpr(cast<CXXThrowExpr>(S)); - case Stmt::ObjCAtSynchronizedStmtClass: return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S)); @@ -456,7 +499,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); } else { - assert (B->getOpcode() == BinaryOperator::LAnd); + assert(B->getOpcode() == BinaryOperator::LAnd); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); } @@ -504,6 +547,22 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { return Block; } +static bool CanThrow(Expr *E) { + QualType Ty = E->getType(); + if (Ty->isFunctionPointerType()) + Ty = Ty->getAs<PointerType>()->getPointeeType(); + else if (Ty->isBlockPointerType()) + Ty = Ty->getAs<BlockPointerType>()->getPointeeType(); + + const FunctionType *FT = Ty->getAs<FunctionType>(); + if (FT) { + if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) + if (Proto->hasEmptyExceptionSpec()) + return false; + } + return true; +} + CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { // If this is a call to a no-return function, this stops the block here. bool NoReturn = false; @@ -511,22 +570,47 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { NoReturn = true; } - if (FunctionDecl *FD = C->getDirectCallee()) + bool AddEHEdge = false; + + // Languages without exceptions are assumed to not throw. + if (Context->getLangOptions().Exceptions) { + if (AddEHEdges) + AddEHEdge = true; + } + + if (FunctionDecl *FD = C->getDirectCallee()) { if (FD->hasAttr<NoReturnAttr>()) NoReturn = true; + if (FD->hasAttr<NoThrowAttr>()) + AddEHEdge = false; + } - if (!NoReturn) + if (!CanThrow(C->getCallee())) + AddEHEdge = false; + + if (!NoReturn && !AddEHEdge) return VisitStmt(C, asc); - if (Block && !FinishBlock(Block)) - return 0; + if (Block) { + Succ = Block; + if (!FinishBlock(Block)) + return 0; + } - // Create new block with no successor for the remaining pieces. - Block = createBlock(false); + Block = createBlock(!NoReturn); AppendStmt(Block, C, asc); - // Wire this to the exit block directly. - AddSuccessor(Block, &cfg->getExit()); + if (NoReturn) { + // Wire this to the exit block directly. + AddSuccessor(Block, &cfg->getExit()); + } + if (AddEHEdge) { + // Add exceptional edges. + if (TryTerminatedBlock) + AddSuccessor(Block, TryTerminatedBlock); + else + AddSuccessor(Block, &cfg->getExit()); + } return VisitChildren(C); } @@ -561,6 +645,8 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { + EndScope(C); + CFGBlock* LastBlock = Block; for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); @@ -570,6 +656,9 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { if (badCFG) return NULL; } + + LastBlock = StartScope(C, LastBlock); + return LastBlock; } @@ -743,7 +832,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { CFGBlock* ThenBlock; { Stmt* Then = I->getThen(); - assert (Then); + assert(Then); SaveAndRestore<CFGBlock*> sv(Succ); Block = NULL; ThenBlock = addStmt(Then); @@ -919,12 +1008,12 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { // Now create the loop body. { - assert (F->getBody()); + assert(F->getBody()); // Save the current values for Block, Succ, and continue and break targets SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); // Create a new block to contain the (bottom) of the loop body. Block = NULL; @@ -1252,8 +1341,12 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { // Create the new block. Block = createBlock(false); - // The Exit block is the only successor. - AddSuccessor(Block, &cfg->getExit()); + if (TryTerminatedBlock) + // The current try statement is the only successor. + AddSuccessor(Block, TryTerminatedBlock); + else + // otherwise the Exit block is the only successor. + AddSuccessor(Block, &cfg->getExit()); // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). @@ -1301,12 +1394,12 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { // Process the loop body. CFGBlock* BodyBlock = NULL; { - assert (D->getBody()); + assert(D->getBody()); // Save the current values for Block, Succ, and continue and break targets SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), - save_continue(ContinueTargetBlock), - save_break(BreakTargetBlock); + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); // All continues within this loop should go to the condition block ContinueTargetBlock = EntryConditionBlock; @@ -1434,7 +1527,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { // When visiting the body, the case statements should automatically get linked // up to the switch. We also don't keep a pointer to the body, since all // control-flow from the switch goes to case/default statements. - assert (Terminator->getBody() && "switch must contain a non-NULL body"); + assert(Terminator->getBody() && "switch must contain a non-NULL body"); Block = NULL; CFGBlock *BodyBlock = addStmt(Terminator->getBody()); if (Block) { @@ -1448,7 +1541,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { // Add the terminator and condition in the switch block. SwitchTerminatedBlock->setTerminator(Terminator); - assert (Terminator->getCond() && "switch condition must be non-NULL"); + assert(Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; Block = addStmt(Terminator->getCond()); @@ -1528,6 +1621,82 @@ CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { return DefaultCaseBlock; } +CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { + // "try"/"catch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock* TrySuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + TrySuccessor = Block; + } else TrySuccessor = Succ; + + CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock; + + // Create a new block that will contain the try statement. + CFGBlock *NewTryTerminatedBlock = createBlock(false); + // Add the terminator in the try block. + NewTryTerminatedBlock->setTerminator(Terminator); + + bool HasCatchAll = false; + for (unsigned h = 0; h <Terminator->getNumHandlers(); ++h) { + // The code after the try is the implicit successor. + Succ = TrySuccessor; + CXXCatchStmt *CS = Terminator->getHandler(h); + if (CS->getExceptionDecl() == 0) { + HasCatchAll = true; + } + Block = NULL; + CFGBlock *CatchBlock = VisitCXXCatchStmt(CS); + if (CatchBlock == 0) + return 0; + // Add this block to the list of successors for the block with the try + // statement. + AddSuccessor(NewTryTerminatedBlock, CatchBlock); + } + if (!HasCatchAll) { + if (PrevTryTerminatedBlock) + AddSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock); + else + AddSuccessor(NewTryTerminatedBlock, &cfg->getExit()); + } + + // The code after the try is the implicit successor. + Succ = TrySuccessor; + + // Save the current "try" context. + SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock); + TryTerminatedBlock = NewTryTerminatedBlock; + + assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); + Block = NULL; + Block = addStmt(Terminator->getTryBlock()); + return Block; +} + +CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { + // CXXCatchStmt are treated like labels, so they are the first statement in a + // block. + + if (CS->getHandlerBlock()) + addStmt(CS->getHandlerBlock()); + + CFGBlock* CatchBlock = Block; + if (!CatchBlock) + CatchBlock = createBlock(); + + CatchBlock->setLabel(CS); + + if (!FinishBlock(CatchBlock)) + return 0; + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + return CatchBlock; +} + CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { // Lazily create the indirect-goto dispatch block if there isn't one already. CFGBlock* IBlock = cfg->getIndirectGotoBlock(); @@ -1571,9 +1740,10 @@ CFGBlock* CFG::createBlock() { /// buildCFG - Constructs a CFG from an AST. Ownership of the returned /// CFG is returned to the caller. -CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) { +CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, + bool AddEHEdges, bool AddScopes) { CFGBuilder Builder; - return Builder.buildCFG(Statement, C); + return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes); } //===----------------------------------------------------------------------===// @@ -1661,9 +1831,7 @@ CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap); BlkExprMapTy::iterator I = M->find(S); - - if (I == M->end()) return CFG::BlkExprNumTy(); - else return CFG::BlkExprNumTy(I->second); + return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second); } unsigned CFG::getNumBlkExprs() { @@ -1692,7 +1860,6 @@ CFG::~CFG() { namespace { class StmtPrinterHelper : public PrinterHelper { - typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; StmtMapTy StmtMap; signed CurrentBlock; @@ -1724,10 +1891,11 @@ public: return false; if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock - && I->second.second == CurrentStmt) + && I->second.second == CurrentStmt) { return false; + } - OS << "[B" << I->second.first << "." << I->second.second << "]"; + OS << "[B" << I->second.first << "." << I->second.second << "]"; return true; } }; @@ -1741,7 +1909,6 @@ class CFGBlockTerminatorPrint llvm::raw_ostream& OS; StmtPrinterHelper* Helper; PrintingPolicy Policy; - public: CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper, const PrintingPolicy &Policy) @@ -1759,22 +1926,27 @@ public: void VisitForStmt(ForStmt* F) { OS << "for (" ; - if (F->getInit()) OS << "..."; + if (F->getInit()) + OS << "..."; OS << "; "; - if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = F->getCond()) + C->printPretty(OS, Helper, Policy); OS << "; "; - if (F->getInc()) OS << "..."; + if (F->getInc()) + OS << "..."; OS << ")"; } void VisitWhileStmt(WhileStmt* W) { OS << "while " ; - if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = W->getCond()) + C->printPretty(OS, Helper, Policy); } void VisitDoStmt(DoStmt* D) { OS << "do ... while "; - if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy); + if (Stmt* C = D->getCond()) + C->printPretty(OS, Helper, Policy); } void VisitSwitchStmt(SwitchStmt* Terminator) { @@ -1782,6 +1954,10 @@ public: Terminator->getCond()->printPretty(OS, Helper, Policy); } + void VisitCXXTryStmt(CXXTryStmt* CS) { + OS << "try ..."; + } + void VisitConditionalOperator(ConditionalOperator* C) { C->getCond()->printPretty(OS, Helper, Policy); OS << " ? ... : ..."; @@ -1826,7 +2002,18 @@ public: static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, - Stmt* Terminator) { + const CFGElement &E) { + Stmt *Terminator = E; + + if (E.asStartScope()) { + OS << "start scope\n"; + return; + } + if (E.asEndScope()) { + OS << "end scope\n"; + return; + } + if (Helper) { // special printing for statement-expressions. if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) { @@ -1876,14 +2063,14 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, OS << " ]\n"; // Print the label of this block. - if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) { + if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) { if (print_edges) OS << " "; - if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator)) + if (LabelStmt* L = dyn_cast<LabelStmt>(Label)) OS << L->getName(); - else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) { + else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) { OS << "case "; C->getLHS()->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); @@ -1892,9 +2079,18 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg, C->getRHS()->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); } - } else if (isa<DefaultStmt>(Terminator)) + } else if (isa<DefaultStmt>(Label)) OS << "default"; - else + else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) { + OS << "catch ("; + if (CS->getExceptionDecl()) + CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()), + 0); + else + OS << "..."; + OS << ")"; + + } else assert(false && "Invalid label statement in CFGBlock."); OS << ":\n"; diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp index a366342..219c09f 100644 --- a/lib/Analysis/CastToStructChecker.cpp +++ b/lib/Analysis/CastToStructChecker.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This files defines CastToStructChecker, a builtin checker that checks for -// assignment of a fixed address to a pointer. +// cast from non-struct pointer to struct pointer. // This check corresponds to CWE-588. // //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 40c12c9..8f8d859 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -2173,8 +2173,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst, bool asLValue){ +void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst, bool asLValue) { ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -2191,14 +2191,6 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet S2; CheckerVisit(CastE, S2, S1, true); - // Check for casting to "void". - if (T->isVoidType()) { - assert(!asLValue); - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) - Dst.Add(*I); - return; - } - // If we are evaluating the cast in an lvalue context, we implicitly want // the cast to evaluate to a location. if (asLValue) { @@ -2207,13 +2199,51 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); } - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode* N = *I; - const GRState* state = GetState(N); - SVal V = state->getSVal(Ex); - const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); - state = Res.getState()->BindExpr(CastE, Res.getSVal()); - MakeNode(Dst, CastE, N, state); + switch (CastE->getCastKind()) { + case CastExpr::CK_ToVoid: + assert(!asLValue); + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) + Dst.Add(*I); + return; + + case CastExpr::CK_NoOp: + case CastExpr::CK_FunctionToPointerDecay: + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + // Copy the SVal of Ex to CastE. + ExplodedNode *N = *I; + const GRState *state = GetState(N); + SVal V = state->getSVal(Ex); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, N, state); + } + return; + + case CastExpr::CK_Unknown: + case CastExpr::CK_ArrayToPointerDecay: + case CastExpr::CK_BitCast: + case CastExpr::CK_IntegralCast: + case CastExpr::CK_IntegralToPointer: + case CastExpr::CK_PointerToIntegral: + case CastExpr::CK_IntegralToFloating: + case CastExpr::CK_FloatingToIntegral: + case CastExpr::CK_FloatingCast: + case CastExpr::CK_AnyPointerToObjCPointerCast: + case CastExpr::CK_AnyPointerToBlockPointerCast: + case CastExpr::CK_DerivedToBase: + // Delegate to SValuator to process. + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + ExplodedNode* N = *I; + const GRState* state = GetState(N); + SVal V = state->getSVal(Ex); + const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy); + state = Res.getState()->BindExpr(CastE, Res.getSVal()); + MakeNode(Dst, CastE, N, state); + } + return; + + default: + llvm::errs() << "Cast kind " << CastE->getCastKind() << " not handled.\n"; + assert(0); } } @@ -2952,13 +2982,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // Perform a load (the LHS). This performs the checks for // null dereferences, and so on. - ExplodedNodeSet Tmp3; + ExplodedNodeSet Tmp4; SVal location = state->getSVal(LHS); - EvalLoad(Tmp3, LHS, *I2, state, location); + EvalLoad(Tmp4, LHS, *I2, state, location); - for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; - ++I3) { - state = GetState(*I3); + for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4; + ++I4) { + state = GetState(*I4); SVal V = state->getSVal(LHS); // Get the computation type. @@ -3008,7 +3038,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy); } - EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result), + EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result), location, LHSVal); } } diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp index fab73ee..28f4db7 100644 --- a/lib/Analysis/MallocChecker.cpp +++ b/lib/Analysis/MallocChecker.cpp @@ -72,7 +72,7 @@ public: private: void MallocMem(CheckerContext &C, const CallExpr *CE); const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state); + const Expr *SizeEx, const GRState *state); void FreeMem(CheckerContext &C, const CallExpr *CE); const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, const GRState *state); @@ -136,18 +136,24 @@ bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = MallocMemAux(C, CE, C.getState()); + const GRState *state = MallocMemAux(C, CE, CE->getArg(0), C.getState()); C.addTransition(state); } const GRState *MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, + const Expr *SizeEx, const GRState *state) { unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); ValueManager &ValMgr = C.getValueManager(); SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count); + SVal Size = state->getSVal(SizeEx); + + state = C.getEngine().getStoreManager().setExtent(state, RetVal.getAsRegion(), + Size); + state = state->BindExpr(CE, RetVal); SymbolRef Sym = RetVal.getAsLocSymbol(); @@ -170,7 +176,12 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, assert(Sym); const RefState *RS = state->get<RegionState>(Sym); - assert(RS); + + // If the symbol has not been tracked, return. This is possible when free() is + // called on a pointer that does not get its pointee directly from malloc(). + // Full support of this requires inter-procedural analysis. + if (!RS) + return state; // Check double free. if (RS->isReleased()) { @@ -211,7 +222,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { if (Sym) stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE)); - const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual); + const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), stateEqual); C.addTransition(stateMalloc); } @@ -232,7 +243,8 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero); if (stateFree) { // FIXME: We should copy the content of the original buffer. - const GRState *stateRealloc = MallocMemAux(C, CE, stateFree); + const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), + stateFree); C.addTransition(stateRealloc); } } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 9b5b44b..a735ed9 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -21,6 +21,7 @@ #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" +#include "clang/AST/CharUnits.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/ImmutableList.h" @@ -423,9 +424,9 @@ public: // Region "extents". //===------------------------------------------------------------------===// - const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent); + const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent); DefinedOrUnknownSVal getSizeInElements(const GRState *state, - const MemRegion* R); + const MemRegion* R, QualType EleTy); //===------------------------------------------------------------------===// // Utility methods. @@ -767,7 +768,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset, //===----------------------------------------------------------------------===// DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, - const MemRegion *R) { + const MemRegion *R, + QualType EleTy) { switch (R->getKind()) { case MemRegion::CXXThisRegionKind: @@ -793,10 +795,25 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, case MemRegion::ElementRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: - case MemRegion::SymbolicRegionKind: case MemRegion::CXXObjectRegionKind: return UnknownVal(); + case MemRegion::SymbolicRegionKind: { + const SVal *Size = state->get<RegionExtents>(R); + if (!Size) + return UnknownVal(); + const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(Size); + if (!CI) + return UnknownVal(); + + CharUnits RegionSize = + CharUnits::fromQuantity(CI->getValue().getSExtValue()); + CharUnits EleSize = getContext().getTypeSizeInChars(EleTy); + assert(RegionSize % EleSize == 0); + + return ValMgr.makeIntVal(RegionSize / EleSize, false); + } + case MemRegion::StringRegionKind: { const StringLiteral* Str = cast<StringRegion>(R)->getStringLiteral(); // We intentionally made the size value signed because it participates in diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp index ab0fcab..b0350cb 100644 --- a/lib/Analysis/ReturnPointerRangeChecker.cpp +++ b/lib/Analysis/ReturnPointerRangeChecker.cpp @@ -65,7 +65,8 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, // into a common place. DefinedOrUnknownSVal NumElements - = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion()); + = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), + ER->getValueType(C.getASTContext())); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index 5bd4314..f733578 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -17,10 +17,13 @@ BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +ifdef CLANG_VENDOR +CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +endif include $(LEVEL)/Makefile.common -SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion) +SVN_REVISION := $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..) CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \ -DSVN_REVISION='"$(SVN_REVISION)"' diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index bba2c3f..ea076ae 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -16,9 +16,9 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetOptions.h" -#include "clang/Frontend/Utils.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index ba31544..b1b250f 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -10,13 +10,17 @@ // This file defines several version-related utility functions for Clang. // //===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/Support/raw_ostream.h" #include <cstring> #include <cstdlib> + using namespace std; namespace clang { -const char *getClangSubversionPath() { +llvm::StringRef getClangRepositoryPath() { static const char *Path = 0; if (Path) return Path; @@ -41,13 +45,43 @@ const char *getClangSubversionPath() { } -unsigned getClangSubversionRevision() { +llvm::StringRef getClangRevision() { #ifndef SVN_REVISION // Subversion was not available at build time? - return 0; + return llvm::StringRef(); #else - return strtol(SVN_REVISION, 0, 10); + static std::string revision; + if (revision.empty()) { + llvm::raw_string_ostream OS(revision); + OS << strtol(SVN_REVISION, 0, 10); + } + return revision; #endif } +llvm::StringRef getClangFullRepositoryVersion() { + static std::string buf; + if (buf.empty()) { + llvm::raw_string_ostream OS(buf); + OS << getClangRepositoryPath(); + llvm::StringRef Revision = getClangRevision(); + if (!Revision.empty()) + OS << ' ' << Revision; + } + return buf; +} + +const char *getClangFullVersion() { + static std::string buf; + if (buf.empty()) { + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "clang version " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + } + return buf.c_str(); +} + } // end namespace clang diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 1fa422f..ca5b6fa 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -18,7 +18,6 @@ #include "llvm/Module.h" #include "llvm/Target/TargetData.h" #include <algorithm> -#include <cstdio> using namespace clang; using namespace CodeGen; @@ -221,11 +220,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantStruct::get(VMContext, Elts, false); - char Name[32]; - sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount()); C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, Name); + llvm::GlobalValue::InternalLinkage, C, + "__block_holder_tmp_" + + llvm::Twine(CGM.getGlobalUniqueCount())); QualType BPT = BE->getType(); C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); return C; @@ -747,13 +745,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(ResultType, Args); - std::string Name = std::string("__") + Info.Name + "_block_invoke_"; CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, + llvm::Twine("__") + Info.Name + "_block_invoke_", &CGM.getModule()); CGM.SetInternalFunctionAttributes(BD, Fn, FI); @@ -875,14 +872,12 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, // FIXME: We'd like to put these into a mergable by content, with // internal linkage. - std::string Name = std::string("__copy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__copy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_block_"); @@ -958,14 +953,12 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, // FIXME: We'd like to put these into a mergable by content, with // internal linkage. - std::string Name = std::string("__destroy_helper_block_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__destroy_helper_block_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__destroy_helper_block_"); @@ -1042,7 +1035,6 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); - std::string Name = std::string("__Block_byref_id_object_copy_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1050,8 +1042,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, - &CGM.getModule()); + "__Block_byref_id_object_copy_", &CGM.getModule()); IdentifierInfo *II = &CGM.getContext().Idents.get("__Block_byref_id_object_copy_"); @@ -1107,7 +1098,6 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); - std::string Name = std::string("__Block_byref_id_object_dispose_"); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1115,7 +1105,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - Name, + "__Block_byref_id_object_dispose_", &CGM.getModule()); IdentifierInfo *II diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 866c587..f11d52e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -72,6 +72,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, switch (BuiltinID) { default: break; // Handle intrinsics and libm functions below. case Builtin::BI__builtin___CFStringMakeConstantString: + case Builtin::BI__builtin___NSStringMakeConstantString: return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0)); case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: @@ -556,6 +557,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(0); } + case Builtin::BI__builtin_llvm_memory_barrier: { + Value *C[5] = { + EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1)), + EmitScalarExpr(E->getArg(2)), + EmitScalarExpr(E->getArg(3)), + EmitScalarExpr(E->getArg(4)) + }; + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5); + return RValue::get(0); + } + // Library functions with special handling. case Builtin::BIsqrt: case Builtin::BIsqrtf: diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index ab3fece..a822ca2 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -394,10 +394,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, if (BitwiseAssign) EmitAggregateCopy(Dest, Src, Ty); else { - bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign"); - (void)hasCopyAssign; + 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), @@ -410,8 +408,10 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, MD->getThisType(getContext()))); // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); + QualType SrcTy = MD->getParamDecl(0)->getType(); + RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : + RValue::getAggregate(Src); + CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), Callee, ReturnValueSlot(), CallArgs, MD); @@ -531,10 +531,8 @@ void CodeGenFunction::EmitClassCopyAssignment( } const CXXMethodDecl *MD = 0; - bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(), - MD); - assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign"); - (void)ConstCopyAssignOp; + BaseClassDecl->hasConstCopyAssignment(getContext(), MD); + assert(MD && "EmitClassCopyAssignment - missing copy assign"); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); const llvm::Type *LTy = @@ -548,8 +546,10 @@ void CodeGenFunction::EmitClassCopyAssignment( MD->getThisType(getContext()))); // Push the Src ptr. - CallArgs.push_back(std::make_pair(RValue::get(Src), - MD->getParamDecl(0)->getType())); + QualType SrcTy = MD->getParamDecl(0)->getType(); + RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : + RValue::getAggregate(Src); + CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index ab8f663..1ffad3e 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -460,58 +460,15 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, return DbgTy; } -/// CreateType - get structure or union type. -llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, - llvm::DICompileUnit Unit) { - RecordDecl *Decl = Ty->getDecl(); - - unsigned Tag; - if (Decl->isStruct()) - Tag = llvm::dwarf::DW_TAG_structure_type; - else if (Decl->isUnion()) - Tag = llvm::dwarf::DW_TAG_union_type; - else { - assert(Decl->isClass() && "Unknown RecordType!"); - Tag = llvm::dwarf::DW_TAG_class_type; - } - +/// CollectRecordFields - A helper function to collect debug info for +/// record fields. This is used while creating debug info entry for a Record. +void CGDebugInfo:: +CollectRecordFields(const RecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) { + unsigned FieldNo = 0; SourceManager &SM = CGM.getContext().getSourceManager(); - - // Get overall information about the record type for the debug info. - PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); - llvm::DICompileUnit DefUnit; - unsigned Line = 0; - if (!PLoc.isInvalid()) { - DefUnit = getOrCreateCompileUnit(Decl->getLocation()); - Line = PLoc.getLine(); - } - - // Records and classes and unions can all be recursive. To handle them, we - // first generate a debug descriptor for the struct as a forward declaration. - // Then (if it is a definition) we go through and get debug info for all of - // its members. Finally, we create a descriptor for the complete type (which - // may refer to the forward decl if the struct is recursive) and replace all - // uses of the forward declaration with the final definition. - llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), - DefUnit, Line, 0, 0, 0, 0, - llvm::DIType(), llvm::DIArray()); - - // If this is just a forward declaration, return it. - if (!Decl->getDefinition(CGM.getContext())) - return FwdDecl; - - llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); - // Otherwise, insert it into the TypeCache so that recursive uses will find - // it. - TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); - - // Convert all the elements. - llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; - const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl); - - unsigned FieldNo = 0; for (RecordDecl::field_iterator I = Decl->field_begin(), E = Decl->field_end(); I != E; ++I, ++FieldNo) { @@ -560,6 +517,125 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, FieldOffset, 0, FieldTy); EltTys.push_back(FieldTy); } +} + +/// CollectCXXMemberFunctions - A helper function to collect debug info for +/// C++ member functions.This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXMemberFunctions(const CXXRecordDecl *Decl, + llvm::DICompileUnit Unit, + llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys, + llvm::DICompositeType &RecordTy) { + SourceManager &SM = CGM.getContext().getSourceManager(); + for(CXXRecordDecl::method_iterator I = Decl->method_begin(), + E = Decl->method_end(); I != E; ++I) { + CXXMethodDecl *Method = *I; + llvm::StringRef MethodName; + llvm::StringRef MethodLinkageName; + llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit); + if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) { + if (CDecl->isImplicit()) + continue; + MethodName = Decl->getName(); + // FIXME : Find linkage name. + } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) { + if (DDecl->isImplicit()) + continue; + MethodName = getFunctionName(Method); + // FIXME : Find linkage name. + } else { + if (Method->isImplicit()) + continue; + // regular method + MethodName = getFunctionName(Method); + MethodLinkageName = CGM.getMangledName(Method); + } + + // Get the location for the method. + SourceLocation MethodDefLoc = Method->getLocation(); + PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc); + llvm::DICompileUnit MethodDefUnit; + unsigned MethodLine = 0; + + if (!PLoc.isInvalid()) { + MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc); + MethodLine = PLoc.getLine(); + } + + llvm::DISubprogram SP = + DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName, + MethodLinkageName, + MethodDefUnit, MethodLine, + MethodTy, false, + Method->isThisDeclarationADefinition(), + 0 /*Virtuality*/, 0 /*VIndex*/, + llvm::DIType() /*ContainingType*/); + if (Method->isThisDeclarationADefinition()) + SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode()); + EltTys.push_back(SP); + } +} + +/// CreateType - get structure or union type. +llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, + llvm::DICompileUnit Unit) { + RecordDecl *Decl = Ty->getDecl(); + + unsigned Tag; + if (Decl->isStruct()) + Tag = llvm::dwarf::DW_TAG_structure_type; + else if (Decl->isUnion()) + Tag = llvm::dwarf::DW_TAG_union_type; + else { + assert(Decl->isClass() && "Unknown RecordType!"); + Tag = llvm::dwarf::DW_TAG_class_type; + } + + SourceManager &SM = CGM.getContext().getSourceManager(); + + // Get overall information about the record type for the debug info. + PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation()); + llvm::DICompileUnit DefUnit; + unsigned Line = 0; + if (!PLoc.isInvalid()) { + DefUnit = getOrCreateCompileUnit(Decl->getLocation()); + Line = PLoc.getLine(); + } + + // Records and classes and unions can all be recursive. To handle them, we + // first generate a debug descriptor for the struct as a forward declaration. + // Then (if it is a definition) we go through and get debug info for all of + // its members. Finally, we create a descriptor for the complete type (which + // may refer to the forward decl if the struct is recursive) and replace all + // uses of the forward declaration with the final definition. + + // A Decl->getName() is not unique. However, the debug info descriptors + // are uniqued. The debug info descriptor describing record's context is + // necessary to keep two Decl's descriptor unique if their name match. + // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step + // use type's name in FwdDecl. + std::string STy = QualType(Ty, 0).getAsString(); + llvm::DICompositeType FwdDecl = + DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(), + DefUnit, Line, 0, 0, 0, 0, + llvm::DIType(), llvm::DIArray()); + + // If this is just a forward declaration, return it. + if (!Decl->getDefinition(CGM.getContext())) + return FwdDecl; + + llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode(); + // Otherwise, insert it into the TypeCache so that recursive uses will find + // it. + TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode(); + + // Convert all the elements. + llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; + + CollectRecordFields(Decl, Unit, EltTys); + if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl)) + CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl); llvm::DIArray Elements = DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); @@ -1000,18 +1076,27 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, const Decl *D = GD.getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If there is a DISubprogram for this function available then use it. + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + FI = SPCache.find(FD); + if (FI != SPCache.end()) { + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second)); + if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) { + RegionStack.push_back(SP.getNode()); + return; + } + } Name = getFunctionName(FD); - if (Name[0] == '\01') + if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. LinkageName = CGM.getMangledName(GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); - // Skip the asm prefix if it exists. - if (Name[0] == '\01') - Name = Name.substr(1); LinkageName = Name; + if (!Name.empty() && Name[0] == '\01') + Name = Name.substr(1); } // It is expected that CurLoc is set before using EmitFunctionStart. diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 8e88988..fddd23b 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -64,6 +64,8 @@ class CGDebugInfo { /// constructed on demand. For example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator FunctionNames; + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache; + /// Helper functions for getOrCreateType. llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U); llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U); @@ -85,6 +87,12 @@ class CGDebugInfo { llvm::DIType CreatePointerLikeType(unsigned Tag, const Type *Ty, QualType PointeeTy, llvm::DICompileUnit U); + void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, + llvm::DICompileUnit U, + llvm::SmallVectorImpl<llvm::DIDescriptor> &E, + llvm::DICompositeType &T); + void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U, + llvm::SmallVectorImpl<llvm::DIDescriptor> &E); public: CGDebugInfo(CodeGenModule &CGM); ~CGDebugInfo(); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index dec06e2..7d5b3da 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -742,7 +742,8 @@ public: return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E)); case Expr::ObjCStringLiteralClass: { ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E); - llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(SL); + llvm::Constant *C = + CGM.getObjCRuntime().GenerateConstantString(SL->getString()); return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } case Expr::PredefinedExprClass: { @@ -764,11 +765,18 @@ public: } case Expr::CallExprClass: { CallExpr* CE = cast<CallExpr>(E); - if (CE->isBuiltinCall(CGM.getContext()) != - Builtin::BI__builtin___CFStringMakeConstantString) + unsigned builtin = CE->isBuiltinCall(CGM.getContext()); + if (builtin != + Builtin::BI__builtin___CFStringMakeConstantString && + builtin != + Builtin::BI__builtin___NSStringMakeConstantString) break; const Expr *Arg = CE->getArg(0)->IgnoreParenCasts(); const StringLiteral *Literal = cast<StringLiteral>(Arg); + if (builtin == + Builtin::BI__builtin___NSStringMakeConstantString) { + return CGM.getObjCRuntime().GenerateConstantString(Literal); + } // FIXME: need to deal with UCN conversion issues. return CGM.GetAddrOfConstantCFString(Literal); } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index ac391d9..896d220 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -26,7 +26,8 @@ using namespace CodeGen; /// Emits an instance of NSConstantString representing the object. llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) { - llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E); + llvm::Constant *C = + CGM.getObjCRuntime().GenerateConstantString(E->getString()); // FIXME: This bitcast should just be made an invariant on the Runtime. return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType())); } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index e7a2093..77be9fb 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -124,7 +124,7 @@ private: void EmitClassRef(const std::string &className); public: CGObjCGNU(CodeGen::CodeGenModule &cgm); - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *); + virtual llvm::Constant *GenerateConstantString(const StringLiteral *); virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, QualType ResultType, @@ -240,15 +240,23 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) Zeros[1] = Zeros[0]; NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // Get the selector Type. - SelectorTy = cast<llvm::PointerType>( - CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType())); + QualType selTy = CGM.getContext().getObjCSelType(); + if (QualType() == selTy) { + SelectorTy = PtrToInt8Ty; + } else { + SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy)); + } PtrToIntTy = llvm::PointerType::getUnqual(IntTy); PtrTy = PtrToInt8Ty; // Object type ASTIdTy = CGM.getContext().getObjCIdType(); - IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + if (QualType() == ASTIdTy) { + IdTy = PtrToInt8Ty; + } else { + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + } // IMP type std::vector<const llvm::Type*> IMPArgs; @@ -348,12 +356,9 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, } /// Generate an NSConstantString object. -//TODO: In case there are any crazy people still using the GNU runtime without -//an OpenStep implementation, this should let them select their own class for -//constant strings. -llvm::Constant *CGObjCGNU::GenerateConstantString(const ObjCStringLiteral *SL) { - std::string Str(SL->getString()->getStrData(), - SL->getString()->getByteLength()); +llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { + std::string Str(SL->getStrData(), SL->getByteLength()); + std::vector<llvm::Constant*> Ivars; Ivars.push_back(NULLPtr); Ivars.push_back(MakeConstantString(Str)); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 727746f..137ea51 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -952,7 +952,7 @@ public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *SL); + virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL); virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD=0); @@ -1454,8 +1454,8 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl */ llvm::Constant *CGObjCCommonMac::GenerateConstantString( - const ObjCStringLiteral *SL) { - return CGM.GetAddrOfConstantCFString(SL->getString()); + const StringLiteral *SL) { + return CGM.GetAddrOfConstantCFString(SL); } /// Generates a message send where the super is the receiver. This is diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 6b45562..ff5d40b 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -106,7 +106,7 @@ public: const ObjCMethodDecl *Method) = 0; /// Generate a constant string object. - virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *) = 0; + virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0; /// Generate a category. A category contains a list of methods (and /// accompanying metadata) and a list of protocols. diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp new file mode 100644 index 0000000..9714bd9 --- /dev/null +++ b/lib/CodeGen/CGVTT.cpp @@ -0,0 +1,398 @@ +//===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with C++ code generation of VTTs (vtable tables). +// +//===----------------------------------------------------------------------===// + +#include "CodeGenModule.h" +#include "clang/AST/RecordLayout.h" +using namespace clang; +using namespace CodeGen; + +#define D1(x) + +namespace { +class VTTBuilder { + /// Inits - The list of values built for the VTT. + std::vector<llvm::Constant *> &Inits; + /// Class - The most derived class that this vtable is being built for. + const CXXRecordDecl *Class; + CodeGenModule &CGM; // Per-module state. + llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; + /// BLayout - Layout for the most derived class that this vtable is being + /// built for. + const ASTRecordLayout &BLayout; + CGVtableInfo::AddrMap_t &AddressPoints; + // vtbl - A pointer to the vtable for Class. + llvm::Constant *ClassVtbl; + llvm::LLVMContext &VMContext; + + /// SeenVBasesInSecondary - The seen virtual bases when building the + /// secondary virtual pointers. + llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary; + + llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; + + bool GenerateDefinition; + + llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; + llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> + CtorVtableAddressPoints; + + llvm::Constant *getCtorVtable(const BaseSubobject &Base) { + if (!GenerateDefinition) + return 0; + + llvm::Constant *&CtorVtable = CtorVtables[Base]; + if (!CtorVtable) { + // Build the vtable. + CGVtableInfo::CtorVtableInfo Info + = CGM.getVtableInfo().getCtorVtable(Class, Base); + + CtorVtable = Info.Vtable; + + // Add the address points for this base. + for (CGVtableInfo::AddressPointsMapTy::const_iterator I = + Info.AddressPoints.begin(), E = Info.AddressPoints.end(); + I != E; ++I) { + uint64_t &AddressPoint = + CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; + + // Check if we already have the address points for this base. + if (AddressPoint) + break; + + // Otherwise, insert it. + AddressPoint = I->second; + } + } + + return CtorVtable; + } + + + /// BuildVtablePtr - Build up a referene to the given secondary vtable + llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, + const CXXRecordDecl *VtableClass, + const CXXRecordDecl *RD, + uint64_t Offset) { + if (!GenerateDefinition) + return 0; + + uint64_t AddressPoint; + + if (VtableClass != Class) { + // We have a ctor vtable, look for the address point in the ctor vtable + // address points. + AddressPoint = + CtorVtableAddressPoints[std::make_pair(VtableClass, + BaseSubobject(RD, Offset))]; + } else { + AddressPoint = + (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; + } + + // FIXME: We can never have 0 address point. Do this for now so gepping + // retains the same structure. Later we'll just assert. + if (AddressPoint == 0) + AddressPoint = 1; + D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", + RD->getNameAsCString(), VtblClass->getNameAsCString(), + Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); + + llvm::Value *Idxs[] = { + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), + llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) + }; + + llvm::Constant *Init = + llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); + } + + /// Secondary - Add the secondary vtable pointers to Inits. Offset is the + /// current offset in bits to the object we're working on. + void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, + const CXXRecordDecl *VtblClass, uint64_t Offset=0, + bool MorallyVirtual=false) { + if (RD->getNumVBases() == 0 && ! MorallyVirtual) + return; + + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + // We only want to visit each virtual base once. + if (i->isVirtual() && SeenVBasesInSecondary.count(Base)) + continue; + + // Itanium C++ ABI 2.6.2: + // Secondary virtual pointers are present for all bases with either + // virtual bases or virtual function declarations overridden along a + // virtual path. + // + // If the base class is not dynamic, we don't want to add it, nor any + // of its base classes. + if (!Base->isDynamicClass()) + continue; + + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); + bool NonVirtualPrimaryBase; + NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; + bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); + uint64_t BaseOffset; + if (!i->isVirtual()) { + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + BaseOffset = Offset + Layout.getBaseClassOffset(Base); + } else + BaseOffset = BLayout.getVBaseClassOffset(Base); + llvm::Constant *subvtbl = vtbl; + const CXXRecordDecl *subVtblClass = VtblClass; + if ((Base->getNumVBases() || BaseMorallyVirtual) + && !NonVirtualPrimaryBase) { + llvm::Constant *init; + if (BaseMorallyVirtual || VtblClass == Class) + init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset); + else { + init = getCtorVtable(BaseSubobject(Base, BaseOffset)); + + subvtbl = init; + subVtblClass = Base; + + init = BuildVtablePtr(init, Class, Base, BaseOffset); + } + + Inits.push_back(init); + } + + if (i->isVirtual()) + SeenVBasesInSecondary.insert(Base); + + Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); + } + } + + /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the + /// currnet object we're working on. + void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { + // Itanium C++ ABI 2.6.2: + // An array of virtual table addresses, called the VTT, is declared for + // each class type that has indirect or direct virtual base classes. + if (RD->getNumVBases() == 0) + return; + + // Remember the sub-VTT index. + SubVTTIndicies[RD] = Inits.size(); + + llvm::Constant *Vtable; + const CXXRecordDecl *VtableClass; + + // First comes the primary virtual table pointer... + if (MorallyVirtual) { + Vtable = ClassVtbl; + VtableClass = Class; + } else { + Vtable = getCtorVtable(BaseSubobject(RD, Offset)); + VtableClass = RD; + } + + llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset); + Inits.push_back(Init); + + // then the secondary VTTs.... + SecondaryVTTs(RD, Offset, MorallyVirtual); + + // Make sure to clear the set of seen virtual bases. + SeenVBasesInSecondary.clear(); + + // and last the secondary vtable pointers. + Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); + } + + /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are + /// built from each direct non-virtual proper base that requires a VTT in + /// declaration order. + void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, + bool MorallyVirtual=false) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual()) + continue; + const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); + uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); + + BuildVTT(Base, BaseOffset, MorallyVirtual); + } + } + + /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance + /// graph preorder. + void VirtualVTTs(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (i->isVirtual() && !SeenVBase.count(Base)) { + SeenVBase.insert(Base); + uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); + BuildVTT(Base, BaseOffset, false); + } + VirtualVTTs(Base); + } + } + +public: + VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, + CodeGenModule &cgm, bool GenerateDefinition) + : Inits(inits), Class(c), CGM(cgm), + BLayout(cgm.getContext().getASTRecordLayout(c)), + AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), + VMContext(cgm.getModule().getContext()), + GenerateDefinition(GenerateDefinition) { + + // First comes the primary virtual table pointer for the complete class... + ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0; + + llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0); + Inits.push_back(Init); + + // then the secondary VTTs... + SecondaryVTTs(Class); + + // Make sure to clear the set of seen virtual bases. + SeenVBasesInSecondary.clear(); + + // then the secondary vtable pointers... + Secondary(Class, ClassVtbl, Class); + + // and last, the virtual VTTs. + VirtualVTTs(Class); + } + + llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { + return SubVTTIndicies; + } +}; +} + +llvm::GlobalVariable * +CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, + bool GenerateDefinition, + const CXXRecordDecl *RD) { + // Only classes that have virtual bases need a VTT. + if (RD->getNumVBases() == 0) + return 0; + + llvm::SmallString<256> OutName; + CGM.getMangleContext().mangleCXXVTT(RD, OutName); + llvm::StringRef Name = OutName.str(); + + D1(printf("vtt %s\n", RD->getNameAsCString())); + + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (GV == 0 || GV->isDeclaration()) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); + + std::vector<llvm::Constant *> inits; + VTTBuilder b(inits, RD, CGM, GenerateDefinition); + + const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); + llvm::Constant *Init = 0; + if (GenerateDefinition) + Init = llvm::ConstantArray::get(Type, inits); + + llvm::GlobalVariable *OldGV = GV; + GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, + Linkage, Init, Name); + CGM.setGlobalVisibility(GV, RD); + + if (OldGV) { + GV->takeName(OldGV); + llvm::Constant *NewPtr = + llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); + OldGV->replaceAllUsesWith(NewPtr); + OldGV->eraseFromParent(); + } + } + + return GV; +} + +CGVtableInfo::CtorVtableInfo +CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, + const BaseSubobject &Base) { + CtorVtableInfo Info; + + Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, + /*GenerateDefinition=*/true, + RD, Base.getBase(), Base.getBaseOffset(), + Info.AddressPoints); + return Info; +} + +llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { + return GenerateVTT(llvm::GlobalValue::ExternalLinkage, + /*GenerateDefinition=*/false, RD); + +} + + +bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { + const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); + + // We don't have any virtual bases, just return early. + if (!MD->getParent()->getNumVBases()) + return false; + + // Check if we have a base constructor. + if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) + return true; + + // Check if we have a base destructor. + if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) + return true; + + return false; +} + +uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, + const CXXRecordDecl *Base) { + ClassPairTy ClassPair(RD, Base); + + SubVTTIndiciesTy::iterator I = + SubVTTIndicies.find(ClassPair); + if (I != SubVTTIndicies.end()) + return I->second; + + std::vector<llvm::Constant *> inits; + VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); + + for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = + Builder.getSubVTTIndicies().begin(), + E = Builder.getSubVTTIndicies().end(); I != E; ++I) { + // Insert all indices. + ClassPairTy ClassPair(RD, I->first); + + SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); + } + + I = SubVTTIndicies.find(ClassPair); + assert(I != SubVTTIndicies.end() && "Did not find index!"); + + return I->second; +} diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index ae900d6..e5abfc6 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -232,8 +232,8 @@ public: return llvm::ConstantExpr::getBitCast(m, Ptr8Ty); } -#define D1(x) -//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) +//#define D1(x) +#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0) void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset, bool updateVBIndex, Index_t current_vbindex) { @@ -254,7 +254,7 @@ public: D1(printf(" vbase for %s at %d delta %d most derived %s\n", Base->getNameAsCString(), (int)-VCalls.size()-3, (int)BaseOffset, - Class->getNameAsCString())); + MostDerivedClass->getNameAsCString())); } // We also record offsets for non-virtual bases to closest enclosing // virtual base. We do this so that we don't have to search @@ -376,13 +376,14 @@ public: CurrentVBaseOffset)) return; + D1(printf(" vfn for %s at %d\n", + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + (int)Methods.size())); + // We didn't find an entry in the vtable that we could use, add a new // entry. Methods.AddMethod(GD); - D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(), - (int)Index[GD])); - VCallOffset[GD] = Offset/8; if (MorallyVirtual) { Index_t &idx = VCall[GD]; @@ -392,7 +393,8 @@ public: idx = VCalls.size()+1; VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d\n", - MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0)); + dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(), + (int)-VCalls.size()-3, 0)); } } } @@ -429,12 +431,11 @@ public: continue; const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (Base != PrimaryBase || PrimaryBaseWasVirtual) { - uint64_t o = Offset + Layout.getBaseClassOffset(Base); - StartNewTable(); - GenerateVtableForBase(Base, o, MorallyVirtual, false, - CurrentVBaseOffset, Path); - } + uint64_t o = Offset + Layout.getBaseClassOffset(Base); + StartNewTable(); + GenerateVtableForBase(Base, o, MorallyVirtual, false, + true, Base == PrimaryBase && !PrimaryBaseWasVirtual, + CurrentVBaseOffset, Path); } Path->pop_back(); } @@ -463,7 +464,7 @@ public: void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset, Index_t AddressPoint) { D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), Class->getNameAsCString(), + RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; @@ -480,7 +481,7 @@ public: BLayout.getVBaseClassOffset(RD) != Offset) break; D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n", - RD->getNameAsCString(), Class->getNameAsCString(), + RD->getNameAsCString(), MostDerivedClass->getNameAsCString(), LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint)); subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint; AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint; @@ -491,6 +492,7 @@ public: void FinishGenerateVtable(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, const CXXRecordDecl *PrimaryBase, + bool ForNPNVBases, bool WasPrimaryBase, bool PrimaryBaseWasVirtual, bool MorallyVirtual, int64_t Offset, bool ForVirtualBase, int64_t CurrentVBaseOffset, @@ -503,23 +505,27 @@ public: StartNewTable(); extra = 0; - bool DeferVCalls = MorallyVirtual || ForVirtualBase; - int VCallInsertionPoint = VtableComponents.size(); - if (!DeferVCalls) { - insertVCalls(VCallInsertionPoint); - } else - // FIXME: just for extra, or for all uses of VCalls.size post this? - extra = -VCalls.size(); + Index_t AddressPoint = 0; + int VCallInsertionPoint = 0; + if (!ForNPNVBases || !WasPrimaryBase) { + bool DeferVCalls = MorallyVirtual || ForVirtualBase; + VCallInsertionPoint = VtableComponents.size(); + if (!DeferVCalls) { + insertVCalls(VCallInsertionPoint); + } else + // FIXME: just for extra, or for all uses of VCalls.size post this? + extra = -VCalls.size(); - // Add the offset to top. - VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); + // Add the offset to top. + VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0); - // Add the RTTI information. - VtableComponents.push_back(rtti); + // Add the RTTI information. + VtableComponents.push_back(rtti); - Index_t AddressPoint = VtableComponents.size(); + AddressPoint = VtableComponents.size(); - AppendMethodsToVtable(); + AppendMethodsToVtable(); + } // and then the non-virtual bases. NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, @@ -537,7 +543,8 @@ public: insertVCalls(VCallInsertionPoint); } - AddAddressPoints(RD, Offset, AddressPoint); + if (!ForNPNVBases || !WasPrimaryBase) + AddAddressPoints(RD, Offset, AddressPoint); if (alloc) { delete Path; @@ -557,13 +564,13 @@ public: // vtables are composed from the chain of primaries. if (PrimaryBase && !PrimaryBaseWasVirtual) { D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, updateVBIndex, current_vbindex, CurrentVBaseOffset); } D1(printf(" doing vcall entries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); // And add the virtuals for the class to the primary vtable. AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset); @@ -589,7 +596,7 @@ public: } D1(printf(" doing primaries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset, updateVBIndex, current_vbindex, PrimaryBaseWasVirtual, @@ -597,7 +604,7 @@ public: } D1(printf(" doing vbase entries for %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex); if (RDisVirtualBase || bottom) { @@ -609,6 +616,8 @@ public: void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0, bool MorallyVirtual = false, bool ForVirtualBase = false, + bool ForNPNVBases = false, + bool WasPrimaryBase = true, int CurrentVBaseOffset = 0, Path_t *Path = 0) { if (!RD->isDynamicClass()) @@ -626,20 +635,22 @@ public: extra = 0; D1(printf("building entries for base %s most derived %s\n", - RD->getNameAsCString(), Class->getNameAsCString())); + RD->getNameAsCString(), MostDerivedClass->getNameAsCString())); if (ForVirtualBase) extra = VCalls.size(); - VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase, - CurrentVBaseOffset, true); + if (!ForNPNVBases || !WasPrimaryBase) { + VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, + ForVirtualBase, CurrentVBaseOffset, true); - if (Path) - OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); + if (Path) + OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset); + } - FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, - MorallyVirtual, Offset, ForVirtualBase, - CurrentVBaseOffset, Path); + FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase, + PrimaryBaseWasVirtual, MorallyVirtual, Offset, + ForVirtualBase, CurrentVBaseOffset, Path); } void GenerateVtableForVBases(const CXXRecordDecl *RD, @@ -665,9 +676,9 @@ public: int64_t BaseOffset = BLayout.getVBaseClassOffset(Base); int64_t CurrentVBaseOffset = BaseOffset; D1(printf("vtable %s virtual base %s\n", - Class->getNameAsCString(), Base->getNameAsCString())); - GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset, - Path); + MostDerivedClass->getNameAsCString(), Base->getNameAsCString())); + GenerateVtableForBase(Base, BaseOffset, true, true, false, + true, CurrentVBaseOffset, Path); } int64_t BaseOffset; if (i->isVirtual()) @@ -823,14 +834,14 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, VCalls.push_back(0); D1(printf(" vcall for %s at %d with delta %d most derived %s\n", MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); + (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); } else { NonVirtualOffset[GD] = NonVirtualOffset[OGD]; VCallOffset[GD] = VCallOffset[OGD]; VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8; D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n", MD->getNameAsString().c_str(), (int)-idx-3, - (int)VCalls[idx-1], Class->getNameAsCString())); + (int)VCalls[idx-1], MostDerivedClass->getNameAsCString())); } int64_t NonVirtualAdjustment = NonVirtualOffset[GD]; int64_t VirtualAdjustment = @@ -1205,284 +1216,6 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, return GV; } -namespace { -class VTTBuilder { - /// Inits - The list of values built for the VTT. - std::vector<llvm::Constant *> &Inits; - /// Class - The most derived class that this vtable is being built for. - const CXXRecordDecl *Class; - CodeGenModule &CGM; // Per-module state. - llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase; - /// BLayout - Layout for the most derived class that this vtable is being - /// built for. - const ASTRecordLayout &BLayout; - CGVtableInfo::AddrMap_t &AddressPoints; - // vtbl - A pointer to the vtable for Class. - llvm::Constant *ClassVtbl; - llvm::LLVMContext &VMContext; - - llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies; - - bool GenerateDefinition; - - llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables; - llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t> - CtorVtableAddressPoints; - - llvm::Constant *getCtorVtable(const BaseSubobject &Base) { - if (!GenerateDefinition) - return 0; - - llvm::Constant *&CtorVtable = CtorVtables[Base]; - if (!CtorVtable) { - // Build the vtable. - CGVtableInfo::CtorVtableInfo Info - = CGM.getVtableInfo().getCtorVtable(Class, Base); - - CtorVtable = Info.Vtable; - - // Add the address points for this base. - for (CGVtableInfo::AddressPointsMapTy::const_iterator I = - Info.AddressPoints.begin(), E = Info.AddressPoints.end(); - I != E; ++I) { - uint64_t &AddressPoint = - CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)]; - - // Check if we already have the address points for this base. - if (AddressPoint) - break; - - // Otherwise, insert it. - AddressPoint = I->second; - } - } - - return CtorVtable; - } - - - /// BuildVtablePtr - Build up a referene to the given secondary vtable - llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable, - const CXXRecordDecl *VtableClass, - const CXXRecordDecl *RD, - uint64_t Offset) { - int64_t AddressPoint = - (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)]; - - // FIXME: We can never have 0 address point. Do this for now so gepping - // retains the same structure. Later we'll just assert. - if (AddressPoint == 0) - AddressPoint = 1; - D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n", - RD->getNameAsCString(), VtblClass->getNameAsCString(), - Class->getNameAsCString(), (int)Offset, (int)AddressPoint)); - - llvm::Value *Idxs[] = { - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0), - llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint) - }; - - llvm::Constant *Init = - llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy); - } - - /// Secondary - Add the secondary vtable pointers to Inits. Offset is the - /// current offset in bits to the object we're working on. - void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl, - const CXXRecordDecl *VtblClass, uint64_t Offset=0, - bool MorallyVirtual=false) { - if (RD->getNumVBases() == 0 && ! MorallyVirtual) - return; - - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); - bool NonVirtualPrimaryBase; - NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase; - bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual(); - uint64_t BaseOffset; - if (!i->isVirtual()) { - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - BaseOffset = Offset + Layout.getBaseClassOffset(Base); - } else - BaseOffset = BLayout.getVBaseClassOffset(Base); - llvm::Constant *subvtbl = vtbl; - const CXXRecordDecl *subVtblClass = VtblClass; - if ((Base->getNumVBases() || BaseMorallyVirtual) - && !NonVirtualPrimaryBase) { - // FIXME: Slightly too many of these for __ZTT8test8_B2 - llvm::Constant *init; - if (BaseMorallyVirtual) - init = GenerateDefinition ? - BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0; - else { - init = GenerateDefinition ? - getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0; - - subvtbl = init; - subVtblClass = Base; - - init = GenerateDefinition ? - BuildVtablePtr(init, Class, Base, BaseOffset) : 0; - } - Inits.push_back(init); - } - Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual); - } - } - - /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the - /// currnet object we're working on. - void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) { - if (RD->getNumVBases() == 0 && !MorallyVirtual) - return; - - llvm::Constant *Vtable; - const CXXRecordDecl *VtableClass; - - // First comes the primary virtual table pointer... - if (MorallyVirtual) { - Vtable = GenerateDefinition ? ClassVtbl : 0; - VtableClass = Class; - } else { - Vtable = GenerateDefinition ? - getCtorVtable(BaseSubobject(RD, Offset)) : 0; - VtableClass = RD; - } - - llvm::Constant *Init = GenerateDefinition ? - BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0; - Inits.push_back(Init); - - // then the secondary VTTs.... - SecondaryVTTs(RD, Offset, MorallyVirtual); - - // and last the secondary vtable pointers. - Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual); - } - - /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are - /// built from each direct non-virtual proper base that requires a VTT in - /// declaration order. - void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0, - bool MorallyVirtual=false) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual()) - continue; - const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base); - - // Remember the sub-VTT index. - SubVTTIndicies[Base] = Inits.size(); - - BuildVTT(Base, BaseOffset, MorallyVirtual); - } - } - - /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance - /// graph preorder. - void VirtualVTTs(const CXXRecordDecl *RD) { - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (i->isVirtual() && !SeenVBase.count(Base)) { - // Remember the sub-VTT index. - SubVTTIndicies[Base] = Inits.size(); - - SeenVBase.insert(Base); - uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base); - BuildVTT(Base, BaseOffset, true); - } - VirtualVTTs(Base); - } - } - -public: - VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c, - CodeGenModule &cgm, bool GenerateDefinition) - : Inits(inits), Class(c), CGM(cgm), - BLayout(cgm.getContext().getASTRecordLayout(c)), - AddressPoints(*cgm.getVtableInfo().AddressPoints[c]), - VMContext(cgm.getModule().getContext()), - GenerateDefinition(GenerateDefinition) { - - // First comes the primary virtual table pointer for the complete class... - ClassVtbl = CGM.getVtableInfo().getVtable(Class); - llvm::Constant *Init = GenerateDefinition ? - BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0; - Inits.push_back(Init); - - // then the secondary VTTs... - SecondaryVTTs(Class); - - // then the secondary vtable pointers... - Secondary(Class, ClassVtbl, Class); - - // and last, the virtual VTTs. - VirtualVTTs(Class); - } - - llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() { - return SubVTTIndicies; - } -}; -} - -llvm::GlobalVariable * -CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, - bool GenerateDefinition, - const CXXRecordDecl *RD) { - // Only classes that have virtual bases need a VTT. - if (RD->getNumVBases() == 0) - return 0; - - llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTT(RD, OutName); - llvm::StringRef Name = OutName.str(); - - D1(printf("vtt %s\n", RD->getNameAsCString())); - - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (GV == 0 || GV->isDeclaration()) { - const llvm::Type *Int8PtrTy = - llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); - - std::vector<llvm::Constant *> inits; - VTTBuilder b(inits, RD, CGM, GenerateDefinition); - - const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size()); - llvm::Constant *Init = 0; - if (GenerateDefinition) - Init = llvm::ConstantArray::get(Type, inits); - - llvm::GlobalVariable *OldGV = GV; - GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true, - Linkage, Init, Name); - CGM.setGlobalVisibility(GV, RD); - - if (OldGV) { - GV->takeName(OldGV); - llvm::Constant *NewPtr = - llvm::ConstantExpr::getBitCast(GV, OldGV->getType()); - OldGV->replaceAllUsesWith(NewPtr); - OldGV->eraseFromParent(); - } - } - - return GV; -} - void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { llvm::GlobalVariable *&Vtable = Vtables[RD]; @@ -1510,25 +1243,6 @@ llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) { return Vtable; } -CGVtableInfo::CtorVtableInfo -CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD, - const BaseSubobject &Base) { - CtorVtableInfo Info; - - Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage, - /*GenerateDefinition=*/true, - RD, Base.getBase(), Base.getBaseOffset(), - Info.AddressPoints); - return Info; -} - -llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) { - return GenerateVTT(llvm::GlobalValue::ExternalLinkage, - /*GenerateDefinition=*/false, RD); - -} - - void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXRecordDecl *RD = MD->getParent(); @@ -1562,47 +1276,3 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { } } -bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); - - // We don't have any virtual bases, just return early. - if (!MD->getParent()->getNumVBases()) - return false; - - // Check if we have a base constructor. - if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base) - return true; - - // Check if we have a base destructor. - if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) - return true; - - return false; -} - -uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD, - const CXXRecordDecl *Base) { - ClassPairTy ClassPair(RD, Base); - - SubVTTIndiciesTy::iterator I = - SubVTTIndicies.find(ClassPair); - if (I != SubVTTIndicies.end()) - return I->second; - - std::vector<llvm::Constant *> inits; - VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false); - - for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I = - Builder.getSubVTTIndicies().begin(), - E = Builder.getSubVTTIndicies().end(); I != E; ++I) { - // Insert all indices. - ClassPairTy ClassPair(RD, I->first); - - SubVTTIndicies.insert(std::make_pair(ClassPair, I->second)); - } - - I = SubVTTIndicies.find(ClassPair); - assert(I != SubVTTIndicies.end() && "Did not find index!"); - - return I->second; -} diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 45469d3..e72a1d9 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangCodeGen CGStmt.cpp CGTemporaries.cpp CGVtable.cpp + CGVTT.cpp CodeGenFunction.cpp CodeGenModule.cpp CodeGenTypes.cpp diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5ecc30e..cf504a7 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -67,6 +67,15 @@ CodeGenModule::~CodeGenModule() { delete DebugInfo; } +void CodeGenModule::createObjCRuntime() { + if (!Features.NeXTRuntime) + Runtime = CreateGNUObjCRuntime(*this); + else if (Features.ObjCNonFragileABI) + Runtime = CreateMacNonFragileABIObjCRuntime(*this); + else + Runtime = CreateMacObjCRuntime(*this); +} + void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c7aa7a4..81f3979 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -161,6 +161,9 @@ class CodeGenModule : public BlockModule { /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; + /// Lazily create the Objective-C runtime + void createObjCRuntime(); + llvm::LLVMContext &VMContext; public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, @@ -174,7 +177,7 @@ public: /// getObjCRuntime() - Return a reference to the configured /// Objective-C runtime. CGObjCRuntime &getObjCRuntime() { - assert(Runtime && "No Objective-C runtime has been configured."); + if (!Runtime) createObjCRuntime(); return *Runtime; } diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp deleted file mode 100644 index 863a297..0000000 --- a/lib/CodeGen/TargetABIInfo.cpp +++ /dev/null @@ -1,1821 +0,0 @@ -//===---- TargetABIInfo.cpp - Encapsulate target ABI details ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// These classes wrap the information about a call or function -// definition used to handle ABI compliancy. -// -//===----------------------------------------------------------------------===// - -#include "ABIInfo.h" -#include "CodeGenFunction.h" -#include "clang/AST/RecordLayout.h" -#include "llvm/Type.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; -using namespace CodeGen; - -ABIInfo::~ABIInfo() {} - -void ABIArgInfo::dump() const { - llvm::raw_ostream &OS = llvm::errs(); - OS << "(ABIArgInfo Kind="; - switch (TheKind) { - case Direct: - OS << "Direct"; - break; - case Extend: - OS << "Extend"; - break; - case Ignore: - OS << "Ignore"; - break; - case Coerce: - OS << "Coerce Type="; - getCoerceToType()->print(OS); - break; - case Indirect: - OS << "Indirect Align=" << getIndirectAlign(); - break; - case Expand: - OS << "Expand"; - break; - } - OS << ")\n"; -} - -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); - -/// isEmptyField - Return true iff a the field is "empty", that is it -/// is an unnamed bit-field or an (array of) empty record(s). -static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, - bool AllowArrays) { - if (FD->isUnnamedBitfield()) - return true; - - QualType FT = FD->getType(); - - // Constant arrays of empty records count as empty, strip them off. - if (AllowArrays) - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) - FT = AT->getElementType(); - - return isEmptyRecord(Context, FT, AllowArrays); -} - -/// isEmptyRecord - Return true iff a structure contains only empty -/// fields. Note that a structure with a flexible array member is not -/// considered empty. -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return 0; - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) - if (!isEmptyField(Context, *i, AllowArrays)) - return false; - return true; -} - -/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either -/// a non-trivial destructor or a non-trivial copy constructor. -static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { - const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); - if (!RD) - return false; - - return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor(); -} - -/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is -/// a record type with either a non-trivial destructor or a non-trivial copy -/// constructor. -static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) { - const RecordType *RT = T->getAs<RecordType>(); - if (!RT) - return false; - - return hasNonTrivialDestructorOrCopyConstructor(RT); -} - -/// isSingleElementStruct - Determine if a structure is a "single -/// element struct", i.e. it has exactly one non-empty field or -/// exactly one field which is itself a single element -/// struct. Structures with flexible array members are never -/// considered single element structs. -/// -/// \return The field declaration for the single non-empty field, if -/// it exists. -static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { - const RecordType *RT = T->getAsStructureType(); - if (!RT) - return 0; - - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return 0; - - const Type *Found = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // Ignore empty fields. - if (isEmptyField(Context, FD, true)) - continue; - - // If we already found an element then this isn't a single-element - // struct. - if (Found) - return 0; - - // Treat single element arrays as the element. - while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { - if (AT->getSize().getZExtValue() != 1) - break; - FT = AT->getElementType(); - } - - if (!CodeGenFunction::hasAggregateLLVMType(FT)) { - Found = FT.getTypePtr(); - } else { - Found = isSingleElementStruct(FT, Context); - if (!Found) - return 0; - } - } - - return Found; -} - -static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { - if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() && - !Ty->isAnyComplexType() && !Ty->isEnumeralType() && - !Ty->isBlockPointerType()) - return false; - - uint64_t Size = Context.getTypeSize(Ty); - return Size == 32 || Size == 64; -} - -/// canExpandIndirectArgument - Test whether an argument type which is to be -/// passed indirectly (on the stack) would have the equivalent layout if it was -/// expanded into separate arguments. If so, we prefer to do the latter to avoid -/// inhibiting optimizations. -/// -// FIXME: This predicate is missing many cases, currently it just follows -// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We -// should probably make this smarter, or better yet make the LLVM backend -// capable of handling it. -static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) { - // We can only expand structure types. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) - return false; - - // We can only expand (C) structures. - // - // FIXME: This needs to be generalized to handle classes as well. - const RecordDecl *RD = RT->getDecl(); - if (!RD->isStruct() || isa<CXXRecordDecl>(RD)) - return false; - - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - - if (!is32Or64BitBasicType(FD->getType(), Context)) - return false; - - // FIXME: Reject bit-fields wholesale; there are two problems, we don't know - // how to expand them yet, and the predicate for telling if a bitfield still - // counts as "basic" is more complicated than what we were doing previously. - if (FD->isBitField()) - return false; - } - - return true; -} - -static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) { - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - - if (FD->getType()->isVectorType() && - Context.getTypeSize(FD->getType()) >= 128) - return true; - - if (const RecordType* RT = FD->getType()->getAs<RecordType>()) - if (typeContainsSSEVector(RT->getDecl(), Context)) - return true; - } - - return false; -} - -namespace { -/// DefaultABIInfo - The default implementation for ABI specific -/// details. This implementation provides information which results in -/// self-consistent and sensible LLVM IR generation, but does not -/// conform to any particular ABI. -class DefaultABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -/// X86_32ABIInfo - The X86-32 ABI information. -class X86_32ABIInfo : public ABIInfo { - ASTContext &Context; - bool IsDarwinVectorABI; - bool IsSmallStructInRegABI; - - static bool isRegisterSize(unsigned Size) { - return (Size == 8 || Size == 16 || Size == 32 || Size == 64); - } - - static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context); - - static unsigned getIndirectArgumentAlignment(QualType Ty, - ASTContext &Context); - -public: - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; - - X86_32ABIInfo(ASTContext &Context, bool d, bool p) - : ABIInfo(), Context(Context), IsDarwinVectorABI(d), - IsSmallStructInRegABI(p) {} -}; -} - - -/// shouldReturnTypeInRegister - Determine if the given type should be -/// passed in a register (for the Darwin ABI). -bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, - ASTContext &Context) { - uint64_t Size = Context.getTypeSize(Ty); - - // Type must be register sized. - if (!isRegisterSize(Size)) - return false; - - if (Ty->isVectorType()) { - // 64- and 128- bit vectors inside structures are not returned in - // registers. - if (Size == 64 || Size == 128) - return false; - - return true; - } - - // If this is a builtin, pointer, enum, or complex type, it is ok. - if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() || - Ty->isAnyComplexType() || Ty->isEnumeralType() || - Ty->isBlockPointerType()) - return true; - - // Arrays are treated like records. - if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) - return shouldReturnTypeInRegister(AT->getElementType(), Context); - - // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) return false; - - // Structure types are passed in register if all fields would be - // passed in a register. - for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(), - e = RT->getDecl()->field_end(); i != e; ++i) { - const FieldDecl *FD = *i; - - // Empty fields are ignored. - if (isEmptyField(Context, FD, true)) - continue; - - // Check fields recursively. - if (!shouldReturnTypeInRegister(FD->getType(), Context)) - return false; - } - - return true; -} - -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (const VectorType *VT = RetTy->getAs<VectorType>()) { - // On Darwin, some vectors are returned in registers. - if (IsDarwinVectorABI) { - uint64_t Size = Context.getTypeSize(RetTy); - - // 128-bit vectors are a special case; they are returned in - // registers and we need to make sure to pick a type the LLVM - // backend will like. - if (Size == 128) - return ABIArgInfo::getCoerce(llvm::VectorType::get( - llvm::Type::getInt64Ty(VMContext), 2)); - - // Always return in register if it fits in a general purpose - // register, or if it is 64 bits and has a single element. - if ((Size == 8 || Size == 16 || Size == 32) || - (Size == 64 && VT->getNumElements() == 1)) - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); - - return ABIArgInfo::getIndirect(0); - } - - return ABIArgInfo::getDirect(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - if (const RecordType *RT = RetTy->getAsStructureType()) { - // 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); - - // Structures with flexible arrays are always indirect. - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(0); - } - - // If specified, structs and unions are always indirect. - if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) - return ABIArgInfo::getIndirect(0); - - // Classify "single element" structs as their element type. - if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { - if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) { - if (BT->isIntegerType()) { - // We need to use the size of the structure, padding - // bit-fields can adjust that to be larger than the single - // element type. - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce( - llvm::IntegerType::get(VMContext, (unsigned) Size)); - } else if (BT->getKind() == BuiltinType::Float) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext)); - } else if (BT->getKind() == BuiltinType::Double) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && - "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext)); - } - } else if (SeltTy->isPointerType()) { - // FIXME: It would be really nice if this could come out as the proper - // pointer type. - const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return ABIArgInfo::getCoerce(PtrTy); - } else if (SeltTy->isVectorType()) { - // 64- and 128-bit vectors are never returned in a - // register when inside a structure. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size == 64 || Size == 128) - return ABIArgInfo::getIndirect(0); - - return classifyReturnType(QualType(SeltTy, 0), Context, VMContext); - } - } - - // Small structures which are register sized are generally returned - // in a register. - if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); - } - - return ABIArgInfo::getIndirect(0); - } else { - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -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::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - // FIXME: Set alignment on indirect arguments. - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - // Structures with flexible arrays are always indirect. - if (const RecordType *RT = Ty->getAsStructureType()) - if (RT->getDecl()->hasFlexibleArrayMember()) - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, - Context)); - - // Ignore empty structs. - if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) - return ABIArgInfo::getIgnore(); - - // Expand small (<= 128-bit) record types when we know that the stack layout - // of those arguments will match the struct. This is important because the - // LLVM backend isn't smart enough to remove byval, which inhibits many - // optimizations. - if (Context.getTypeSize(Ty) <= 4*32 && - canExpandIndirectArgument(Ty, Context)) - return ABIArgInfo::getExpand(); - - return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context)); - } else { - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -namespace { -/// X86_64ABIInfo - The X86_64 ABI information. -class X86_64ABIInfo : public ABIInfo { - enum Class { - Integer = 0, - SSE, - SSEUp, - X87, - X87Up, - ComplexX87, - NoClass, - Memory - }; - - /// merge - Implement the X86_64 ABI merging algorithm. - /// - /// Merge an accumulating classification \arg Accum with a field - /// classification \arg Field. - /// - /// \param Accum - The accumulating classification. This should - /// always be either NoClass or the result of a previous merge - /// call. In addition, this should never be Memory (the caller - /// should just return Memory for the aggregate). - Class merge(Class Accum, Class Field) const; - - /// classify - Determine the x86_64 register classes in which the - /// given type T should be passed. - /// - /// \param Lo - The classification for the parts of the type - /// residing in the low word of the containing object. - /// - /// \param Hi - The classification for the parts of the type - /// residing in the high word of the containing object. - /// - /// \param OffsetBase - The bit offset of this type in the - /// containing object. Some parameters are classified different - /// depending on whether they straddle an eightbyte boundary. - /// - /// If a word is unused its result will be NoClass; if a type should - /// be passed in Memory then at least the classification of \arg Lo - /// will be Memory. - /// - /// The \arg Lo class will be NoClass iff the argument is ignored. - /// - /// If the \arg Lo class is ComplexX87, then the \arg Hi class will - /// also be ComplexX87. - void classify(QualType T, ASTContext &Context, uint64_t OffsetBase, - Class &Lo, Class &Hi) const; - - /// getCoerceResult - Given a source type \arg Ty and an LLVM type - /// to coerce to, chose the best way to pass Ty in the same place - /// that \arg CoerceTo would be passed, but while keeping the - /// emitted code as simple as possible. - /// - /// FIXME: Note, this should be cleaned up to just take an enumeration of all - /// the ways we might want to pass things, instead of constructing an LLVM - /// type. This makes this code more explicit, and it makes it clearer that we - /// are also doing this for correctness in the case of passing scalar types. - ABIArgInfo getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - 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 classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE) const; - -public: - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; -} - -X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, - Class Field) const { - // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is - // classified recursively so that always two fields are - // considered. The resulting class is calculated according to - // the classes of the fields in the eightbyte: - // - // (a) If both classes are equal, this is the resulting class. - // - // (b) If one of the classes is NO_CLASS, the resulting class is - // the other class. - // - // (c) If one of the classes is MEMORY, the result is the MEMORY - // class. - // - // (d) If one of the classes is INTEGER, the result is the - // INTEGER. - // - // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, - // MEMORY is used as class. - // - // (f) Otherwise class SSE is used. - - // Accum should never be memory (we should have returned) or - // ComplexX87 (because this cannot be passed in a structure). - assert((Accum != Memory && Accum != ComplexX87) && - "Invalid accumulated classification during merge."); - if (Accum == Field || Field == NoClass) - return Accum; - else if (Field == Memory) - return Memory; - else if (Accum == NoClass) - return Field; - else if (Accum == Integer || Field == Integer) - return Integer; - else if (Field == X87 || Field == X87Up || Field == ComplexX87 || - Accum == X87 || Accum == X87Up) - return Memory; - else - return SSE; -} - -void X86_64ABIInfo::classify(QualType Ty, - ASTContext &Context, - uint64_t OffsetBase, - Class &Lo, Class &Hi) const { - // FIXME: This code can be simplified by introducing a simple value class for - // Class pairs with appropriate constructor methods for the various - // situations. - - // FIXME: Some of the split computations are wrong; unaligned vectors - // shouldn't be passed in registers for example, so there is no chance they - // can straddle an eightbyte. Verify & simplify. - - Lo = Hi = NoClass; - - Class &Current = OffsetBase < 64 ? Lo : Hi; - Current = Memory; - - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { - BuiltinType::Kind k = BT->getKind(); - - if (k == BuiltinType::Void) { - Current = NoClass; - } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { - Lo = Integer; - Hi = Integer; - } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { - Current = Integer; - } else if (k == BuiltinType::Float || k == BuiltinType::Double) { - Current = SSE; - } else if (k == BuiltinType::LongDouble) { - Lo = X87; - Hi = X87Up; - } - // FIXME: _Decimal32 and _Decimal64 are SSE. - // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). - } else if (const EnumType *ET = Ty->getAs<EnumType>()) { - // Classify the underlying integer type. - classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi); - } else if (Ty->hasPointerRepresentation()) { - Current = Integer; - } else if (const VectorType *VT = Ty->getAs<VectorType>()) { - uint64_t Size = Context.getTypeSize(VT); - if (Size == 32) { - // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x - // float> as integer. - Current = Integer; - - // If this type crosses an eightbyte boundary, it should be - // split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Size - 1) / 64; - if (EB_Real != EB_Imag) - Hi = Lo; - } else if (Size == 64) { - // gcc passes <1 x double> in memory. :( - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) - return; - - // gcc passes <1 x long long> as INTEGER. - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) - Current = Integer; - else - Current = SSE; - - // If this type crosses an eightbyte boundary, it should be - // split. - if (OffsetBase && OffsetBase != 64) - Hi = Lo; - } else if (Size == 128) { - Lo = SSE; - Hi = SSEUp; - } - } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) { - QualType ET = Context.getCanonicalType(CT->getElementType()); - - uint64_t Size = Context.getTypeSize(Ty); - if (ET->isIntegralType()) { - if (Size <= 64) - Current = Integer; - else if (Size <= 128) - Lo = Hi = Integer; - } else if (ET == Context.FloatTy) - Current = SSE; - else if (ET == Context.DoubleTy) - Lo = Hi = SSE; - else if (ET == Context.LongDoubleTy) - Current = ComplexX87; - - // If this complex type crosses an eightbyte boundary then it - // should be split. - uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; - if (Hi == NoClass && EB_Real != EB_Imag) - Hi = Lo; - } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { - // Arrays are treated like structures. - - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Only need to check alignment of array base. - if (OffsetBase % Context.getTypeAlign(AT->getElementType())) - return; - - // Otherwise implement simplified merge. We could be smarter about - // this, but it isn't worth it and would be harder to verify. - Current = NoClass; - uint64_t EltSize = Context.getTypeSize(AT->getElementType()); - uint64_t ArraySize = AT->getSize().getZExtValue(); - for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) { - Class FieldLo, FieldHi; - classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // Do post merger cleanup (see below). Only case we worry about is Memory. - if (Hi == Memory) - Lo = Memory; - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); - } else if (const RecordType *RT = Ty->getAs<RecordType>()) { - uint64_t Size = Context.getTypeSize(Ty); - - // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger - // than two eightbytes, ..., it has class MEMORY. - if (Size > 128) - return; - - // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial - // copy constructor or a non-trivial destructor, it is passed by invisible - // reference. - if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return; - - const RecordDecl *RD = RT->getDecl(); - - // Assume variable sized types are passed in memory. - if (RD->hasFlexibleArrayMember()) - return; - - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - // Reset Lo class, this will be recomputed. - Current = NoClass; - - // If this is a C++ record, classify the bases first. - if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { - for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), - e = CXXRD->bases_end(); i != e; ++i) { - assert(!i->isVirtual() && !i->getType()->isDependentType() && - "Unexpected base class!"); - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - - // Classify this field. - // - // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a - // single eightbyte, each is classified separately. Each eightbyte gets - // initialized to class NO_CLASS. - Class FieldLo, FieldHi; - uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base); - classify(i->getType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // If this record has no fields but isn't empty, classify as INTEGER. - if (RD->field_empty() && Size) - Current = Integer; - } - - // Classify the fields one at a time, merging the results. - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i, ++idx) { - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - bool BitField = i->isBitField(); - - // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned - // fields, it has class MEMORY. - // - // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % Context.getTypeAlign(i->getType())) { - Lo = Memory; - return; - } - - // Classify this field. - // - // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate - // exceeds a single eightbyte, each is classified - // separately. Each eightbyte gets initialized to class - // NO_CLASS. - Class FieldLo, FieldHi; - - // Bit-fields require special handling, they do not force the - // structure to be passed in memory even if unaligned, and - // therefore they can straddle an eightbyte. - if (BitField) { - // Ignore padding bit-fields. - if (i->isUnnamedBitfield()) - continue; - - uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); - - uint64_t EB_Lo = Offset / 64; - uint64_t EB_Hi = (Offset + Size - 1) / 64; - FieldLo = FieldHi = NoClass; - if (EB_Lo) { - assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); - FieldLo = NoClass; - FieldHi = Integer; - } else { - FieldLo = Integer; - FieldHi = EB_Hi ? Integer : NoClass; - } - } else - classify(i->getType(), Context, Offset, FieldLo, FieldHi); - Lo = merge(Lo, FieldLo); - Hi = merge(Hi, FieldHi); - if (Lo == Memory || Hi == Memory) - break; - } - - // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: - // - // (a) If one of the classes is MEMORY, the whole argument is - // passed in memory. - // - // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. - - // The first of these conditions is guaranteed by how we implement - // the merge (just bail). - // - // The second condition occurs in the case of unions; for example - // union { _Complex double; unsigned; }. - if (Hi == Memory) - Lo = Memory; - if (Hi == SSEUp && Lo != SSE) - Hi = SSE; - } -} - -ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo, - ASTContext &Context) const { - if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) { - // Integer and pointer types will end up in a general purpose - // register. - if (Ty->isIntegralType() || Ty->hasPointerRepresentation()) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) { - // FIXME: It would probably be better to make CGFunctionInfo only map using - // canonical types than to canonize here. - QualType CTy = Context.getCanonicalType(Ty); - - // Float and double end up in a single SSE reg. - if (CTy == Context.FloatTy || CTy == Context.DoubleTy) - return ABIArgInfo::getDirect(); - - } - - return ABIArgInfo::getCoerce(CoerceTo); -} - -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 - // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty); - - // FIXME: Set alignment correctly. - return ABIArgInfo::getIndirect(0, ByVal); -} - -ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the - // classification algorithm. - X86_64ABIInfo::Class Lo, Hi; - classify(RetTy, Context, 0, Lo, Hi); - - // Check some invariants. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via - // hidden argument. - case Memory: - return getIndirectResult(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. - case Integer: - ResType = llvm::Type::getInt64Ty(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next - // available SSE register of the sequence %xmm0, %xmm1 is used. - case SSE: - ResType = llvm::Type::getDoubleTy(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is - // returned on the X87 stack in %st0 as 80-bit x87 number. - case X87: - ResType = llvm::Type::getX86_FP80Ty(VMContext); break; - - // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real - // part of the value is returned in %st0 and the imaginary part in - // %st1. - case ComplexX87: - assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); - ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext), - llvm::Type::getX86_FP80Ty(VMContext), - NULL); - break; - } - - switch (Hi) { - // Memory was handled previously and X87 should - // never occur as a hi class. - case Memory: - case X87: - assert(0 && "Invalid classification for hi word."); - - case ComplexX87: // Previously handled. - case NoClass: break; - - case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); - break; - case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - break; - - // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte - // is passed in the upper half of the last used SSE register. - // - // SSEUP should always be preceeded by SSE, just widen. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); - break; - - // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is - // returned together with the previous X87 value in %st0. - case X87Up: - // If X87Up is preceeded by X87, we don't need to do - // anything. However, in some cases with unions it may not be - // preceeded by X87. In such situations we follow gcc and pass the - // extra bits in an SSE reg. - if (Lo != X87) - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - break; - } - - return getCoerceResult(RetTy, ResType, Context); -} - -ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE) const { - X86_64ABIInfo::Class Lo, Hi; - classify(Ty, Context, 0, Lo, Hi); - - // Check some invariants. - // FIXME: Enforce these by construction. - assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); - assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); - - neededInt = 0; - neededSSE = 0; - const llvm::Type *ResType = 0; - switch (Lo) { - case NoClass: - return ABIArgInfo::getIgnore(); - - // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument - // on the stack. - case Memory: - - // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or - // COMPLEX_X87, it is passed in memory. - case X87: - case ComplexX87: - return getIndirectResult(Ty, Context); - - case SSEUp: - case X87Up: - assert(0 && "Invalid classification for lo word."); - - // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next - // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 - // and %r9 is used. - case Integer: - ++neededInt; - ResType = llvm::Type::getInt64Ty(VMContext); - break; - - // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next - // available SSE register is used, the registers are taken in the - // order from %xmm0 to %xmm7. - case SSE: - ++neededSSE; - ResType = llvm::Type::getDoubleTy(VMContext); - break; - } - - switch (Hi) { - // Memory was handled previously, ComplexX87 and X87 should - // never occur as hi classes, and X87Up must be preceed by X87, - // which is passed in memory. - case Memory: - case X87: - case ComplexX87: - assert(0 && "Invalid classification for hi word."); - break; - - case NoClass: break; - case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); - ++neededInt; - break; - - // X87Up generally doesn't occur here (long double is passed in - // memory), except in situations involving unions. - case X87Up: - case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); - ++neededSSE; - break; - - // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the - // eightbyte is passed in the upper half of the last used SSE - // register. - case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); - break; - } - - return getCoerceResult(Ty, ResType, Context); -} - -void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), - Context, VMContext); - - // Keep track of the number of assigned registers. - unsigned freeIntRegs = 6, freeSSERegs = 8; - - // If the return value is indirect, then the hidden argument is consuming one - // integer register. - if (FI.getReturnInfo().isIndirect()) - --freeIntRegs; - - // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers - // get assigned (in left-to-right order) for passing as follows... - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - unsigned neededInt, neededSSE; - it->info = classifyArgumentType(it->type, Context, VMContext, - neededInt, neededSSE); - - // AMD64-ABI 3.2.3p3: If there are no registers available for any - // eightbyte of an argument, the whole argument is passed on the - // stack. If registers have already been assigned for some - // eightbytes of such an argument, the assignments get reverted. - if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) { - freeIntRegs -= neededInt; - freeSSERegs -= neededSSE; - } else { - it->info = getIndirectResult(it->type, Context); - } - } -} - -static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr, - QualType Ty, - CodeGenFunction &CGF) { - llvm::Value *overflow_arg_area_p = - CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); - llvm::Value *overflow_arg_area = - CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); - - // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 - // byte boundary if alignment needed by type exceeds 8 byte boundary. - uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; - if (Align > 8) { - // Note that we follow the ABI & gcc here, even though the type - // could in theory have an alignment greater than 16. This case - // shouldn't ever matter in practice. - - // overflow_arg_area = (overflow_arg_area + 15) & ~15; - llvm::Value *Offset = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset); - llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area, - llvm::Type::getInt64Ty(CGF.getLLVMContext())); - llvm::Value *Mask = llvm::ConstantInt::get( - llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL); - overflow_arg_area = - CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask), - overflow_arg_area->getType(), - "overflow_arg_area.align"); - } - - // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *Res = - CGF.Builder.CreateBitCast(overflow_arg_area, - llvm::PointerType::getUnqual(LTy)); - - // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: - // l->overflow_arg_area + sizeof(type). - // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to - // an 8 byte boundary. - - uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; - llvm::Value *Offset = - llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), - (SizeInBytes + 7) & ~7); - overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, - "overflow_arg_area.next"); - CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); - - // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. - return Res; -} - -llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - llvm::LLVMContext &VMContext = CGF.getLLVMContext(); - const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext); - const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext); - - // Assume that va_list type is correct; should be pointer to LLVM type: - // struct { - // i32 gp_offset; - // i32 fp_offset; - // i8* overflow_arg_area; - // i8* reg_save_area; - // }; - unsigned neededInt, neededSSE; - ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext, - neededInt, neededSSE); - - // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed - // in the registers. If not go to step 7. - if (!neededInt && !neededSSE) - return EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of - // general purpose registers needed to pass type and num_fp to hold - // the number of floating point registers needed. - - // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into - // registers. In the case: l->gp_offset > 48 - num_gp * 8 or - // l->fp_offset > 304 - num_fp * 16 go to step 7. - // - // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of - // register save space). - - llvm::Value *InRegs = 0; - llvm::Value *gp_offset_p = 0, *gp_offset = 0; - llvm::Value *fp_offset_p = 0, *fp_offset = 0; - if (neededInt) { - gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); - gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); - InRegs = - CGF.Builder.CreateICmpULE(gp_offset, - llvm::ConstantInt::get(i32Ty, - 48 - neededInt * 8), - "fits_in_gp"); - } - - if (neededSSE) { - fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); - fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); - llvm::Value *FitsInFP = - CGF.Builder.CreateICmpULE(fp_offset, - llvm::ConstantInt::get(i32Ty, - 176 - neededSSE * 16), - "fits_in_fp"); - InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; - } - - llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); - llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); - llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); - CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); - - // Emit code to load the value if it was passed in registers. - - CGF.EmitBlock(InRegBlock); - - // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with - // an offset of l->gp_offset and/or l->fp_offset. This may require - // copying to a temporary location in case the parameter is passed - // in different register classes or requires an alignment greater - // than 8 for general purpose registers and 16 for XMM registers. - // - // FIXME: This really results in shameful code when we end up needing to - // collect arguments from different places; often what should result in a - // simple assembling of a structure from scattered addresses has many more - // loads than necessary. Can we clean this up? - const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); - llvm::Value *RegAddr = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3), - "reg_save_area"); - if (neededInt && neededSSE) { - // FIXME: Cleanup. - assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); - const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType()); - llvm::Value *Tmp = CGF.CreateTempAlloca(ST); - assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); - const llvm::Type *TyLo = ST->getElementType(0); - const llvm::Type *TyHi = ST->getElementType(1); - assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) && - "Unexpected ABI info for mixed regs"); - const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); - const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); - llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr; - llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr; - llvm::Value *V = - CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - - RegAddr = CGF.Builder.CreateBitCast(Tmp, - llvm::PointerType::getUnqual(LTy)); - } else if (neededInt) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - if (neededSSE == 1) { - RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset); - RegAddr = CGF.Builder.CreateBitCast(RegAddr, - llvm::PointerType::getUnqual(LTy)); - } else { - assert(neededSSE == 2 && "Invalid number of needed registers!"); - // SSE registers are spaced 16 bytes apart in the register save - // area, we need to collect the two eightbytes together. - llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset); - llvm::Value *RegAddrHi = - CGF.Builder.CreateGEP(RegAddrLo, - llvm::ConstantInt::get(i32Ty, 16)); - const llvm::Type *DblPtrTy = - llvm::PointerType::getUnqual(DoubleTy); - const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy, - DoubleTy, NULL); - llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); - V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi, - DblPtrTy)); - CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); - RegAddr = CGF.Builder.CreateBitCast(Tmp, - llvm::PointerType::getUnqual(LTy)); - } - } - - // AMD64-ABI 3.5.7p5: Step 5. Set: - // l->gp_offset = l->gp_offset + num_gp * 8 - // l->fp_offset = l->fp_offset + num_fp * 16. - if (neededInt) { - llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), - gp_offset_p); - } - if (neededSSE) { - llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16); - CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), - fp_offset_p); - } - CGF.EmitBranch(ContBlock); - - // Emit code to load the value if it was passed in memory. - - CGF.EmitBlock(InMemBlock); - llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF); - - // Return the appropriate result. - - CGF.EmitBlock(ContBlock); - llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), - "vaarg.addr"); - ResAddr->reserveOperandSpace(2); - ResAddr->addIncoming(RegAddr, InRegBlock); - ResAddr->addIncoming(MemAddr, InMemBlock); - - return ResAddr; -} - -// PIC16 ABI Implementation - -namespace { - -class PIC16ABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else { - return ABIArgInfo::getDirect(); - } -} - -ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - return ABIArgInfo::getDirect(); -} - -llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -// ARM ABI Implementation - -namespace { - -class ARMABIInfo : public ABIInfo { -public: - enum ABIKind { - APCS = 0, - AAPCS = 1, - AAPCS_VFP - }; - -private: - ABIKind Kind; - -public: - ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {} - -private: - ABIKind getABIKind() const { return Kind; } - - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMCOntext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - // ARM always overrides the calling convention. - switch (getABIKind()) { - case APCS: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS); - break; - - case AAPCS: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS); - break; - - case AAPCS_VFP: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP); - break; - } -} - -ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Ignore empty records. - if (isEmptyRecord(Context, Ty, true)) - return ABIArgInfo::getIgnore(); - - // FIXME: This is kind of nasty... but there isn't much choice because the ARM - // backend doesn't support byval. - // FIXME: This doesn't handle alignment > 64 bits. - const llvm::Type* ElemTy; - unsigned SizeRegs; - if (Context.getTypeAlign(Ty) > 32) { - ElemTy = llvm::Type::getInt64Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; - } else { - ElemTy = llvm::Type::getInt32Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; - } - std::vector<const llvm::Type*> LLVMFields; - LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); - const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true); - return ABIArgInfo::getCoerce(STy); -} - -static bool isIntegerLikeType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) { - // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure - // is called integer-like if its size is less than or equal to one word, and - // the offset of each of its addressable sub-fields is zero. - - uint64_t Size = Context.getTypeSize(Ty); - - // Check that the type fits in a word. - if (Size > 32) - return false; - - // FIXME: Handle vector types! - if (Ty->isVectorType()) - return false; - - // Float types are never treated as "integer like". - if (Ty->isRealFloatingType()) - return false; - - // If this is a builtin or pointer type then it is ok. - if (Ty->getAs<BuiltinType>() || Ty->isPointerType()) - return true; - - // Complex types "should" be ok by the definition above, but they are not. - if (Ty->isAnyComplexType()) - return false; - - // Single element and zero sized arrays should be allowed, by the definition - // above, but they are not. - - // Otherwise, it must be a record type. - const RecordType *RT = Ty->getAs<RecordType>(); - if (!RT) return false; - - // Ignore records with flexible arrays. - const RecordDecl *RD = RT->getDecl(); - if (RD->hasFlexibleArrayMember()) - return false; - - // Check that all sub-fields are at offset 0, and are themselves "integer - // like". - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - - bool HadField = false; - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i, ++idx) { - const FieldDecl *FD = *i; - - // Check if this field is at offset 0. - uint64_t Offset = Layout.getFieldOffset(idx); - if (Offset != 0) { - // Allow padding bit-fields, but only if they are all at the end of the - // structure (despite the wording above, this matches gcc). - if (FD->isBitField() && - !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { - for (; i != e; ++i) - if (!i->isBitField() || - i->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) - return false; - - // All remaining fields are padding, allow this. - return true; - } - - return false; - } - - if (!isIntegerLikeType(FD->getType(), Context, VMContext)) - return false; - - // Only allow at most one field in a structure. Again this doesn't match the - // wording above, but follows gcc. - if (!RD->isUnion()) { - if (HadField) - return false; - - HadField = true; - } - } - - return true; -} - -ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) - return ABIArgInfo::getIgnore(); - - if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // Are we following APCS? - if (getABIKind() == APCS) { - if (isEmptyRecord(Context, RetTy, false)) - return ABIArgInfo::getIgnore(); - - // Integer like structures are returned in r0. - if (isIntegerLikeType(RetTy, Context, VMContext)) { - // Return in the smallest viable integer type. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); - if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); - } - - // Otherwise return in memory. - return ABIArgInfo::getIndirect(0); - } - - // Otherwise this is an AAPCS variant. - - if (isEmptyRecord(Context, RetTy, true)) - return ABIArgInfo::getIgnore(); - - // Aggregates <= 4 bytes are returned in r0; other aggregates - // are returned indirectly. - uint64_t Size = Context.getTypeSize(RetTy); - if (Size <= 32) { - // Return in the smallest viable integer type. - if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); - if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); - } - - return ABIArgInfo::getIndirect(0); -} - -llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // FIXME: Need to handle alignment - const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); - - CGBuilderTy &Builder = CGF.Builder; - llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, - "ap"); - llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); - - uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); - llvm::Value *NextAddr = - Builder.CreateGEP(Addr, llvm::ConstantInt::get( - llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset), - "ap.next"); - Builder.CreateStore(NextAddr, VAListAddrAsBPP); - - return AddrTyped; -} - -ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - return ABIArgInfo::getIndirect(0); - } else { - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -// SystemZ ABI Implementation - -namespace { - -class SystemZABIInfo : public ABIInfo { - bool isPromotableIntegerType(QualType Ty) const; - - ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), - Context, VMContext); - for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); - } - - virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const; -}; - -} - -bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { - // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended. - if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) - switch (BT->getKind()) { - case BuiltinType::Bool: - case BuiltinType::Char_S: - case BuiltinType::Char_U: - case BuiltinType::SChar: - case BuiltinType::UChar: - case BuiltinType::Short: - case BuiltinType::UShort: - case BuiltinType::Int: - case BuiltinType::UInt: - return true; - default: - return false; - } - return false; -} - -llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - // FIXME: Implement - return 0; -} - - -ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { - return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(RetTy) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(Ty) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } -} - -llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; -} - -const ABIInfo &CodeGenTypes::getABIInfo() const { - if (TheABIInfo) - return *TheABIInfo; - - // For now we just cache the ABIInfo in CodeGenTypes and don't free it. - - const llvm::Triple &Triple(getContext().Target.getTriple()); - switch (Triple.getArch()) { - default: - return *(TheABIInfo = new DefaultABIInfo); - - case llvm::Triple::arm: - case llvm::Triple::thumb: - // FIXME: We want to know the float calling convention as well. - if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::APCS)); - - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::AAPCS)); - - case llvm::Triple::pic16: - return *(TheABIInfo = new PIC16ABIInfo()); - - case llvm::Triple::systemz: - return *(TheABIInfo = new SystemZABIInfo()); - - case llvm::Triple::x86: - switch (Triple.getOS()) { - case llvm::Triple::Darwin: - return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); - case llvm::Triple::Cygwin: - case llvm::Triple::MinGW32: - case llvm::Triple::MinGW64: - case llvm::Triple::AuroraUX: - case llvm::Triple::DragonFly: - case llvm::Triple::FreeBSD: - case llvm::Triple::OpenBSD: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, true)); - - default: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, false)); - } - - case llvm::Triple::x86_64: - return *(TheABIInfo = new X86_64ABIInfo()); - } -} diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index e5fd47e..4454662 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -257,7 +257,7 @@ class DefaultABIInfo : public ABIInfo { class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: - DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} }; llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -320,7 +320,7 @@ public: class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) - :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}; + :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {} }; } @@ -619,7 +619,7 @@ public: class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: - X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}; + X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {} }; } @@ -1428,7 +1428,7 @@ class PIC16ABIInfo : public ABIInfo { class PIC16TargetCodeGenInfo : public TargetCodeGenInfo { public: - PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {}; + PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {} }; } @@ -1493,7 +1493,7 @@ private: class ARMTargetCodeGenInfo : public TargetCodeGenInfo { public: ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K) - :TargetCodeGenInfo(new ARMABIInfo(K)) {}; + :TargetCodeGenInfo(new ARMABIInfo(K)) {} }; } @@ -1754,7 +1754,7 @@ class SystemZABIInfo : public ABIInfo { class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { public: - SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {}; + SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {} }; } @@ -1816,7 +1816,7 @@ namespace { class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { public: - MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const; }; diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 495b22f..58b7b79 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -34,7 +34,7 @@ namespace clang { ABIInfo *Info; public: // WARNING: Acquires the ownership of ABIInfo. - TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }; + TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { } virtual ~TargetCodeGenInfo(); /// getABIInfo() - Returns ABI info helper for the target. @@ -43,7 +43,7 @@ namespace clang { /// SetTargetAttributes - Provides a convenient hook to handle extra /// target-specific attributes for the given global. virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const { }; + CodeGen::CodeGenModule &M) const { } }; } diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index ab4bd49..852a018 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Version.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -66,6 +67,14 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, CCCUseClangCXX = false; } + + // Compute the path to the resource directory. + llvm::sys::Path P(Dir); + P.eraseComponent(); // Remove /bin from foo/bin + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + ResourceDir = P.str(); } Driver::~Driver() { @@ -273,15 +282,7 @@ void Driver::PrintHelp(bool ShowHidden) const { void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. -#ifdef CLANG_VENDOR - OS << CLANG_VENDOR; -#endif - OS << "clang version " CLANG_VERSION_STRING " (" - << getClangSubversionPath(); - if (unsigned Revision = getClangSubversionRevision()) - OS << " " << Revision; - OS << ")" << '\n'; - + OS << getClangFullVersion() << '\n'; const ToolChain &TC = C.getDefaultToolChain(); OS << "Target: " << TC.getTripleString() << '\n'; @@ -675,7 +676,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { } // Build the pipeline for this file. - Action *Current = new InputAction(*InputArg, InputType); + llvm::OwningPtr<Action> Current(new InputAction(*InputArg, InputType)); for (unsigned i = 0; i != NumSteps; ++i) { phases::ID Phase = types::getCompilationPhase(InputType, i); @@ -686,8 +687,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // Queue linker inputs. if (Phase == phases::Link) { assert(i + 1 == NumSteps && "linking must be final compilation step."); - LinkerInputs.push_back(Current); - Current = 0; + LinkerInputs.push_back(Current.take()); break; } @@ -698,14 +698,14 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { continue; // Otherwise construct the appropriate action. - Current = ConstructPhaseAction(Args, Phase, Current); + Current.reset(ConstructPhaseAction(Args, Phase, Current.take())); if (Current->getType() == types::TY_Nothing) break; } // If we ended with something, add to the output list. if (Current) - Actions.push_back(Current); + Actions.push_back(Current.take()); } // Add a link action if necessary. diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile index 4c3ca5c..dbacf8b 100644 --- a/lib/Driver/Makefile +++ b/lib/Driver/Makefile @@ -13,8 +13,5 @@ BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include -ifdef CLANG_VENDOR -CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' -endif include $(LEVEL)/Makefile.common diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 42657d9..a9c6a68 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -47,6 +47,69 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, IPhoneOSVersionMin = "3.0"; } +// FIXME: Can we tablegen this? +static const char *GetArmArchForMArch(llvm::StringRef Value) { + if (Value == "armv6k") + return "armv6"; + + if (Value == "armv5tej") + return "armv5"; + + if (Value == "xscale") + return "xscale"; + + if (Value == "armv4t") + return "armv4t"; + + if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || + Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || + Value == "armv7m") + return "armv7"; + + return 0; +} + +// FIXME: Can we tablegen this? +static const char *GetArmArchForMCpu(llvm::StringRef Value) { + if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || + Value == "arm946e-s" || Value == "arm966e-s" || + Value == "arm968e-s" || Value == "arm10e" || + Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || + Value == "arm1026ej-s") + return "armv5"; + + if (Value == "xscale") + return "xscale"; + + if (Value == "arm1136j-s" || Value == "arm1136jf-s" || + Value == "arm1176jz-s" || Value == "arm1176jzf-s") + return "armv6"; + + if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") + return "armv7"; + + return 0; +} + +llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { + switch (getTriple().getArch()) { + default: + return getArchName(); + + case llvm::Triple::arm: { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) + return Arch; + + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) + return Arch; + + return "arm"; + } + } +} + DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, const unsigned (&DarwinVersion)[3], const unsigned (&_GCCVersion)[3], bool IsIPhoneOS) @@ -118,10 +181,6 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, Path += ToolChainDir; getProgramPaths().push_back(Path); - Path = getDriver().Dir; - Path += "/../libexec"; - getProgramPaths().push_back(Path); - getProgramPaths().push_back(getDriver().Dir); } @@ -235,13 +294,6 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, bool IsIPhoneOS) : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) { - // Add the relative libexec dir (for clang-cc). - // - // FIXME: We should sink clang-cc into libexec/clang/<version>/. - std::string Path = getDriver().Dir; - Path += "/../libexec"; - getProgramPaths().push_back(Path); - // We expect 'as', 'ld', etc. to be adjacent to our install dir. getProgramPaths().push_back(getDriver().Dir); } @@ -253,12 +305,10 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - // Check for static linking. - if (Args.hasArg(options::OPT_static)) { - // FIXME: We need to have compiler-rt available (perhaps as - // libclang_static.a) to link against. + // Darwin doesn't support real static executables, don't link any runtime + // libraries with -static. + if (Args.hasArg(options::OPT_static)) return; - } // Reject -static-libgcc for now, we can deal with this when and if someone // cares. This is useful in situations where someone wants to statically link @@ -269,12 +319,52 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, return; } - // Otherwise link libSystem, which should have the support routines. - // - // FIXME: This is only true for 10.6 and beyond. Legacy support isn't - // critical, but it should work... we should just link in the static - // compiler-rt library. + // Otherwise link libSystem, then the dynamic runtime library, and finally any + // target specific static runtime library. CmdArgs.push_back("-lSystem"); + + // Select the dynamic runtime library and the target specific static library. + const char *DarwinStaticLib = 0; + if (isIPhoneOS()) { + CmdArgs.push_back("-lgcc_s.1"); + + // We may need some static functions for armv6/thumb which are required to + // be in the same linkage unit as their caller. + if (getDarwinArchName(Args) == "armv6") + DarwinStaticLib = "libclang_rt.armv6.a"; + } else { + unsigned MacosxVersionMin[3]; + getMacosxVersionMin(Args, MacosxVersionMin); + + // The dynamic runtime library was merged with libSystem for 10.6 and + // beyond; only 10.4 and 10.5 need an additional runtime library. + if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + CmdArgs.push_back("-lgcc_s.10.4"); + else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + CmdArgs.push_back("-lgcc_s.10.5"); + + // For OS X, we only need a static runtime library when targetting 10.4, to + // provide versions of the static functions which were omitted from + // 10.4.dylib. + if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + DarwinStaticLib = "libclang_rt.10.4.a"; + } + + /// Add the target specific static library, if needed. + if (DarwinStaticLib) { + llvm::sys::Path P(getDriver().ResourceDir); + P.appendComponent("lib"); + P.appendComponent("darwin"); + P.appendComponent(DarwinStaticLib); + + // For now, allow missing resource libraries to support developers who may + // not have compiler-rt checked out or integrated into their build. + if (!P.exists()) + getDriver().Diag(clang::diag::warn_drv_missing_resource_library) + << P.str(); + else + CmdArgs.push_back(Args.MakeArgString(P.str())); + } } void Darwin::getMacosxVersionMin(const ArgList &Args, @@ -544,10 +634,6 @@ const char *Darwin::GetForcedPicModel() const { Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { - std::string Path(getDriver().Dir); - Path += "/../libexec"; - getProgramPaths().push_back(Path); - getProgramPaths().push_back(getDriver().Dir); } @@ -684,11 +770,6 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - // Path mangling to find libexec - std::string Path(getDriver().Dir); - - Path += "/../libexec"; - getProgramPaths().push_back(Path); getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); @@ -753,10 +834,6 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { // Path mangling to find libexec - std::string Path(getDriver().Dir); - - Path += "/../libexec"; - getProgramPaths().push_back(Path); getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 374ad8c..3ca6ad8 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -85,6 +85,11 @@ public: Res[2] = DarwinVersion[1]; } + /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler + /// invocation. For example, Darwin treats different ARM variations as + /// distinct architectures. + llvm::StringRef getDarwinArchName(const ArgList &Args) const; + /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is /// either the -mmacosx-version-min, or the current version if unspecified. void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 010953d..afb22a2 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -9,7 +9,6 @@ #include "Tools.h" -#include "clang/Basic/Version.h" #include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" @@ -864,15 +863,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); // Pass the path to compiler resource files. - // - // FIXME: Get this from a configuration object. - llvm::sys::Path P(D.Dir); - P.eraseComponent(); // Remove /bin from foo/bin - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); CmdArgs.push_back("-resource-dir"); - CmdArgs.push_back(Args.MakeArgString(P.str())); + CmdArgs.push_back(D.ResourceDir.c_str()); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -1857,87 +1849,17 @@ static bool isSourceSuffix(const char *Str) { .Default(false); } -// FIXME: Can we tablegen this? -static const char *GetArmArchForMArch(llvm::StringRef Value) { - if (Value == "armv6k") - return "armv6"; - - if (Value == "armv5tej") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "armv4t") - return "armv4t"; - - if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || - Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || - Value == "armv7m") - return "armv7"; - - return 0; -} - -// FIXME: Can we tablegen this? -static const char *GetArmArchForMCpu(llvm::StringRef Value) { - if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || - Value == "arm946e-s" || Value == "arm966e-s" || - Value == "arm968e-s" || Value == "arm10e" || - Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || - Value == "arm1026ej-s") - return "armv5"; - - if (Value == "xscale") - return "xscale"; - - if (Value == "arm1136j-s" || Value == "arm1136jf-s" || - Value == "arm1176jz-s" || Value == "arm1176jzf-s") - return "armv6"; - - if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") - return "armv7"; - - return 0; -} - void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const { + llvm::StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args); + // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); + CmdArgs.push_back(Args.MakeArgString(ArchName)); - switch (getToolChain().getTriple().getArch()) { - default: - CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName())); - break; - - case llvm::Triple::arm: { - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) { - CmdArgs.push_back(Arch); - return; - } - } - - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) { - CmdArgs.push_back(Arch); - return; - } - } - - CmdArgs.push_back("arm"); + // FIXME: Is this needed anymore? + if (ArchName == "arm") CmdArgs.push_back("-force_cpusubtype_ALL"); - return; - } - } -} - -void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Derived from darwin_subarch spec, not sure what the distinction - // exists for but at least for this chain it is the same. - AddDarwinArch(Args, CmdArgs); } void darwin::Link::AddLinkArgs(const ArgList &Args, @@ -1954,11 +1876,9 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, } if (!Args.hasArg(options::OPT_dynamiclib)) { - if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) { - AddDarwinArch(Args, CmdArgs); - CmdArgs.push_back("-force_cpusubtype_ALL"); - } else - AddDarwinSubArch(Args, CmdArgs); + AddDarwinArch(Args, CmdArgs); + // FIXME: Why do this only on this path? + Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); Args.AddLastArg(CmdArgs, options::OPT_bundle); Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); @@ -1992,11 +1912,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, "-dylib_current_version"); - if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) { - AddDarwinArch(Args, CmdArgs); - // NOTE: We don't add -force_cpusubtype_ALL on this path. Ok. - } else - AddDarwinSubArch(Args, CmdArgs); + AddDarwinArch(Args, CmdArgs); Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, "-dylib_install_name"); diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 8f7da52..abd8cfc 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -130,7 +130,6 @@ namespace darwin { class VISIBILITY_HIDDEN DarwinTool : public Tool { protected: void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const; const toolchains::Darwin &getDarwinToolChain() const { return reinterpret_cast<const toolchains::Darwin&>(getToolChain()); diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 52b597e..33cb94e 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -421,6 +421,11 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<namespace alias> " << NAD->getNameAsString() << "\n"; break; } + case Decl::ClassTemplate: { + ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I); + Out << "<class template> " << CTD->getNameAsString() << '\n'; + break; + } default: Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n"; assert(0 && "decl unhandled"); diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 48296c7..2fb47cb 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" using namespace clang; @@ -103,11 +104,31 @@ const std::string &ASTUnit::getPCHFileName() { ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, Diagnostic &Diags, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); AST->OnlyLocalDecls = OnlyLocalDecls; AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + RemappedFiles[I].second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, + RemappedFiles[I].second); + } + // Gather Info for preprocessor construction later on. LangOptions LangInfo; @@ -289,7 +310,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Diagnostic &Diags, llvm::StringRef ResourceFilesPath, bool OnlyLocalDecls, - bool UseBumpAllocator) { + bool UseBumpAllocator, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles) { llvm::SmallVector<const char *, 16> Args; Args.push_back("<clang>"); // FIXME: Remove dummy argument. Args.insert(Args.end(), ArgBegin, ArgEnd); @@ -327,6 +350,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, (const char**) CCArgs.data()+CCArgs.size(), Diags); + // Override any files that need remapping + for (unsigned I = 0; I != NumRemappedFiles; ++I) + CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + // Override the resources path. CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath; diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp index ad152d3..45a3b15 100644 --- a/lib/Frontend/AnalysisConsumer.cpp +++ b/lib/Frontend/AnalysisConsumer.cpp @@ -204,45 +204,47 @@ namespace llvm { void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) { switch (D->getKind()) { - case Decl::Function: { - FunctionDecl* FD = cast<FunctionDecl>(D); + case Decl::Function: { + FunctionDecl* FD = cast<FunctionDecl>(D); - if (!Opts.AnalyzeSpecificFunction.empty() && - Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) - break; - - Stmt* Body = FD->getBody(); - if (Body) HandleCode(FD, Body, FunctionActions); + if (!Opts.AnalyzeSpecificFunction.empty() && + Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName()) break; - } - case Decl::ObjCMethod: { - ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); + Stmt* Body = FD->getBody(); + if (Body) HandleCode(FD, Body, FunctionActions); + break; + } - if (Opts.AnalyzeSpecificFunction.size() > 0 && - Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) - return; + case Decl::ObjCMethod: { + ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D); - Stmt* Body = MD->getBody(); - if (Body) HandleCode(MD, Body, ObjCMethodActions); - break; - } + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString()) + return; + + Stmt* Body = MD->getBody(); + if (Body) HandleCode(MD, Body, ObjCMethodActions); + break; + } - case Decl::CXXMethod: { - CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); + case Decl::CXXConstructor: + case Decl::CXXDestructor: + case Decl::CXXConversion: + case Decl::CXXMethod: { + CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D); - if (Opts.AnalyzeSpecificFunction.size() > 0 && - Opts.AnalyzeSpecificFunction != CXXMD->getName()) - return; + if (Opts.AnalyzeSpecificFunction.size() > 0 && + Opts.AnalyzeSpecificFunction != CXXMD->getName()) + return; - Stmt *Body = CXXMD->getBody(); - if (Body) - HandleCode(CXXMD, Body, FunctionActions); - break; - } + Stmt *Body = CXXMD->getBody(); + if (Body) HandleCode(CXXMD, Body, FunctionActions); + break; + } - default: - break; + default: + break; } } @@ -409,20 +411,20 @@ static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { switch (mgr.getLangOptions().getGCMode()) { - default: - assert (false && "Invalid GC mode."); - case LangOptions::NonGC: - ActionCheckerCFRefAux(C, mgr, D, false); - break; - - case LangOptions::GCOnly: - ActionCheckerCFRefAux(C, mgr, D, true); - break; - - case LangOptions::HybridGC: - ActionCheckerCFRefAux(C, mgr, D, false); - ActionCheckerCFRefAux(C, mgr, D, true); - break; + default: + assert (false && "Invalid GC mode."); + case LangOptions::NonGC: + ActionCheckerCFRefAux(C, mgr, D, false); + break; + + case LangOptions::GCOnly: + ActionCheckerCFRefAux(C, mgr, D, true); + break; + + case LangOptions::HybridGC: + ActionCheckerCFRefAux(C, mgr, D, false); + ActionCheckerCFRefAux(C, mgr, D, true); + break; } } @@ -530,11 +532,11 @@ ASTConsumer* clang::CreateAnalysisConsumer(const Preprocessor& pp, for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) switch (Opts.AnalysisList[i]) { #define ANALYSIS(NAME, CMD, DESC, SCOPE)\ - case NAME:\ - C->add ## SCOPE ## Action(&Action ## NAME);\ - break; + case NAME:\ + C->add ## SCOPE ## Action(&Action ## NAME);\ + break; #include "clang/Frontend/Analyses.def" - default: break; + default: break; } // Last, disable the effects of '-Werror' when using the AnalysisConsumer. diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 7296246..7326937 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -77,25 +77,25 @@ public: void EmitData(llvm::raw_ostream& Out) { switch (Kind) { - case IsFE: - // Emit stat information. - ::Emit32(Out, FE->getInode()); - ::Emit32(Out, FE->getDevice()); - ::Emit16(Out, FE->getFileMode()); - ::Emit64(Out, FE->getModificationTime()); - ::Emit64(Out, FE->getSize()); - break; - case IsDE: - // Emit stat information. - ::Emit32(Out, (uint32_t) StatBuf->st_ino); - ::Emit32(Out, (uint32_t) StatBuf->st_dev); - ::Emit16(Out, (uint16_t) StatBuf->st_mode); - ::Emit64(Out, (uint64_t) StatBuf->st_mtime); - ::Emit64(Out, (uint64_t) StatBuf->st_size); - delete StatBuf; - break; - default: - break; + case IsFE: + // Emit stat information. + ::Emit32(Out, FE->getInode()); + ::Emit32(Out, FE->getDevice()); + ::Emit16(Out, FE->getFileMode()); + ::Emit64(Out, FE->getModificationTime()); + ::Emit64(Out, FE->getSize()); + break; + case IsDE: + // Emit stat information. + ::Emit32(Out, (uint32_t) StatBuf->st_ino); + ::Emit32(Out, (uint32_t) StatBuf->st_dev); + ::Emit16(Out, (uint16_t) StatBuf->st_mode); + ::Emit64(Out, (uint64_t) StatBuf->st_mtime); + ::Emit64(Out, (uint64_t) StatBuf->st_size); + delete StatBuf; + break; + default: + break; } } diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp index b981fc4..d7470d9 100644 --- a/lib/Frontend/DeclXML.cpp +++ b/lib/Frontend/DeclXML.cpp @@ -98,14 +98,14 @@ public: const char* pAttributeName = NAME; \ const bool optional = false; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp index 93421ca..b163e26 100644 --- a/lib/Frontend/HTMLDiagnostics.cpp +++ b/lib/Frontend/HTMLDiagnostics.cpp @@ -349,10 +349,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, const char *Kind = 0; switch (P.getKind()) { - case PathDiagnosticPiece::Event: Kind = "Event"; break; - case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; - // Setting Kind to "Control" is intentional. - case PathDiagnosticPiece::Macro: Kind = "Control"; break; + case PathDiagnosticPiece::Event: Kind = "Event"; break; + case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; + // Setting Kind to "Control" is intentional. + case PathDiagnosticPiece::Macro: Kind = "Control"; break; } std::string sbuf; @@ -380,14 +380,14 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) switch (*I) { - default: - ++cnt; - continue; - case ' ': - case '\t': - case '\n': - if (cnt > max_token) max_token = cnt; - cnt = 0; + default: + ++cnt; + continue; + case ' ': + case '\t': + case '\n': + if (cnt > max_token) max_token = cnt; + cnt = 0; } if (cnt > max_token) diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 6fceb98..6102760 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -189,10 +189,12 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base, void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, llvm::StringRef Arch, llvm::StringRef Version) { - llvm::Twine localBase = Base + "/" + Arch + "/" + Version + "/include"; - AddPath(localBase, System, true, false, false); - AddPath(localBase + "/c++", System, true, false, false); - AddPath(localBase + "/c++/backward", System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", + System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", + System, true, false, false); } // FIXME: This probably should goto to some platform utils place. @@ -206,8 +208,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, // I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION". // There can be additional characters in the component. Only the numberic // characters are compared. -bool getSystemRegistryString(const char *keyPath, const char *valueName, - char *value, size_t maxLength) { +static bool getSystemRegistryString(const char *keyPath, const char *valueName, + char *value, size_t maxLength) { HKEY hRootKey = NULL; HKEY hKey = NULL; const char* subKey = NULL; @@ -312,13 +314,13 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName, } #else // _MSC_VER // Read registry string. -bool getSystemRegistryString(const char *, const char *, char *, size_t) { +static bool getSystemRegistryString(const char*, const char*, char*, size_t) { return(false); } #endif // _MSC_VER // Get Visual Studio installation directory. -bool getVisualStudioDir(std::string &path) { +static bool getVisualStudioDir(std::string &path) { char vsIDEInstallDir[256]; // Try the Windows registry first. bool hasVCDir = getSystemRegistryString( @@ -365,7 +367,7 @@ bool getVisualStudioDir(std::string &path) { } // Get Windows SDK installation directory. -bool getWindowsSDKDir(std::string &path) { +static bool getWindowsSDKDir(std::string &path) { char windowsSDKInstallDir[256]; // Try the Windows registry. bool hasSDKDir = getSystemRegistryString( @@ -508,6 +510,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", "i386-redhat-linux","", "", triple); + // Fedora 10 x86_64 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2", + "x86_64-redhat-linux", "32", "", triple); + // Fedora 11 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1", "i586-redhat-linux","", "", triple); @@ -556,7 +562,7 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl "i686-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: - AddPath("/usr/include/c++/4.2", System, true, false, false); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; case llvm::Triple::Solaris: // Solaris - Fall though.. diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index e4c380a..9aaf132 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/Utils.h" +#include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" @@ -137,7 +138,10 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix, "1.79769313486231580793728971405301e+308L", "1.18973149535723176508575932662800702e+4932L"); - llvm::Twine DefPrefix = "__" + Prefix + "_"; + llvm::SmallString<32> DefPrefix; + DefPrefix = "__"; + DefPrefix += Prefix; + DefPrefix += "_"; Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); @@ -420,40 +424,61 @@ static void InitializeFileRemapping(Diagnostic &Diags, SourceManager &SourceMgr, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { - // Remap files in the source manager. + // Remap files in the source manager (with buffers). + for (PreprocessorOptions::remapped_file_buffer_iterator + Remap = InitOpts.remapped_file_buffer_begin(), + RemapEnd = InitOpts.remapped_file_buffer_end(); + Remap != RemapEnd; + ++Remap) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, + Remap->second->getBufferSize(), + 0); + if (!FromFile) { + Diags.Report(diag::err_fe_remap_missing_from_file) + << Remap->first; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + SourceMgr.overrideFileContents(FromFile, Remap->second); + } + + // Remap files in the source manager (with other files). for (PreprocessorOptions::remapped_file_iterator - Remap = InitOpts.remapped_file_begin(), - RemapEnd = InitOpts.remapped_file_end(); + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); Remap != RemapEnd; ++Remap) { // Find the file that we're mapping to. const FileEntry *ToFile = FileMgr.getFile(Remap->second); if (!ToFile) { Diags.Report(diag::err_fe_remap_missing_to_file) - << Remap->first << Remap->second; + << Remap->first << Remap->second; continue; } - + // Create the file entry for the file that we're mapping from. const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first, ToFile->getSize(), 0); if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) - << Remap->first; + << Remap->first; continue; } - + // Load the contents of the file we're mapping to. std::string ErrorStr; const llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); + = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr); if (!Buffer) { Diags.Report(diag::err_fe_error_opening) - << Remap->second << ErrorStr; + << Remap->second << ErrorStr; continue; } - + // Override the contents of the "from" file with the contents of // the "to" file. SourceMgr.overrideFileContents(FromFile, Buffer); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 07d5a78..2593551 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -1399,17 +1399,10 @@ PCHReader::ReadPCHBlock() { NumComments = BlobLen / sizeof(SourceRange); break; - case pch::SVN_BRANCH_REVISION: { - unsigned CurRevision = getClangSubversionRevision(); - if (Record[0] && CurRevision && Record[0] != CurRevision) { - Diag(Record[0] < CurRevision? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - const char *CurBranch = getClangSubversionPath(); - if (strncmp(CurBranch, BlobStart, BlobLen)) { - std::string PCHBranch(BlobStart, BlobLen); + case pch::VERSION_CONTROL_BRANCH_REVISION: { + llvm::StringRef CurBranch = getClangFullRepositoryVersion(); + llvm::StringRef PCHBranch(BlobStart, BlobLen); + if (CurBranch != PCHBranch) { Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; return IgnorePCH; } @@ -1909,18 +1902,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { } case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 2) { + if (Record.size() != 3) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - return Context->getFunctionNoProtoType(ResultType, Record[1]); + return Context->getFunctionNoProtoType(ResultType, Record[1], + (CallingConv)Record[2]); } case pch::TYPE_FUNCTION_PROTO: { QualType ResultType = GetType(Record[0]); bool NoReturn = Record[1]; - unsigned Idx = 2; + CallingConv CallConv = (CallingConv)Record[2]; + unsigned Idx = 3; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -1936,7 +1931,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, isVariadic, Quals, hasExceptionSpec, hasAnyExceptionSpec, NumExceptions, - Exceptions.data(), NoReturn); + Exceptions.data(), NoReturn, CallConv); } case pch::TYPE_UNRESOLVED_USING: @@ -2040,7 +2035,13 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + if (TL.needsExtraLocalData()) { + TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); + TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); + TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); + TL.setModeAttr(Record[Idx++]); + } } void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 69343ed..4dc1318 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -223,7 +223,12 @@ void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - ID->setProtocolList(Protocols.data(), NumProtocols, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtocols); + for (unsigned I = 0; I != NumProtocols; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(), + *Reader.getContext()); unsigned NumIvars = Record[Idx++]; llvm::SmallVector<ObjCIvarDecl *, 16> IVars; IVars.reserve(NumIvars); @@ -253,7 +258,12 @@ void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); } void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { @@ -282,7 +292,12 @@ void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); } void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { @@ -293,9 +308,15 @@ void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext()); + llvm::SmallVector<SourceLocation, 16> ProtoLocs; + ProtoLocs.reserve(NumProtoRefs); + for (unsigned I = 0; I != NumProtoRefs; ++I) + ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), + *Reader.getContext()); CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++]))); - CD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { @@ -305,6 +326,7 @@ void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); + D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setType(Reader.GetType(Record[Idx++])); // FIXME: stable encoding D->setPropertyAttributes( @@ -671,7 +693,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation()); break; case pch::DECL_OBJC_CATEGORY: - D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), 0); + D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), SourceLocation(), 0); break; case pch::DECL_OBJC_CATEGORY_IMPL: D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0); @@ -683,7 +706,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0); break; case pch::DECL_OBJC_PROPERTY: - D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); + D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), + QualType()); break; case pch::DECL_OBJC_PROPERTY_IMPL: D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(), diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 138f1e1..21c9cbf 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -117,6 +117,12 @@ namespace { unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); unsigned VisitCXXConstructExpr(CXXConstructExpr *E); + unsigned VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + unsigned VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + unsigned VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E); + unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); }; } @@ -513,7 +519,7 @@ unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); - E->setTypeAsWritten(Reader.GetType(Record[Idx++])); + E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); return 1; } @@ -527,6 +533,7 @@ unsigned PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { unsigned PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { VisitExpr(E); E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); E->setInitializer(cast<Expr>(StmtStack.back())); E->setFileScope(Record[Idx++]); return 1; @@ -868,6 +875,35 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { return E->getNumArgs(); } +unsigned PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + +unsigned PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + return VisitCXXNamedCastExpr(E); +} + +unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + unsigned num = VisitExplicitCastExpr(E); + E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); + return num; +} + // Within the bitstream, expressions are stored in Reverse Polish // Notation, with each of the subexpressions preceding the // expression they are stored in. To evaluate expressions, we @@ -1176,6 +1212,28 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) { S = new (Context) CXXConstructExpr(Empty, *Context, Record[PCHStmtReader::NumExprFields + 2]); break; + + case pch::EXPR_CXX_STATIC_CAST: + S = new (Context) CXXStaticCastExpr(Empty); + break; + + case pch::EXPR_CXX_DYNAMIC_CAST: + S = new (Context) CXXDynamicCastExpr(Empty); + break; + + case pch::EXPR_CXX_REINTERPRET_CAST: + S = new (Context) CXXReinterpretCastExpr(Empty); + break; + + case pch::EXPR_CXX_CONST_CAST: + S = new (Context) CXXConstCastExpr(Empty); + break; + + case pch::EXPR_CXX_FUNCTIONAL_CAST: + S = new (Context) CXXFunctionalCastExpr(Empty); + break; + + } // We hit a STMT_STOP, so we're done with this expression. diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 3f6841b..9909c95 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -139,6 +139,8 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); Record.push_back(T->getNoReturnAttr()); + // FIXME: need to stabilize encoding of calling convention... + Record.push_back(T->getCallConv()); } void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { @@ -275,7 +277,13 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { // nothing to do } void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); + Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); + if (TL.needsExtraLocalData()) { + Record.push_back(TL.getWrittenTypeSpec()); + Record.push_back(TL.getWrittenSignSpec()); + Record.push_back(TL.getWrittenWidthSpec()); + Record.push_back(TL.hasModeAttr()); + } } void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); @@ -535,7 +543,7 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); RECORD(COMMENT_RANGES); - RECORD(SVN_BRANCH_REVISION); + RECORD(VERSION_CONTROL_BRANCH_REVISION); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -699,16 +707,15 @@ void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); } - // Subversion branch/version information. - BitCodeAbbrev *SvnAbbrev = new BitCodeAbbrev(); - SvnAbbrev->Add(BitCodeAbbrevOp(pch::SVN_BRANCH_REVISION)); - SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // SVN revision - SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag - unsigned SvnAbbrevCode = Stream.EmitAbbrev(SvnAbbrev); + // Repository branch/version information. + BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); + RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); + RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); Record.clear(); - Record.push_back(pch::SVN_BRANCH_REVISION); - Record.push_back(getClangSubversionRevision()); - Stream.EmitRecordWithBlob(SvnAbbrevCode, Record, getClangSubversionPath()); + Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION); + Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, + getClangFullRepositoryVersion()); } /// \brief Write the LangOptions structure. @@ -1263,7 +1270,7 @@ void PCHWriter::WriteType(QualType T) { // For all of the concrete, non-dependent types, call the // appropriate visitor function. #define TYPE(Class, Base) \ - case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; + case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break; #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 2dbcc27..020f69b 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -223,6 +223,10 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { PEnd = D->protocol_end(); P != PEnd; ++P) Writer.AddDeclRef(*P, Record); + for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Record.push_back(D->ivar_size()); for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(), IEnd = D->ivar_end(); I != IEnd; ++I) @@ -251,6 +255,10 @@ void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), + PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_PROTOCOL; } @@ -272,9 +280,13 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { VisitDecl(D); Record.push_back(D->protocol_size()); - for (ObjCProtocolDecl::protocol_iterator + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCForwardProtocolDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Code = pch::DECL_OBJC_FORWARD_PROTOCOL; } @@ -282,11 +294,16 @@ void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { VisitObjCContainerDecl(D); Writer.AddDeclRef(D->getClassInterface(), Record); Record.push_back(D->protocol_size()); - for (ObjCProtocolDecl::protocol_iterator + for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) Writer.AddDeclRef(*I, Record); + for (ObjCCategoryDecl::protocol_loc_iterator + PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); + PL != PLEnd; ++PL) + Writer.AddSourceLocation(*PL, Record); Writer.AddDeclRef(D->getNextClassCategory(), Record); - Writer.AddSourceLocation(D->getLocEnd(), Record); + Writer.AddSourceLocation(D->getAtLoc(), Record); + Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); Code = pch::DECL_OBJC_CATEGORY; } @@ -298,6 +315,7 @@ void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); + Writer.AddSourceLocation(D->getAtLoc(), Record); Writer.AddTypeRef(D->getType(), Record); // FIXME: stable encoding Record.push_back((unsigned)D->getPropertyAttributes()); diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp index 4be9b81..fdfdfef 100644 --- a/lib/Frontend/PCHWriterStmt.cpp +++ b/lib/Frontend/PCHWriterStmt.cpp @@ -112,6 +112,12 @@ namespace { // C++ Statements void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXConstructExpr(CXXConstructExpr *E); + void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); + void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); + void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); + void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); + void VisitCXXConstCastExpr(CXXConstCastExpr *E); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); }; } @@ -477,7 +483,7 @@ void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) { void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); - Writer.AddTypeRef(E->getTypeAsWritten(), Record); + Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record); } void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { @@ -490,6 +496,7 @@ void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { VisitExpr(E); Writer.AddSourceLocation(E->getLParenLoc(), Record); + Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); Writer.WriteSubStmt(E->getInitializer()); Record.push_back(E->isFileScope()); Code = pch::EXPR_COMPOUND_LITERAL; @@ -795,6 +802,38 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { Code = pch::EXPR_CXX_CONSTRUCT; } +void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getOperatorLoc(), Record); +} + +void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_STATIC_CAST; +} + +void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_DYNAMIC_CAST; +} + +void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_REINTERPRET_CAST; +} + +void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) { + VisitCXXNamedCastExpr(E); + Code = pch::EXPR_CXX_CONST_CAST; +} + +void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + VisitExplicitCastExpr(E); + Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = pch::EXPR_CXX_FUNCTIONAL_CAST; +} + //===----------------------------------------------------------------------===// // PCHWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 92cafe6..98be869 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -177,12 +177,12 @@ static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { char c = *I; switch (c) { - default: o << c; break; - case '&': o << "&"; break; - case '<': o << "<"; break; - case '>': o << ">"; break; - case '\'': o << "'"; break; - case '\"': o << """; break; + default: o << c; break; + case '&': o << "&"; break; + case '<': o << "<"; break; + case '>': o << ">"; break; + case '\'': o << "'"; break; + case '\"': o << """; break; } } o << "</string>"; @@ -289,16 +289,16 @@ static void ReportMacro(llvm::raw_ostream& o, I!=E; ++I) { switch ((*I)->getKind()) { - default: - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, - indent); - break; + default: + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, + indent); + break; } } } @@ -310,18 +310,18 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, unsigned indent = 4; switch (P.getKind()) { - case PathDiagnosticPiece::ControlFlow: - ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, - LangOpts, indent); - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, - indent); - break; + case PathDiagnosticPiece::ControlFlow: + ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, + LangOpts, indent); + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, + indent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, + indent); + break; } } diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp index 95afb90..a91dd8d 100644 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ b/lib/Frontend/PrintParserCallbacks.cpp @@ -65,6 +65,7 @@ namespace { SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtocols, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { Out << __FUNCTION__ << "\n"; @@ -72,7 +73,8 @@ namespace { ClassName, ClassLoc, SuperName, SuperLoc, ProtoRefs, NumProtocols, - EndProtoLoc, AttrList); + ProtoLocs, EndProtoLoc, + AttrList); } /// ActOnForwardClassDeclaration - diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index d9708d8..43deaee 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -22,7 +22,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TokenConcatenation.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Config/config.h" #include "llvm/Support/raw_ostream.h" #include <cstdio> @@ -443,13 +443,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, } } -namespace { - struct SortMacrosByID { - typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; - bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const { - return LHS.first->getName() < RHS.first->getName(); - } - }; +typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair; +static int MacroIDCompare(const void* a, const void* b) { + const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a); + const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b); + return LHS->first->getName().compare(RHS->first->getName()); } static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { @@ -461,11 +459,9 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID; - for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); - I != E; ++I) - MacrosByID.push_back(*I); - std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID()); + llvm::SmallVector<id_macro_pair, 128> + MacrosByID(PP.macro_begin(), PP.macro_end()); + llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { MacroInfo &MI = *MacrosByID[i].second; @@ -473,7 +469,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { if (MI.isBuiltinMacro()) continue; PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS); - *OS << "\n"; + *OS << '\n'; } } diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp index fc9401d..35d8dde 100644 --- a/lib/Frontend/RewriteObjC.cpp +++ b/lib/Frontend/RewriteObjC.cpp @@ -420,6 +420,14 @@ namespace { } } }; + + // Helper function: create a CStyleCastExpr with trivial type source info. + 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, + SourceLocation(), SourceLocation()); + } } void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType, @@ -610,6 +618,7 @@ void RewriteObjC::Initialize(ASTContext &context) { Preamble += "#undef __OBJC_RW_DLLIMPORT\n"; Preamble += "#undef __OBJC_RW_STATICIMPORT\n"; Preamble += "#define __attribute__(X)\n"; + Preamble += "#define __weak\n"; } else { Preamble += "#define __block\n"; @@ -824,6 +833,10 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) { } void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { + // When method is a synthesized one, such as a getter/setter there is + // nothing to rewrite. + if (Method->isSynthesized()) + return; SourceLocation LocStart = Method->getLocStart(); SourceLocation LocEnd = Method->getLocEnd(); @@ -837,10 +850,9 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) { } void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) { - SourceLocation Loc = prop->getLocation(); + SourceLocation Loc = prop->getAtLoc(); ReplaceText(Loc, 0, "// ", 3); - // FIXME: handle properties that are declared across multiple lines. } @@ -1219,11 +1231,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new (Context) CStyleCastExpr(castT, - CastExpr::CK_Unknown, - IV->getBase(), - castT,SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), @@ -1267,11 +1277,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, SourceLocation(), II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - CastExpr *castExpr = new (Context) CStyleCastExpr(castT, - CastExpr::CK_Unknown, - IV->getBase(), - castT, SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, + CastExpr::CK_Unknown, + IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), IV->getBase()->getLocEnd(), castExpr); @@ -1584,12 +1592,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { std::string syncBuf; syncBuf += " objc_sync_exit("; - Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - S->getSynchExpr(), - Context->getObjCIdType(), - SourceLocation(), - SourceLocation()); + Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, + S->getSynchExpr()); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); syncExpr->printPretty(syncExprBuf, *Context, 0, @@ -2332,11 +2337,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { Context->getPointerType(DRE->getType()), SourceLocation()); // cast to NSConstantString * - CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(), - CastExpr::CK_Unknown, - Unop, Exp->getType(), - SourceLocation(), - SourceLocation()); + CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), + CastExpr::CK_Unknown, Unop); ReplaceStmt(Exp, cast); // delete Exp; leak for now, see RewritePropertySetter() usage for more info. return cast; @@ -2465,13 +2467,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // set the receiver to self, the first argument to all methods. InitExprs.push_back( - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), - SourceLocation()), - Context->getObjCIdType(), - SourceLocation(), SourceLocation())); // set the 'receiver'. + SourceLocation())) + ); // set the 'receiver'. llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); @@ -2484,10 +2485,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { ClsExprs.size()); // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - Cls, Context->getObjCIdType(), - SourceLocation(), SourceLocation())); + NoTypeInfoCStyleCastExpr(Context, + Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2509,17 +2509,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); - SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep, - Context->getPointerType(superType), - SourceLocation(), 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()); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, - false); + 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()), @@ -2551,13 +2552,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { llvm::SmallVector<Expr*, 4> InitExprs; InitExprs.push_back( - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), - SourceLocation()), - Context->getObjCIdType(), - SourceLocation(), SourceLocation())); // set the 'receiver'. + SourceLocation())) + ); // set the 'receiver'. llvm::SmallVector<Expr*, 8> ClsExprs; QualType argType = Context->getPointerType(Context->CharTy); @@ -2571,9 +2571,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // To turn off a warning, type-cast to 'id' InitExprs.push_back( // set 'super class', using objc_getClass(). - new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation())); + NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2595,16 +2594,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); - SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType), - CastExpr::CK_Unknown, - SuperRep, Context->getPointerType(superType), - SourceLocation(), 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()); - SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false); + TypeSourceInfo *superTInfo + = Context->getTrivialTypeSourceInfo(superType); + SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, + superType, ILE, false); } MsgExprs.push_back(SuperRep); } else { @@ -2612,10 +2613,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // Foo<Proto> *. while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr)) recExpr = CE->getSubExpr(); - recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, recExpr, - Context->getObjCIdType(), - SourceLocation(), SourceLocation()); + recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, recExpr); MsgExprs.push_back(recExpr); } } @@ -2639,19 +2638,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { QualType type = ICE->getType()->isObjCQualifiedIdType() ? Context->getObjCIdType() : ICE->getType(); - userExpr = new (Context) CStyleCastExpr(type, CastExpr::CK_Unknown, - userExpr, type, SourceLocation(), - SourceLocation()); + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown, + userExpr); } // Make id<P...> cast into an 'id' cast. else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) { if (CE->getType()->isObjCQualifiedIdType()) { while ((CE = dyn_cast<CStyleCastExpr>(userExpr))) userExpr = CE->getSubExpr(); - userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(), - CastExpr::CK_Unknown, - userExpr, Context->getObjCIdType(), - SourceLocation(), SourceLocation()); + userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), + CastExpr::CK_Unknown, userExpr); } } MsgExprs.push_back(userExpr); @@ -2701,10 +2697,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // If we don't do this cast, we get the following bizarre warning/note: // xx.m:13: warning: function called through a non-compatible type // xx.m:13: note: if this code is reached, the program will abort - cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, DRE, - Context->getPointerType(Context->VoidTy), - SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, DRE); // Now do the "normal" pointer to function cast. QualType castType = Context->getFunctionType(returnType, @@ -2712,9 +2707,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { // If we don't have a method decl, force a variadic cast. Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0); castType = Context->getPointerType(castType); - cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, cast, - castType, SourceLocation(), - SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); @@ -2734,17 +2728,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) { DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType, SourceLocation()); // Need to cast objc_msgSend_stret to "void *" (see above comment). - cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, STDRE, - Context->getPointerType(Context->VoidTy), - SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, + Context->getPointerType(Context->VoidTy), + CastExpr::CK_Unknown, STDRE); // Now do the "normal" pointer to function cast. castType = Context->getFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0); castType = Context->getPointerType(castType); - cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, - cast, castType, SourceLocation(), SourceLocation()); + cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast); // Don't forget the parens to enforce the proper binding. PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); @@ -2819,10 +2812,9 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, Context->getPointerType(DRE->getType()), SourceLocation()); - CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(), - CastExpr::CK_Unknown, - DerefExpr, DerefExpr->getType(), - SourceLocation(), SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), + CastExpr::CK_Unknown, + DerefExpr); ReplaceStmt(Exp, castExpr); ProtocolExprDecls.insert(Exp->getProtocol()); // delete Exp; leak for now, see RewritePropertySetter() usage for more info. @@ -4043,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert declaration for the function in which block literal is used. - if (CurFunctionDeclToDeclareForBlock) + if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { @@ -4204,11 +4196,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); - CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock, - CastExpr::CK_Unknown, - const_cast<Expr*>(BlockExp), - PtrBlock, SourceLocation(), - SourceLocation()); + CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, + CastExpr::CK_Unknown, + const_cast<Expr*>(BlockExp)); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), BlkCast); @@ -4220,11 +4210,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType()); - CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType, - CastExpr::CK_Unknown, ME, - PtrToFuncCastType, - SourceLocation(), - SourceLocation()); + CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, + CastExpr::CK_Unknown, ME); PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); llvm::SmallVector<Expr*, 8> BlkExprs; @@ -4309,17 +4296,29 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) { const char *startBuf = SM->getCharacterData(LocStart); const char *endBuf = SM->getCharacterData(LocEnd); - + QualType QT = CE->getType(); + const Type* TypePtr = QT->getAs<Type>(); + if (isa<TypeOfExprType>(TypePtr)) { + const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr); + QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType(); + std::string TypeAsString = "("; + TypeAsString += QT.getAsString(); + TypeAsString += ")"; + ReplaceText(LocStart, endBuf-startBuf+1, + TypeAsString.c_str(), TypeAsString.size()); + return; + } + // advance the location to startArgList. const char *argPtr = startBuf; while (*argPtr++ && (argPtr < endBuf)) { switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); - ReplaceText(LocStart, 1, "*", 1); - break; + case '^': + // Replace the '^' with '*'. + LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf); + ReplaceText(LocStart, 1, "*", 1); + break; } } return; @@ -4344,17 +4343,17 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) { while (*argPtr++ && parenCount) { switch (*argPtr) { - case '^': - // Replace the '^' with '*'. - DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); - ReplaceText(DeclLoc, 1, "*", 1); - break; - case '(': - parenCount++; - break; - case ')': - parenCount--; - break; + case '^': + // Replace the '^' with '*'. + DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList); + ReplaceText(DeclLoc, 1, "*", 1); + break; + case '(': + parenCount++; + break; + case ')': + parenCount--; + break; } } return; @@ -4390,9 +4389,9 @@ void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen, while (*argPtr && parenCount) { switch (*argPtr) { - case '(': parenCount++; break; - case ')': parenCount--; break; - default: break; + case '(': parenCount++; break; + case ')': parenCount--; break; + default: break; } if (parenCount) argPtr++; } @@ -4557,8 +4556,13 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += " " + Name + ";\n"; ByrefType += "};\n"; // Insert this type in global scope. It is needed by helper function. - assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null"); - SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = CurFunctionDef->getTypeSpecStartLoc(); + else { + assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size()); if (Ty.isObjCGCWeak()) { flag |= BLOCK_FIELD_IS_WEAK; @@ -4608,12 +4612,17 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType.c_str(), ByrefType.size()); } else { - SourceLocation startLoc = ND->getInit()->getLocStart(); + SourceLocation startLoc; + Expr *E = ND->getInit(); + if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E)) + startLoc = ECE->getLParenLoc(); + else + startLoc = E->getLocStart(); startLoc = SM->getInstantiationLoc(startLoc); + endBuf = SM->getCharacterData(startLoc); + ByrefType += " " + Name; - ReplaceText(DeclLoc, endBuf-startBuf, - ByrefType.c_str(), ByrefType.size()); - ByrefType = " = {(void*)"; + ByrefType += " = {(void*)"; ByrefType += utostr(isa); ByrefType += ", &" + Name + ", "; ByrefType += utostr(flags); @@ -4628,7 +4637,8 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += utostr(flag); ByrefType += ", "; } - InsertText(startLoc, ByrefType.c_str(), ByrefType.size()); + ReplaceText(DeclLoc, endBuf-startBuf, + ByrefType.c_str(), ByrefType.size()); // Complete the newly synthesized compound expression by inserting a right // curly brace before the end of the declaration. @@ -4719,10 +4729,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { FD = SynthBlockInitFunctionDecl(Func.c_str()); DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, SourceLocation(), - SourceLocation()); + CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); InitExprs.push_back(castExpr); // Initialize the block descriptor. @@ -4753,11 +4761,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { } else if (isTopLevelBlockPointerType((*I)->getType())) { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg, - Context->VoidPtrTy, - SourceLocation(), - SourceLocation()); + Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, + CastExpr::CK_Unknown, Arg); } else { FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); @@ -4789,9 +4794,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) { NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, Context->getPointerType(NewRep->getType()), SourceLocation()); - NewRep = new (Context) CStyleCastExpr(FType, CastExpr::CK_Unknown, NewRep, - FType, SourceLocation(), - SourceLocation()); + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown, + NewRep); BlockDeclRefs.clear(); BlockByRefDecls.clear(); BlockByCopyDecls.clear(); diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index c0977b5..ce474d3 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -89,14 +89,14 @@ namespace { const char* pAttributeName = NAME; \ const bool optional = false; \ switch (S->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (S->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } @@ -189,17 +189,17 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { const char* pKind; switch (Node->getDecl()->getKind()) { - case Decl::Function: pKind = "FunctionDecl"; break; - case Decl::Var: pKind = "Var"; break; - case Decl::ParmVar: pKind = "ParmVar"; break; - case Decl::EnumConstant: pKind = "EnumConstant"; break; - case Decl::Typedef: pKind = "Typedef"; break; - case Decl::Record: pKind = "Record"; break; - case Decl::Enum: pKind = "Enum"; break; - case Decl::CXXRecord: pKind = "CXXRecord"; break; - case Decl::ObjCInterface: pKind = "ObjCInterface"; break; - case Decl::ObjCClass: pKind = "ObjCClass"; break; - default: pKind = "Decl"; break; + case Decl::Function: pKind = "FunctionDecl"; break; + case Decl::Var: pKind = "Var"; break; + case Decl::ParmVar: pKind = "ParmVar"; break; + case Decl::EnumConstant: pKind = "EnumConstant"; break; + case Decl::Typedef: pKind = "Typedef"; break; + case Decl::Record: pKind = "Record"; break; + case Decl::Enum: pKind = "Enum"; break; + case Decl::CXXRecord: pKind = "CXXRecord"; break; + case Decl::ObjCInterface: pKind = "ObjCInterface"; break; + case Decl::ObjCClass: pKind = "ObjCClass"; break; + default: pKind = "Decl"; break; } Doc.addAttribute("kind", pKind); @@ -210,10 +210,10 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) { DumpExpr(Node); switch (Node->getIdentType()) { - default: assert(0 && "unknown case"); - case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; - case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; - case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; + default: assert(0 && "unknown case"); + case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; + case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; + case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; } } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index fcefd4e..83b4542 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -428,6 +428,42 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, } } } + // Now that we have the entire fixit line, expand the tabs in it. + // Since we don't want to insert spaces in the middle of a word, + // find each word and the column it should line up with and insert + // spaces until they match. + if (!FixItInsertionLine.empty()) { + unsigned FixItPos = 0; + unsigned LinePos = 0; + unsigned TabExpandedCol = 0; + unsigned LineLength = LineEnd - LineStart; + + while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { + // Find the next word in the FixIt line. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] == ' ') + ++FixItPos; + unsigned CharDistance = FixItPos - TabExpandedCol; + + // Walk forward in the source line, keeping track of + // the tab-expanded column. + for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) + if (LinePos >= LineLength || LineStart[LinePos] != '\t') + ++TabExpandedCol; + else + TabExpandedCol = + (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; + + // Adjust the fixit line to match this column. + FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); + FixItPos = TabExpandedCol; + + // Walk to the end of the word. + while (FixItPos < FixItInsertionLine.size() && + FixItInsertionLine[FixItPos] != ' ') + ++FixItPos; + } + } } // If the source line is too long for our terminal, select only the diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp index 8bd0544..be9db42 100644 --- a/lib/Frontend/TypeXML.cpp +++ b/lib/Frontend/TypeXML.cpp @@ -43,14 +43,14 @@ public: const char* pAttributeName = NAME; \ const bool optional = false; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ { \ const char* pAttributeName = NAME; \ const bool optional = true; \ switch (T->FN) { \ - default: assert(0 && "unknown enum value"); + default: assert(0 && "unknown enum value"); #define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; #define END_ENUM_XML } } diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp index 81a5de4..4bb1594 100644 --- a/lib/Index/ResolveLocation.cpp +++ b/lib/Index/ResolveLocation.cpp @@ -264,7 +264,7 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { return ASTLocation(D); // Second, search through the declarations that are part of the function. - // If we find he location there, we won't have to search through its body. + // If we find the location there, we won't have to search through its body. for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 0a74b26..afd1ba8 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -210,6 +210,7 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) { } } +static bool isWhitespace(unsigned char c); /// MeasureTokenLength - Relex the token at the specified location and return /// its length in bytes in the input file. If the token needs cleaning (e.g. @@ -231,6 +232,9 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first); const char *StrData = Buffer.first+LocInfo.second; + if (isWhitespace(StrData[0])) + return 0; + // Create a lexer starting at the beginning of this token. Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second); TheLexer.SetCommentRetentionState(true); @@ -902,8 +906,10 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) { // SkipBCPLComment - We have just read the // characters from input. Skip until // we find the newline character thats terminate the comment. Then update -/// BufferPtr and return. If we're in KeepCommentMode, this will form the token -/// and return true. +/// BufferPtr and return. +/// +/// If we're in KeepCommentMode or any CommentHandler has inserted +/// some tokens, this will store the first token and return true. bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { // If BCPL comments aren't explicitly enabled for this language, emit an // extension warning. @@ -980,9 +986,12 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } while (C != '\n' && C != '\r'); // Found but did not consume the newline. - if (PP) - PP->HandleComment(SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr))); + if (PP && PP->HandleComment(Result, + SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { + BufferPtr = CurPtr; + return true; // A token has to be returned. + } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) @@ -1108,8 +1117,8 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, /// happen is the comment could end with an escaped newline between the */ end /// of comment. /// -/// If KeepCommentMode is enabled, this forms a token from the comment and -/// returns true. +/// If we're in KeepCommentMode or any CommentHandler has inserted +/// some tokens, this will store the first token and return true. bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { // Scan one character past where we should, looking for a '/' character. Once // we find it, check to see if it was preceeded by a *. This common @@ -1226,9 +1235,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { C = *CurPtr++; } - if (PP) - PP->HandleComment(SourceRange(getSourceLocation(BufferPtr), - getSourceLocation(CurPtr))); + if (PP && PP->HandleComment(Result, + SourceRange(getSourceLocation(BufferPtr), + getSourceLocation(CurPtr)))) { + BufferPtr = CurPtr; + return true; // A token has to be returned. + } // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) { @@ -1606,10 +1618,12 @@ LexNextToken: // too (without going through the big switch stmt). if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() && Features.BCPLComment) { - SkipBCPLComment(Result, CurPtr+2); + if (SkipBCPLComment(Result, CurPtr+2)) + return; // There is a token to return. goto SkipIgnoredUnits; } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) { - SkipBlockComment(Result, CurPtr+2); + if (SkipBlockComment(Result, CurPtr+2)) + return; // There is a token to return. goto SkipIgnoredUnits; } else if (isHorizontalWhitespace(*CurPtr)) { goto SkipHorizontalWhitespace; @@ -1795,7 +1809,7 @@ LexNextToken: if (Features.BCPLComment || getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') { if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) - return; // KeepCommentMode + return; // There is a token to return. // It is common for the tokens immediately after a // comment to be // whitespace (indentation for the next line). Instead of going through @@ -1806,7 +1820,7 @@ LexNextToken: if (Char == '*') { // /**/ comment. if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) - return; // KeepCommentMode + return; // There is a token to return. goto LexNextToken; // GCC isn't tail call eliminating. } diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 5cd5497..004e675 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -375,7 +375,7 @@ NumericLiteralParser(const char *begin, const char *end, continue; // Success. case 'i': if (PP.getLangOptions().Microsoft) { - if (isFPConstant || isUnsigned || isLong || isLongLong) break; + if (isFPConstant || isLong || isLongLong) break; // Allow i8, i16, i32, i64, and i128. if (s + 1 != ThisTokEnd) { diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index aa807f8..b0e784b 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -160,10 +160,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, CurPPLexer->LexingRawMode = true; Token Tok; while (1) { - if (CurLexer) - CurLexer->Lex(Tok); - else - CurPTHLexer->Lex(Tok); + CurLexer->Lex(Tok); // If this is the end of the buffer, we have an error. if (Tok.is(tok::eof)) { @@ -405,7 +402,6 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, - SourceLocation FilenameTokLoc, bool isAngled, const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir) { @@ -432,16 +428,7 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, CurDir = CurDirLookup; const FileEntry *FE = HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt); - if (FE) { - // Warn about normal quoted #include from framework headers. Since - // framework headers are published (both public and private ones) they - // should not do relative searches, they should do an include with the - // framework path included. - if (!isAngled && CurDir && FilenameTokLoc.isValid() && - CurDir->isFramework() && CurDir == CurDirLookup) - Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework); - return FE; - } + if (FE) return FE; // Otherwise, see if this is a subframework header. If so, this is relative // to one of the headers on the #include stack. Walk the list of the current @@ -1082,8 +1069,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), - isAngled, LookupFrom, CurDir); + const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3792782..13aeb88 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -567,9 +567,7 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = PP.LookupFile(Filename, - SourceLocation(),// produce no warnings. - isAngled, LookupFrom, CurDir); + const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir); // Get the result value. Result = true means the file exists. Result = File != 0; diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 856b3bd..63b23b6 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -301,8 +301,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(), - isAngled, 0, CurDir); + const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 26bb3a9..5689baa 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -429,21 +429,17 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, return TokStart.getFileLocWithOffset(PhysOffset); } -/// \brief Computes the source location just past the end of the -/// token at this source location. -/// -/// This routine can be used to produce a source location that -/// points just past the end of the token referenced by \p Loc, and -/// is generally used when a diagnostic needs to point just after a -/// token where it expected something different that it received. If -/// the returned source location would not be meaningful (e.g., if -/// it points into a macro), this routine returns an invalid -/// source location. -SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc) { +SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, + unsigned Offset) { if (Loc.isInvalid() || !Loc.isFileID()) return SourceLocation(); unsigned Len = Lexer::MeasureTokenLength(Loc, getSourceManager(), Features); + if (Len > Offset) + Len = Len - Offset; + else + return Loc; + return AdvanceToTokenCharacter(Loc, Len); } @@ -583,11 +579,18 @@ void Preprocessor::RemoveCommentHandler(CommentHandler *Handler) { CommentHandlers.erase(Pos); } -void Preprocessor::HandleComment(SourceRange Comment) { +bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { + bool AnyPendingTokens = false; for (std::vector<CommentHandler *>::iterator H = CommentHandlers.begin(), HEnd = CommentHandlers.end(); - H != HEnd; ++H) - (*H)->HandleComment(*this, Comment); + H != HEnd; ++H) { + if ((*H)->HandleComment(*this, Comment)) + AnyPendingTokens = true; + } + if (!AnyPendingTokens || getCommentRetentionState()) + return false; + Lex(result); + return true; } CommentHandler::~CommentHandler() { } diff --git a/lib/Makefile b/lib/Makefile index adf9474..d499ee5 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,8 +8,8 @@ ##===----------------------------------------------------------------------===## LEVEL = ../../.. -PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite \ - Frontend Index Driver +PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \ + Rewrite Frontend Index Driver include $(LEVEL)/Makefile.common diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index f52d8b9..9e5f5a2 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -373,11 +373,30 @@ void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, ProtocolLAngleLoc = LAngleLoc; } +void DeclSpec::SaveWrittenBuiltinSpecs() { + writtenBS.Sign = getTypeSpecSign(); + writtenBS.Width = getTypeSpecWidth(); + writtenBS.Type = getTypeSpecType(); + // Search the list of attributes for the presence of a mode attribute. + writtenBS.ModeAttr = false; + AttributeList* attrs = getAttributes(); + while (attrs) { + if (attrs->getKind() == AttributeList::AT_mode) { + writtenBS.ModeAttr = true; + break; + } + attrs = attrs->getNext(); + } +} + /// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { + // Before possibly changing their values, save specs as written. + SaveWrittenBuiltinSpecs(); + // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 8b207fa..5f48897 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -204,6 +204,7 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc, SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtocols, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { // Allocate and add the 'TypeNameInfo' "decl". diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 90040c5..efaf8ee 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -983,7 +983,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse an (optional) access specifier. AccessSpecifier Access = getAccessSpecifierIfPresent(); - if (Access) + if (Access != AS_none) ConsumeToken(); // Parse the 'virtual' keyword (again!), in case it came after the @@ -1398,15 +1398,35 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, PP.getSourceManager(), "parsing struct/union/class body"); - // Determine whether this is a top-level (non-nested) class. - bool TopLevelClass = ClassStack.empty() || - CurScope->isInCXXInlineMethodScope(); + // Determine whether this is a non-nested class. Note that local + // classes are *not* considered to be nested classes. + bool NonNestedClass = true; + if (!ClassStack.empty()) { + for (const Scope *S = CurScope; S; S = S->getParent()) { + if (S->isClassScope()) { + // We're inside a class scope, so this is a nested class. + NonNestedClass = false; + break; + } + + if ((S->getFlags() & Scope::FnScope)) { + // If we're in a function or function template declared in the + // body of a class, then this is a local class rather than a + // nested class. + const Scope *Parent = S->getParent(); + if (Parent->isTemplateParamScope()) + Parent = Parent->getParent(); + if (Parent->isClassScope()) + break; + } + } + } // Enter a scope for the class. ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); // Note that we are parsing a new (potentially-nested) class definition. - ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass); + ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); if (TagDecl) Actions.ActOnTagStartDefinition(CurScope, TagDecl); @@ -1484,7 +1504,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // // FIXME: Only function bodies and constructor ctor-initializers are // parsed correctly, fix the rest. - if (TopLevelClass) { + if (NonNestedClass) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. @@ -1666,10 +1686,10 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. -void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) { - assert((TopLevelClass || !ClassStack.empty()) && +void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) { + assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); - ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass)); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); } /// \brief Deallocate the given parsed class and all of its nested diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 5e23635..ae85aa3 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -186,6 +186,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( categoryId, categoryLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc); ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); @@ -224,6 +225,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc, attrList); if (Tok.is(tok::l_brace)) @@ -1127,6 +1129,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(), + ProtocolLocs.data(), EndProtoLoc, attrList); ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol); return ProtoType; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 0aecac9..f2bc303 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -29,8 +29,9 @@ class ActionCommentHandler : public CommentHandler { public: explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { } - virtual void HandleComment(Preprocessor &PP, SourceRange Comment) { + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) { Actions.ActOnComment(Comment); + return false; } }; diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp index 101cf93..35e888b 100644 --- a/lib/Rewrite/DeltaTree.cpp +++ b/lib/Rewrite/DeltaTree.cpp @@ -20,7 +20,7 @@ using llvm::cast; using llvm::dyn_cast; /// The DeltaTree class is a multiway search tree (BTree) structure with some -/// fancy features. B-Trees are are generally more memory and cache efficient +/// fancy features. B-Trees are generally more memory and cache efficient /// than binary trees, because they store multiple keys/values in each node. /// /// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index fbd1450..8c4caaf 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -572,11 +572,11 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; case Decl::ObjCImplementation: - Kind = CXCursor_ObjCClassDefn; + Kind = CXCursor_ObjCImplementationDecl; break; case Decl::ObjCCategoryImpl: - Kind = CXCursor_ObjCCategoryDefn; + Kind = CXCursor_ObjCCategoryImplDecl; break; default: diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h index 9064de6..f4cea2e 100644 --- a/lib/Sema/Lookup.h +++ b/lib/Sema/Lookup.h @@ -123,9 +123,7 @@ public: Temporary }; - typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy; - typedef DeclsTy::const_iterator iterator; - + typedef UnresolvedSetImpl::iterator iterator; typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS); LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, @@ -133,6 +131,7 @@ public: Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(SemaRef), Name(Name), NameLoc(NameLoc), @@ -152,6 +151,7 @@ public: LookupResult(TemporaryToken _, const LookupResult &Other) : ResultKind(NotFound), Paths(0), + NamingClass(0), SemaRef(Other.SemaRef), Name(Other.Name), NameLoc(Other.NameLoc), @@ -224,8 +224,8 @@ public: return Ambiguity; } - iterator begin() const { return Decls.begin(); } - iterator end() const { return Decls.end(); } + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } /// \brief Return true if no decls were found bool empty() const { return Decls.empty(); } @@ -247,32 +247,57 @@ public: return IDNS; } - /// \brief Add a declaration to these results. Does not test the - /// acceptance criteria. + /// \brief Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != 0; + } + + /// \brief Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// \brief Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// \brief Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. void addDecl(NamedDecl *D) { - Decls.push_back(D); + addDecl(D, D->getAccess()); + } + + /// \brief Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); ResultKind = Found; } /// \brief Add all the declarations from another set of lookup /// results. void addAllDecls(const LookupResult &Other) { - Decls.append(Other.begin(), Other.end()); + Decls.append(Other.Decls.begin(), Other.Decls.end()); ResultKind = Found; } - /// \brief Hides a set of declarations. - template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) { - unsigned I = 0, N = Decls.size(); - while (I < N) { - if (Set.count(Decls[I])) - Decls[I] = Decls[--N]; - else - I++; - } - Decls.set_size(N); - } - /// \brief Determine whether no result was found because we could not /// search into dependent base classes of the current instantiation. bool wasNotFoundInCurrentInstantiation() const { @@ -319,13 +344,13 @@ public: NamedDecl *getFoundDecl() const { assert(getResultKind() == Found && "getFoundDecl called on non-unique result"); - return Decls[0]->getUnderlyingDecl(); + return (*begin())->getUnderlyingDecl(); } /// Fetches a representative decl. Useful for lazy diagnostics. NamedDecl *getRepresentativeDecl() const { assert(!Decls.empty() && "cannot get representative of empty set"); - return Decls[0]; + return *begin(); } /// \brief Asks if the result is a single tag decl. @@ -403,7 +428,7 @@ public: /// sugared. class Filter { LookupResult &Results; - unsigned I; + LookupResult::iterator I; bool Changed; #ifndef NDEBUG bool CalledDone; @@ -411,7 +436,7 @@ public: friend class LookupResult; Filter(LookupResult &Results) - : Results(Results), I(0), Changed(false) + : Results(Results), I(Results.begin()), Changed(false) #ifndef NDEBUG , CalledDone(false) #endif @@ -426,23 +451,30 @@ public: #endif bool hasNext() const { - return I != Results.Decls.size(); + return I != Results.end(); } NamedDecl *next() { - assert(I < Results.Decls.size() && "next() called on empty filter"); - return Results.Decls[I++]; + assert(I != Results.end() && "next() called on empty filter"); + return *I++; } /// Erase the last element returned from this iterator. void erase() { - Results.Decls[--I] = Results.Decls.back(); - Results.Decls.pop_back(); + Results.Decls.erase(--I); Changed = true; } + /// Replaces the current entry with the given one, preserving the + /// access bits. void replace(NamedDecl *D) { - Results.Decls[I-1] = D; + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); Changed = true; } @@ -466,6 +498,8 @@ private: void diagnose() { if (isAmbiguous()) SemaRef.DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && SemaRef.getLangOptions().AccessControl) + SemaRef.CheckAccess(*this); } void setAmbiguous(AmbiguityKind AK) { @@ -482,7 +516,7 @@ private: assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind != FoundOverloaded || Decls.size() > 1 || (Decls.size() == 1 && - isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl()))); + isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); @@ -492,8 +526,7 @@ private: } bool sanityCheckUnresolved() const { - for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end(); - I != E; ++I) + for (iterator I = begin(), E = end(); I != E; ++I) if (isa<UnresolvedUsingValueDecl>(*I)) return true; return false; @@ -504,8 +537,9 @@ private: // Results. LookupResultKind ResultKind; AmbiguityKind Ambiguity; // ill-defined unless ambiguous - DeclsTy Decls; + UnresolvedSet<8> Decls; CXXBasePaths *Paths; + CXXRecordDecl *NamingClass; // Parameters. Sema &SemaRef; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fab7292..06e9e3a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1291,6 +1291,17 @@ public: ObjCContainerDecl* IDecl, bool IncompleteImpl = false); + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap); + + /// CollectImmediateProperties - This routine collects all properties in + /// the class and its conforming protocols; but not those it its super class. + void CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap); + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. @@ -1651,6 +1662,11 @@ public: virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + ExprArg Op); + virtual bool TypeIsVectorType(TypeTy *Ty) { return GetTypeFromParser(Ty)->isVectorType(); } @@ -1658,13 +1674,18 @@ public: OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg E, - QualType Ty); + TypeSourceInfo *TInfo); virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op); + OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + ExprArg InitExpr); + virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, MultiExprArg InitList, SourceLocation RParenLoc); @@ -1920,6 +1941,13 @@ public: ExprArg E, SourceLocation RParenLoc); + OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + ExprArg E, + SourceRange AngleBrackets, + SourceRange Parens); + /// ActOnCXXTypeid - Parse typeid( something ). virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, @@ -2033,7 +2061,6 @@ public: bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); bool isUnknownSpecialization(const CXXScopeSpec &SS); - bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -2334,6 +2361,9 @@ public: CXXBasePaths &Paths, bool NoPrivileges = false); + void CheckAccess(const LookupResult &R); + bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access); + bool CheckBaseClassAccess(QualType Derived, QualType Base, unsigned InaccessibleBaseID, CXXBasePaths& Paths, SourceLocation AccessLoc, @@ -3153,13 +3183,17 @@ public: /// relevant to this particular scope). LocalInstantiationScope *Outer; + /// \brief Whether we have already exited this scope. + bool Exited; + // This class is non-copyable LocalInstantiationScope(const LocalInstantiationScope &); LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false) { if (!CombineWithOuterScope) SemaRef.CurrentInstantiationScope = this; else @@ -3168,7 +3202,15 @@ public: } ~LocalInstantiationScope() { + if (!Exited) + SemaRef.CurrentInstantiationScope = Outer; + } + + /// \brief Exit this local instantiation scope early. + void Exit() { SemaRef.CurrentInstantiationScope = Outer; + LocalDecls.clear(); + Exited = true; } Decl *getInstantiationOf(const Decl *D) { @@ -3215,7 +3257,16 @@ public: /// but have not yet been performed. std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations; - void PerformPendingImplicitInstantiations(); + /// \brief The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + void PerformPendingImplicitInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3300,6 +3351,7 @@ public: SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3317,6 +3369,7 @@ public: SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); @@ -3327,6 +3380,7 @@ public: SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc); virtual DeclPtrTy ActOnStartClassImplementation( @@ -3373,14 +3427,13 @@ public: ObjCMethodDecl *MethodDecl, bool IsInstance); - void MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeProtocols); + void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); - void MergeOneProtocolPropertiesIntoClass(Decl *CDecl, - ObjCProtocolDecl *PDecl); + void MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl); virtual void ActOnAtEnd(SourceRange AtEnd, DeclPtrTy classDecl, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index b7cc37b..51f9e30 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -137,3 +138,101 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base, return false; } + +/// Diagnose the path which caused the given declaration to become +/// inaccessible. +static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + // Easy case: the decl's natural access determined its path access. + if (Access == D->getAccess() || D->getAccess() == AS_private) { + S.Diag(D->getLocation(), diag::note_access_natural) + << (unsigned) (Access == AS_protected); + return; + } + + // TODO: flesh this out + S.Diag(D->getLocation(), diag::note_access_constrained_by_path) + << (unsigned) (Access == AS_protected); +} + +/// Checks access to the given declaration in the current context. +/// +/// \param R the means via which the access was made; must have a naming +/// class set +/// \param D the declaration accessed +/// \param Access the best access along any inheritance path from the +/// naming class to the declaration. AS_none means the path is impossible +bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D, + AccessSpecifier Access) { + assert(R.getNamingClass() && "performing access check without naming class"); + + // If the access path is public, it's accessible everywhere. + if (Access == AS_public) + return false; + + // Otherwise, derive the current class context. + DeclContext *DC = CurContext; + while (isa<CXXRecordDecl>(DC) && + cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion()) + DC = DC->getParent(); + + CXXRecordDecl *CurRecord; + if (isa<CXXRecordDecl>(DC)) + CurRecord = cast<CXXRecordDecl>(DC); + else if (isa<CXXMethodDecl>(DC)) + CurRecord = cast<CXXMethodDecl>(DC)->getParent(); + else { + Diag(R.getNameLoc(), diag::err_access_outside_class) + << (Access == AS_protected); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + CXXRecordDecl *NamingClass = R.getNamingClass(); + while (NamingClass->isAnonymousStructOrUnion()) + // This should be guaranteed by the fact that the decl has + // non-public access. If not, we should make it guaranteed! + NamingClass = cast<CXXRecordDecl>(NamingClass); + + // White-list accesses from within the declaring class. + if (Access != AS_none && + CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl()) + return false; + + // Protected access. + if (Access == AS_protected) { + // FIXME: implement [class.protected]p1 + if (CurRecord->isDerivedFrom(NamingClass)) + return false; + + // FIXME: dependent classes + } + + // FIXME: friends + + // Okay, it's a bad access, reject it. + + + CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext()); + + if (Access == AS_protected) { + Diag(R.getNameLoc(), diag::err_access_protected) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; + } + + assert(Access == AS_private || Access == AS_none); + Diag(R.getNameLoc(), diag::err_access_private) + << Context.getTypeDeclType(DeclaringClass) + << Context.getTypeDeclType(CurRecord); + DiagnoseAccessPath(*this, R, D, Access); + return true; +} + +/// Checks access to all the declarations in the given result set. +void Sema::CheckAccess(const LookupResult &R) { + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + CheckAccess(R, *I, I.getAccess()); +} diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index f924bd3..57c4f9b 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -116,11 +116,26 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, ExprArg E, SourceLocation RParenLoc) { + + TypeSourceInfo *DestTInfo; + QualType DestType = GetTypeFromParser(Ty, &DestTInfo); + if (!DestTInfo) + DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation()); + + return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E), + SourceRange(LAngleBracketLoc, RAngleBracketLoc), + SourceRange(LParenLoc, RParenLoc)); +} + +Action::OwningExprResult +Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, + TypeSourceInfo *DestTInfo, ExprArg E, + SourceRange AngleBrackets, SourceRange Parens) { Expr *Ex = E.takeAs<Expr>(); - // FIXME: Preserve type source info. - QualType DestType = GetTypeFromParser(Ty); - SourceRange OpRange(OpLoc, RParenLoc); - SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc); + QualType DestType = DestTInfo->getType(); + + SourceRange OpRange(OpLoc, Parens.getEnd()); + SourceRange DestRange = AngleBrackets; // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? @@ -133,14 +148,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, if (!TypeDependent) CheckConstCast(*this, Ex, DestType, OpRange, DestRange); return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(), - Ex, DestType, OpLoc)); + Ex, DestTInfo, OpLoc)); case tok::kw_dynamic_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; if (!TypeDependent) CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_reinterpret_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -148,7 +163,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); return Owned(new (Context) CXXReinterpretCastExpr( DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } case tok::kw_static_cast: { CastExpr::CastKind Kind = CastExpr::CK_Unknown; @@ -169,7 +184,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, } return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(), - Kind, Ex, DestType, OpLoc)); + Kind, Ex, DestTInfo, OpLoc)); } } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 8594583..7a0b625 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -30,9 +30,9 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, if (T.isNull()) return 0; - T = Context.getCanonicalType(T); + T = Context.getCanonicalType(T).getUnqualifiedType(); - for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + 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()) @@ -210,28 +210,6 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { return getCurrentInstantiationOf(NNS) == 0; } -/// \brief Determine whether the given scope specifier refers to a -/// current instantiation that has any dependent base clases. -/// -/// This check is typically used when we've performed lookup into the -/// current instantiation of a template, but that lookup failed. When -/// there are dependent bases present, however, the lookup needs to be -/// delayed until template instantiation time. -bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) { - if (!SS.isSet()) - return false; - - NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep(); - if (!NNS->isDependent()) - return false; - - CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS); - if (!CurrentInstantiation) - return false; - - return CurrentInstantiation->hasAnyDependentBases(); -} - /// \brief If the given nested name specifier refers to the current /// instantiation, return the declaration that corresponds to that /// current instantiation (C++0x [temp.dep.type]p1). diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 5f124e4..6ff8b1d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,14 +13,22 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/PathSensitive/AnalysisContext.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include <limits> +#include <queue> using namespace clang; /// getLocationOfStringLiteralByte - Return a source location that points to the @@ -2029,3 +2037,522 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } +// MarkLive - Mark all the blocks reachable from e as live. Returns the total +// number of blocks just marked live. +static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) { + unsigned count = 0; + std::queue<CFGBlock*> workq; + // Prep work queue + live.set(e->getBlockID()); + ++count; + workq.push(e); + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + ++count; + workq.push(*I); + } + } + } + return count; +} + +static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1, + SourceRange &R2) { + Stmt *S; + unsigned sn = 0; + R1 = R2 = SourceRange(); + + top: + if (sn < b.size()) + S = b[sn].getStmt(); + else if (b.getTerminator()) + S = b.getTerminator(); + else + return SourceLocation(); + + switch (S->getStmtClass()) { + case Expr::BinaryOperatorClass: { + BinaryOperator *BO = cast<BinaryOperator>(S); + if (BO->getOpcode() == BinaryOperator::Comma) { + if (sn+1 < b.size()) + return b[sn+1].getStmt()->getLocStart(); + CFGBlock *n = &b; + while (1) { + if (n->getTerminator()) + return n->getTerminator()->getLocStart(); + if (n->succ_size() != 1) + return SourceLocation(); + n = n[0].succ_begin()[0]; + if (n->pred_size() != 1) + return SourceLocation(); + if (!n->empty()) + return n[0][0].getStmt()->getLocStart(); + } + } + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return BO->getOperatorLoc(); + } + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(S); + R1 = UO->getSubExpr()->getSourceRange(); + return UO->getOperatorLoc(); + } + case Expr::CompoundAssignOperatorClass: { + const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); + R1 = CAO->getLHS()->getSourceRange(); + R2 = CAO->getRHS()->getSourceRange(); + return CAO->getOperatorLoc(); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(S); + return CO->getQuestionLoc(); + } + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(S); + R1 = ME->getSourceRange(); + return ME->getMemberLoc(); + } + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); + R1 = ASE->getLHS()->getSourceRange(); + R2 = ASE->getRHS()->getSourceRange(); + return ASE->getRBracketLoc(); + } + case Expr::CStyleCastExprClass: { + const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); + R1 = CSC->getSubExpr()->getSourceRange(); + return CSC->getLParenLoc(); + } + case Expr::CXXFunctionalCastExprClass: { + const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); + R1 = CE->getSubExpr()->getSourceRange(); + return CE->getTypeBeginLoc(); + } + case Expr::ImplicitCastExprClass: + ++sn; + goto top; + case Stmt::CXXTryStmtClass: { + return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); + } + default: ; + } + R1 = S->getSourceRange(); + return S->getLocStart(); +} + +static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, + SourceManager &SM) { + std::queue<CFGBlock*> workq; + // Prep work queue + workq.push(e); + SourceRange R1, R2; + SourceLocation top = GetUnreachableLoc(*e, R1, R2); + bool FromMainFile = false; + bool FromSystemHeader = false; + bool TopValid = false; + if (top.isValid()) { + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + TopValid = true; + } + // Solve + while (!workq.empty()) { + CFGBlock *item = workq.front(); + workq.pop(); + SourceLocation c = GetUnreachableLoc(*item, R1, R2); + if (c.isValid() + && (!TopValid + || (SM.isFromMainFile(c) && !FromMainFile) + || (FromSystemHeader && !SM.isInSystemHeader(c)) + || SM.isBeforeInTranslationUnit(c, top))) { + top = c; + FromMainFile = SM.isFromMainFile(top); + FromSystemHeader = SM.isInSystemHeader(top); + } + live.set(item->getBlockID()); + for (CFGBlock::succ_iterator I=item->succ_begin(), + E=item->succ_end(); + I != E; + ++I) { + if ((*I) && !live[(*I)->getBlockID()]) { + live.set((*I)->getBlockID()); + workq.push(*I); + } + } + } + return top; +} + +static int LineCmp(const void *p1, const void *p2) { + SourceLocation *Line1 = (SourceLocation *)p1; + SourceLocation *Line2 = (SourceLocation *)p2; + return !(*Line1 < *Line2); +} + +namespace { + struct ErrLoc { + SourceLocation Loc; + SourceRange R1; + SourceRange R2; + ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) + : Loc(l), R1(r1), R2(r2) { } + }; +} + +/// CheckUnreachable - Check for unreachable code. +void Sema::CheckUnreachable(AnalysisContext &AC) { + unsigned count; + // We avoid checking when there are errors, as the CFG won't faithfully match + // the user's code. + if (getDiagnostics().hasErrorOccurred()) + return; + if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) + return; + + CFG *cfg = AC.getCFG(); + if (cfg == 0) + return; + + llvm::BitVector live(cfg->getNumBlockIDs()); + // Mark all live things first. + count = MarkLive(&cfg->getEntry(), live); + + if (count == cfg->getNumBlockIDs()) + // If there are no dead blocks, we're done. + return; + + SourceRange R1, R2; + + llvm::SmallVector<ErrLoc, 24> lines; + bool AddEHEdges = AC.getAddEHEdges(); + // First, give warnings for blocks with no predecessors, as they + // can't be part of a loop. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (!AddEHEdges && b.getTerminator() + && isa<CXXTryStmt>(b.getTerminator())) { + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + SourceLocation c = GetUnreachableLoc(b, R1, R2); + if (!c.isValid()) { + // Blocks without a location can't produce a warning, so don't mark + // reachable blocks from here as live. + live.set(b.getBlockID()); + ++count; + continue; + } + lines.push_back(ErrLoc(c, R1, R2)); + // Avoid excessive errors by marking everything reachable from here + count += MarkLive(&b, live); + } + } + } + + if (count < cfg->getNumBlockIDs()) { + // And then give warnings for the tops of loops. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) + // Avoid excessive errors by marking everything reachable from here + lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange())); + } + } + + llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); + for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(), + E = lines.end(); + I != E; + ++I) + if (I->Loc.isValid()) + Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2; +} + +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// MaybeFallThrough iff we might or might not fall off the end, +/// NeverFallThroughOrReturn iff we never fall off the end of the statement or +/// return. We assume NeverFallThrough iff we never fall off the end of the +/// statement but we may return. We assume that functions not marked noreturn +/// will return. +Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { + CFG *cfg = AC.getCFG(); + if (cfg == 0) + // FIXME: This should be NeverFallThrough + return NeverFallThroughOrReturn; + + // 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 = MarkLive(&cfg->getEntry(), live); + + bool AddEHEdges = AC.getAddEHEdges(); + if (!AddEHEdges && count != cfg->getNumBlockIDs()) + // When there are things remaining dead, and we didn't add EH edges + // from CallExprs to the catch clauses, we have to go back and + // mark them as live. + for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { + CFGBlock &b = **I; + if (!live[b.getBlockID()]) { + if (b.pred_begin() == b.pred_end()) { + if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) + // When not adding EH edges from calls, catch clauses + // can otherwise seem dead. Avoid noting them as dead. + count += MarkLive(&b, live); + continue; + } + } + } + + // Now we know what is live, we check the live precessors of the exit block + // and look for fall through paths, being careful to ignore normal returns, + // and exceptional paths. + bool HasLiveReturn = false; + bool HasFakeEdge = false; + bool HasPlainEdge = false; + bool HasAbnormalEdge = false; + for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), + E = cfg->getExit().pred_end(); + I != E; + ++I) { + CFGBlock& B = **I; + if (!live[B.getBlockID()]) + continue; + if (B.size() == 0) { + if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { + HasAbnormalEdge = true; + continue; + } + + // A labeled empty statement, or the entry block... + HasPlainEdge = true; + continue; + } + Stmt *S = B[B.size()-1]; + if (isa<ReturnStmt>(S)) { + HasLiveReturn = true; + continue; + } + if (isa<ObjCAtThrowStmt>(S)) { + HasFakeEdge = true; + continue; + } + if (isa<CXXThrowExpr>(S)) { + HasFakeEdge = true; + continue; + } + if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { + if (AS->isMSAsm()) { + HasFakeEdge = true; + HasLiveReturn = true; + continue; + } + } + if (isa<CXXTryStmt>(S)) { + HasAbnormalEdge = true; + continue; + } + + bool NoReturnEdge = false; + if (CallExpr *C = dyn_cast<CallExpr>(S)) { + if (B.succ_begin()[0] != &cfg->getExit()) { + HasAbnormalEdge = true; + continue; + } + Expr *CEE = C->getCallee()->IgnoreParenCasts(); + if (CEE->getType().getNoReturnAttr()) { + NoReturnEdge = true; + HasFakeEdge = true; + } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { + ValueDecl *VD = DRE->getDecl(); + if (VD->hasAttr<NoReturnAttr>()) { + NoReturnEdge = true; + HasFakeEdge = true; + } + } + } + // FIXME: Add noreturn message sends. + if (NoReturnEdge == false) + HasPlainEdge = true; + } + if (!HasPlainEdge) { + if (HasLiveReturn) + return NeverFallThrough; + return NeverFallThroughOrReturn; + } + if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) + return MaybeFallThrough; + // This says AlwaysFallThrough for calls to functions that are not marked + // noreturn, that don't return. If people would like this warning to be more + // accurate, such functions should be marked as noreturn. + return AlwaysFallThrough; +} + +/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// function that should return a value. Check that we don't fall off the end +/// of a noreturn function. We assume that functions and blocks not marked +/// noreturn will return. +void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // If the result type of the function is a dependent type, we don't know + // whether it will be void or not, so don't + if (FD->getResultType()->isDependentType()) + return; + if (FD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (MD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Function try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckFallThroughForBlock - Check that we don't fall off the end of a block +/// that should return a value. Check that we don't fall off the end of a +/// noreturn block. We assume that functions and blocks not marked noreturn +/// will return. +void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, + AnalysisContext &AC) { + // FIXME: Would be nice if we had a better way to control cascading errors, + // but for now, avoid them. The problem is that when Parse sees: + // int foo() { return a; } + // The return is eaten and the Sema code sees just: + // int foo() { } + // which this code would then warn about. + if (getDiagnostics().hasErrorOccurred()) + return; + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + + // Short circuit for compilation speed. + if (ReturnsVoid + && !HasNoReturn + && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid)) + return; + // FIXME: Funtion try block + if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); + break; + case AlwaysFallThrough: + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid) + Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); + break; + case NeverFallThrough: + break; + } + } +} + +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + // + // This is also C++ [dcl.fct]p6. + if (!Param->isInvalidDecl() && + RequireCompleteType(Param->getLocation(), Param->getType(), + diag::err_typecheck_decl_incomplete_type)) { + Param->setInvalidDecl(); + HasInvalidParm = true; + } + + // C99 6.9.1p5: If the declarator includes a parameter type list, the + // declaration of each parameter shall include an identifier. + if (Param->getIdentifier() == 0 && + !Param->isImplicit() && + !getLangOptions().CPlusPlus) + Diag(Param->getLocation(), diag::err_parameter_name_omitted); + } + + return HasInvalidParm; +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index a4cda01..fcd419b 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2234,30 +2234,36 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // FIXME: What if we're calling a pseudo-destructor? // FIXME: What if we're calling a member function? + typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; + llvm::SmallVector<ResultCandidate, 8> Results; + Expr *NakedFn = Fn->IgnoreParenCasts(); if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet, /*PartialOverloading=*/ true); else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) { FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); - if (FDecl) - AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, - false, false, /*PartialOverloading*/ true); + if (FDecl) { + if (!FDecl->getType()->getAs<FunctionProtoType>()) + Results.push_back(ResultCandidate(FDecl)); + else + AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet, + false, false, /*PartialOverloading*/ true); + } } - // Sort the overload candidate set by placing the best overloads first. - std::stable_sort(CandidateSet.begin(), CandidateSet.end(), - IsBetterOverloadCandidate(*this)); + if (!CandidateSet.empty()) { + // Sort the overload candidate set by placing the best overloads first. + std::stable_sort(CandidateSet.begin(), CandidateSet.end(), + IsBetterOverloadCandidate(*this)); - // Add the remaining viable overload candidates as code-completion reslults. - typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate; - llvm::SmallVector<ResultCandidate, 8> Results; - - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - CandEnd = CandidateSet.end(); - Cand != CandEnd; ++Cand) { - if (Cand->Viable) - Results.push_back(ResultCandidate(Cand->Function)); + // Add the remaining viable overload candidates as code-completion reslults. + for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), + CandEnd = CandidateSet.end(); + Cand != CandEnd; ++Cand) { + if (Cand->Viable) + Results.push_back(ResultCandidate(Cand->Function)); + } } if (Results.empty()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0ccb8f2..fbe0289 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -18,13 +18,10 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/Analysis/CFG.h" #include "clang/AST/CXXInheritance.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtObjC.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Template.h" @@ -34,13 +31,10 @@ // FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's) #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include <algorithm> #include <cstring> #include <functional> -#include <queue> using namespace clang; /// getDeclName - Return a pretty name for the specified decl if possible, or @@ -1305,382 +1299,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // Keep a chain of previous declarations. New->setPreviousDeclaration(Old); -} - -static void MarkLive(CFGBlock *e, llvm::BitVector &live) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } -} - -static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live, - SourceManager &SM) { - std::queue<CFGBlock*> workq; - // Prep work queue - workq.push(e); - SourceLocation top; - if (!e->empty()) - top = e[0][0].getStmt()->getLocStart(); - bool FromMainFile = false; - bool FromSystemHeader = false; - bool TopValid = false; - if (top.isValid()) { - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - TopValid = true; - } - // Solve - while (!workq.empty()) { - CFGBlock *item = workq.front(); - workq.pop(); - SourceLocation c; - if (!item->empty()) - c = item[0][0].getStmt()->getLocStart(); - else if (item->getTerminator()) - c = item->getTerminator()->getLocStart(); - if (c.isValid() - && (!TopValid - || (SM.isFromMainFile(c) && !FromMainFile) - || (FromSystemHeader && !SM.isInSystemHeader(c)) - || SM.isBeforeInTranslationUnit(c, top))) { - top = c; - FromMainFile = SM.isFromMainFile(top); - FromSystemHeader = SM.isInSystemHeader(top); - } - live.set(item->getBlockID()); - for (CFGBlock::succ_iterator I=item->succ_begin(), - E=item->succ_end(); - I != E; - ++I) { - if ((*I) && !live[(*I)->getBlockID()]) { - live.set((*I)->getBlockID()); - workq.push(*I); - } - } - } - return top; -} -namespace { -class LineCmp { - SourceManager &SM; -public: - LineCmp(SourceManager &sm) : SM(sm) { - } - bool operator () (SourceLocation l1, SourceLocation l2) { - return l1 < l2; - } -}; -} - -/// CheckUnreachable - Check for unreachable code. -void Sema::CheckUnreachable(AnalysisContext &AC) { - // We avoid checking when there are errors, as the CFG won't faithfully match - // the user's code. - if (getDiagnostics().hasErrorOccurred()) - return; - if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - CFG *cfg = AC.getCFG(); - if (cfg == 0) - return; - - llvm::BitVector live(cfg->getNumBlockIDs()); - // Mark all live things first. - MarkLive(&cfg->getEntry(), live); - - llvm::SmallVector<SourceLocation, 24> lines; - // First, give warnings for blocks with no predecessors, as they - // can't be part of a loop. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) { - if (b.pred_begin() == b.pred_end()) { - if (!b.empty()) - lines.push_back(b[0].getStmt()->getLocStart()); - else if (b.getTerminator()) - lines.push_back(b.getTerminator()->getLocStart()); - // Avoid excessive errors by marking everything reachable from here - MarkLive(&b, live); - } - } - } - - // And then give warnings for the tops of loops. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - CFGBlock &b = **I; - if (!live[b.getBlockID()]) - // Avoid excessive errors by marking everything reachable from here - lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager())); - } - - std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager())); - for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(), - E = lines.end(); - I != E; - ++I) - if (I->isValid()) - Diag(*I, diag::warn_unreachable); -} - -/// CheckFallThrough - Check that we don't fall off the end of a -/// Statement that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// MaybeFallThrough iff we might or might not fall off the end, -/// NeverFallThroughOrReturn iff we never fall off the end of the statement or -/// return. We assume NeverFallThrough iff we never fall off the end of the -/// statement but we may return. We assume that functions not marked noreturn -/// will return. -Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) { - CFG *cfg = AC.getCFG(); - if (cfg == 0) - // FIXME: This should be NeverFallThrough - return NeverFallThroughOrReturn; - - // The CFG leaves in dead things, and we don't want to dead code paths to - // confuse us, so we mark all live things first. - std::queue<CFGBlock*> workq; - llvm::BitVector live(cfg->getNumBlockIDs()); - MarkLive(&cfg->getEntry(), live); - - // Now we know what is live, we check the live precessors of the exit block - // and look for fall through paths, being careful to ignore normal returns, - // and exceptional paths. - bool HasLiveReturn = false; - bool HasFakeEdge = false; - bool HasPlainEdge = false; - for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(), - E = cfg->getExit().pred_end(); - I != E; - ++I) { - CFGBlock& B = **I; - if (!live[B.getBlockID()]) - continue; - if (B.size() == 0) { - // A labeled empty statement, or the entry block... - HasPlainEdge = true; - continue; - } - Stmt *S = B[B.size()-1]; - if (isa<ReturnStmt>(S)) { - HasLiveReturn = true; - continue; - } - if (isa<ObjCAtThrowStmt>(S)) { - HasFakeEdge = true; - continue; - } - if (isa<CXXThrowExpr>(S)) { - HasFakeEdge = true; - continue; - } - if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - if (CEE->getType().getNoReturnAttr()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } - } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; - } - if (!HasPlainEdge) { - if (HasLiveReturn) - return NeverFallThrough; - return NeverFallThroughOrReturn; - } - if (HasFakeEdge || HasLiveReturn) - return MaybeFallThrough; - // This says AlwaysFallThrough for calls to functions that are not marked - // noreturn, that don't return. If people would like this warning to be more - // accurate, such functions should be marked as noreturn. - return AlwaysFallThrough; -} - -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a -/// function that should return a value. Check that we don't fall off the end -/// of a noreturn function. We assume that functions and blocks not marked -/// noreturn will return. -void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - // If the result type of the function is a dependent type, we don't know - // whether it will be void or not, so don't - if (FD->getResultType()->isDependentType()) - return; - if (FD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (MD->getResultType()->isVoidType()) - ReturnsVoid = true; - if (MD->hasAttr<NoReturnAttr>()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored || ReturnsVoid) - && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) - == Diagnostic::Ignored || !HasNoReturn) - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Function try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckFallThroughForBlock - Check that we don't fall off the end of a block -/// that should return a value. Check that we don't fall off the end of a -/// noreturn block. We assume that functions and blocks not marked noreturn -/// will return. -void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body, - AnalysisContext &AC) { - // FIXME: Would be nice if we had a better way to control cascading errors, - // but for now, avoid them. The problem is that when Parse sees: - // int foo() { return a; } - // The return is eaten and the Sema code sees just: - // int foo() { } - // which this code would then warn about. - if (getDiagnostics().hasErrorOccurred()) - return; - bool ReturnsVoid = false; - bool HasNoReturn = false; - if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){ - if (FT->getResultType()->isVoidType()) - ReturnsVoid = true; - if (FT->getNoReturnAttr()) - HasNoReturn = true; - } - - // Short circuit for compilation speed. - if (ReturnsVoid - && !HasNoReturn - && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block) - == Diagnostic::Ignored || !ReturnsVoid)) - return; - // FIXME: Funtion try block - if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { - switch (CheckFallThrough(AC)) { - case MaybeFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block); - break; - case AlwaysFallThrough: - if (HasNoReturn) - Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr); - else if (!ReturnsVoid) - Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block); - break; - case NeverFallThroughOrReturn: - if (ReturnsVoid) - Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block); - break; - case NeverFallThrough: - break; - } - } -} - -/// CheckParmsForFunctionDef - Check that the parameters of the given -/// function are appropriate for the definition of a function. This -/// takes care of any checks that cannot be performed on the -/// declaration itself, e.g., that the types of each of the function -/// parameters are complete. -bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { - bool HasInvalidParm = false; - for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - - // C99 6.7.5.3p4: the parameters in a parameter type list in a - // function declarator that is part of a function definition of - // that function shall not have incomplete type. - // - // This is also C++ [dcl.fct]p6. - if (!Param->isInvalidDecl() && - RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { - Param->setInvalidDecl(); - HasInvalidParm = true; - } - - // C99 6.9.1p5: If the declarator includes a parameter type list, the - // declaration of each parameter shall include an identifier. - if (Param->getIdentifier() == 0 && - !Param->isImplicit() && - !getLangOptions().CPlusPlus) - Diag(Param->getLocation(), diag::err_parameter_name_omitted); - } - - return HasInvalidParm; + // Inherit access appropriately. + New->setAccess(Old->getAccess()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -1773,6 +1394,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { /// \return true if this is a forbidden redeclaration static bool CheckAnonMemberRedeclaration(Sema &SemaRef, Scope *S, + DeclContext *Owner, DeclarationName Name, SourceLocation NameLoc, unsigned diagnostic) { @@ -1785,6 +1407,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, // Pick a representative declaration. NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl(); + if (PrevDecl && Owner->isRecord()) { + RecordDecl *Record = cast<RecordDecl>(Owner); + if (!SemaRef.isDeclInScope(PrevDecl, Record, S)) + return false; + } SemaRef.Diag(NameLoc, diagnostic) << Name; SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -1819,7 +1446,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner, FEnd = AnonRecord->field_end(); F != FEnd; ++F) { if ((*F)->getDeclName()) { - if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(), + if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(), (*F)->getLocation(), diagKind)) { // C++ [class.union]p2: // The names of the members of an anonymous union shall be @@ -3243,7 +2870,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Synthesize a parameter for each argument type. for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(), AE = FT->arg_type_end(); AI != AE; ++AI) { - ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, + ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(), 0, *AI, /*TInfo=*/0, VarDecl::None, 0); @@ -3322,6 +2949,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { + // Fake up an access specifier if it's supposed to be a class member. + if (isa<CXXRecordDecl>(NewFD->getDeclContext())) + NewFD->setAccess(AS_public); + // An out-of-line member function declaration must also be a // definition (C++ [dcl.meaning]p1). // Note that this is not the case for explicit specializations of @@ -3332,7 +2963,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); - } else if (!Redeclaration) { + } else if (!Redeclaration && + !(isFriend && CurContext->isDependentContext())) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, @@ -4236,8 +3868,13 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { 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, CurContext, D.getIdentifierLoc(), II, + = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II, T, TInfo, StorageClass, 0); if (D.isInvalidType()) @@ -4476,7 +4113,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - AnalysisContext AC(dcl); + // 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(dcl, false); FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); if (FunTmpl) @@ -6064,7 +5703,8 @@ 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, LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(IdLoc, PrevDecl); @@ -6092,8 +5732,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, IdLoc, Id, Owned(Val)); // Register this decl in the current scope stack. - if (New) + if (New) { + New->setAccess(TheEnumDecl->getAccess()); PushOnScopeChains(New, S); + } return DeclPtrTy::make(New); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a81a04e..9ec95f3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1062,8 +1062,23 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, if (!TyD) { if (R.isAmbiguous()) return true; + if (SS.isSet() && isDependentScopeSpecifier(SS)) { + bool NotUnknownSpecialization = false; + DeclContext *DC = computeDeclContext(SS, false); + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC)) + NotUnknownSpecialization = !Record->hasAnyDependentBases(); + + 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(), + *MemberOrBase, SS.getRange()); + R.clear(); + } + } + // If no results were found, try to correct typos. - if (R.empty() && + if (R.empty() && BaseType.isNull() && CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) { if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { @@ -1106,20 +1121,22 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, } } - if (!TyD) { + if (!TyD && BaseType.isNull()) { Diag(IdLoc, diag::err_mem_init_not_member_or_class) << MemberOrBase << SourceRange(IdLoc, RParenLoc); return true; } } - BaseType = Context.getTypeDeclType(TyD); - if (SS.isSet()) { - NestedNameSpecifier *Qualifier = - static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + if (BaseType.isNull()) { + BaseType = Context.getTypeDeclType(TyD); + if (SS.isSet()) { + NestedNameSpecifier *Qualifier = + static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - // FIXME: preserve source range information - BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + // FIXME: preserve source range information + BaseType = Context.getQualifiedNameType(Qualifier, BaseType); + } } } @@ -4470,9 +4487,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); @@ -5594,26 +5611,24 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType(); QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType(); - QualType CNewTy = Context.getCanonicalType(NewTy); - QualType COldTy = Context.getCanonicalType(OldTy); - - if (CNewTy == COldTy && - CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers()) + if (Context.hasSameType(NewTy, OldTy)) return false; // Check if the return types are covariant QualType NewClassTy, OldClassTy; /// Both types must be pointers or references to classes. - if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) { - if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) { + if (const PointerType *NewPT = NewTy->getAs<PointerType>()) { + if (const PointerType *OldPT = OldTy->getAs<PointerType>()) { NewClassTy = NewPT->getPointeeType(); OldClassTy = OldPT->getPointeeType(); } - } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) { - if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) { - NewClassTy = NewRT->getPointeeType(); - OldClassTy = OldRT->getPointeeType(); + } else if (const ReferenceType *NewRT = NewTy->getAs<ReferenceType>()) { + if (const ReferenceType *OldRT = OldTy->getAs<ReferenceType>()) { + if (NewRT->getTypeClass() == OldRT->getTypeClass()) { + NewClassTy = NewRT->getPointeeType(); + OldClassTy = OldRT->getPointeeType(); + } } } @@ -5661,7 +5676,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, } // The qualifiers of the return types must be the same. - if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) { + if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) { Diag(New->getLocation(), diag::err_covariant_return_type_different_qualifications) << New->getDeclName() << NewTy << OldTy; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index f2fc1f4..1b07d19 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -81,6 +81,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); @@ -201,7 +202,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, /// Check then save referenced protocols. if (NumProtoRefs) { IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); + ProtoLocs, Context); IDecl->setLocEnd(EndProtoLoc); } @@ -279,6 +280,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, SourceLocation ProtocolLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { // FIXME: Deal with AttrList. @@ -312,7 +314,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, ProcessDeclAttributeList(TUScope, PDecl, AttrList); if (NumProtoRefs) { /// Check then save referenced protocols. - PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context); + PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + ProtoLocs, Context); PDecl->setLocEnd(EndProtoLoc); } @@ -432,17 +435,17 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { } } -/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list -/// of properties declared in a protocol and adds them to the list -/// of properties for current class/category if it is not there already. +/// MatchOneProtocolPropertiesInClass - This routine goes thru the list +/// of properties declared in a protocol and compares their attribute against +/// the same property declared in the class or category. void -Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, +Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) { ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); if (!IDecl) { // Category ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MergeOneProtocolPropertiesIntoClass"); + assert (CatDecl && "MatchOneProtocolPropertiesInClass"); for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), E = PDecl->prop_end(); P != E; ++P) { ObjCPropertyDecl *Pr = (*P); @@ -471,35 +474,35 @@ Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl, } } -/// MergeProtocolPropertiesIntoClass - This routine merges properties -/// declared in 'MergeItsProtocols' objects (which can be a class or an -/// inherited protocol into the list of properties for class/category 'CDecl' +/// CompareProperties - This routine compares properties +/// declared in 'ClassOrProtocol' objects (which can be a class or an +/// inherited protocol with the list of properties for class/category 'CDecl' /// -void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, - DeclPtrTy MergeItsProtocols) { - Decl *ClassDecl = MergeItsProtocols.getAs<Decl>(); +void Sema::CompareProperties(Decl *CDecl, + DeclPtrTy ClassOrProtocol) { + Decl *ClassDecl = ClassOrProtocol.getAs<Decl>(); ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl); if (!IDecl) { // Category ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl); - assert (CatDecl && "MergeProtocolPropertiesIntoClass"); + assert (CatDecl && "CompareProperties"); if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) - // Merge properties of category (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + // Match properties of category with those of protocol (*P) + MatchOneProtocolPropertiesInClass(CatDecl, *P); - // Go thru the list of protocols for this category and recursively merge - // their properties into this class as well. + // Go thru the list of protocols for this category and recursively match + // their properties with those in the category. for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), E = CatDecl->protocol_end(); P != E; ++P) - MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P)); + CompareProperties(CatDecl, DeclPtrTy::make(*P)); } else { ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), E = MD->protocol_end(); P != E; ++P) - MergeOneProtocolPropertiesIntoClass(CatDecl, *P); + MatchOneProtocolPropertiesInClass(CatDecl, *P); } return; } @@ -507,19 +510,19 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl, if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), E = MDecl->protocol_end(); P != E; ++P) - // Merge properties of class (*P) into IDECL's - MergeOneProtocolPropertiesIntoClass(IDecl, *P); + // Match properties of class IDecl with those of protocol (*P). + MatchOneProtocolPropertiesInClass(IDecl, *P); - // Go thru the list of protocols for this class and recursively merge - // their properties into this class as well. + // Go thru the list of protocols for this class and recursively match + // their properties with those declared in the class. for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), E = IDecl->protocol_end(); P != E; ++P) - MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P)); + CompareProperties(IDecl, DeclPtrTy::make(*P)); } else { ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), E = MD->protocol_end(); P != E; ++P) - MergeOneProtocolPropertiesIntoClass(IDecl, *P); + MatchOneProtocolPropertiesInClass(IDecl, *P); } } @@ -559,6 +562,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, unsigned NumElts, AttributeList *attrList) { llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols; + llvm::SmallVector<SourceLocation, 8> ProtoLocs; for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; @@ -571,11 +575,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, if (attrList) ProcessDeclAttributeList(TUScope, PDecl, attrList); Protocols.push_back(PDecl); + ProtoLocs.push_back(IdentList[i].second); } ObjCForwardProtocolDecl *PDecl = ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc, - &Protocols[0], Protocols.size()); + Protocols.data(), Protocols.size(), + ProtoLocs.data()); CurContext->addDecl(PDecl); CheckObjCDeclScope(PDecl); return DeclPtrTy::make(PDecl); @@ -588,9 +594,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, SourceLocation CategoryLoc, const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { ObjCCategoryDecl *CDecl = - ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName); + ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc, + CategoryLoc, CategoryName); // FIXME: PushOnScopeChains? CurContext->addDecl(CDecl); @@ -623,12 +631,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, if (NumProtoRefs) { CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, - Context); - CDecl->setLocEnd(EndProtoLoc); + ProtoLocs, Context); // Protocols in the class extension belong to the class. if (!CDecl->getIdentifier()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, - NumProtoRefs,Context); + NumProtoRefs, ProtoLocs, + Context); } CheckObjCDeclScope(CDecl); @@ -650,6 +658,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( // Category @implementation with no corresponding @interface. // Create and install one. CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), SourceLocation(), CatName); CatIDecl->setClassInterface(IDecl); CatIDecl->insertNextClassCategory(); @@ -1077,6 +1086,92 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } +/// CollectImmediateProperties - This routine collects all properties in +/// the class and its conforming protocols; but not those it its super class. +void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), + E = IDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), + E = IDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(), + E = CATDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + PropMap[Prop->getIdentifier()] = Prop; + } + // scan through class's protocols. + for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + E = CATDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), + E = PDecl->prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = (*P); + ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; + if (!PropEntry) + PropEntry = Prop; + } + // scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + E = PDecl->protocol_end(); PI != E; ++PI) + CollectImmediateProperties((*PI), PropMap); + } +} + +void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const llvm::DenseSet<Selector>& InsMap) { + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + CollectImmediateProperties(CDecl, PropMap); + if (PropMap.empty()) + return; + + llvm::DenseSet<ObjCPropertyDecl *> PropImplMap; + for (ObjCImplDecl::propimpl_iterator + I = IMPDecl->propimpl_begin(), + EI = IMPDecl->propimpl_end(); I != EI; ++I) + PropImplMap.insert((*I)->getPropertyDecl()); + + for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { + ObjCPropertyDecl *Prop = P->second; + // Is there a matching propery synthesize/dynamic? + if (Prop->isInvalidDecl() || + Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || + PropImplMap.count(Prop)) + continue; + + if (!InsMap.count(Prop->getGetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getGetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + + if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { + Diag(Prop->getLocation(), + isa<ObjCCategoryDecl>(CDecl) ? + diag::warn_setter_getter_impl_required_in_category : + diag::warn_setter_getter_impl_required) + << Prop->getDeclName() << Prop->getSetterName(); + Diag(IMPDecl->getLocation(), + diag::note_property_impl_required); + } + } +} + void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { @@ -1091,39 +1186,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, // an implementation or 2) there is a @synthesize/@dynamic implementation // of the property in the @implementation. if (isa<ObjCInterfaceDecl>(CDecl)) - for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(), - E = CDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = (*P); - if (Prop->isInvalidDecl()) - continue; - ObjCPropertyImplDecl *PI = 0; - // Is there a matching propery synthesize/dynamic? - for (ObjCImplDecl::propimpl_iterator - I = IMPDecl->propimpl_begin(), - EI = IMPDecl->propimpl_end(); I != EI; ++I) - if ((*I)->getPropertyDecl() == Prop) { - PI = (*I); - break; - } - if (PI) - continue; - if (!InsMap.count(Prop->getGetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getGetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - - if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) { - Diag(Prop->getLocation(), - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Prop->getSetterName(); - Diag(IMPDecl->getLocation(), - diag::note_property_impl_required); - } - } - + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + llvm::DenseSet<Selector> ClsMap; for (ObjCImplementationDecl::classmeth_iterator I = IMPDecl->classmeth_begin(), @@ -1163,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl, E = C->protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, C->getClassInterface()); - } + // Report unimplemented properties in the category as well. + // When reporting on missing setter/getters, do not report when + // setter/getter is implemented in category's primary class + // implementation. + if (ObjCInterfaceDecl *ID = C->getClassInterface()) + if (ObjCImplDecl *IMP = ID->getImplementation()) { + for (ObjCImplementationDecl::instmeth_iterator + I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I) + InsMap.insert((*I)->getSelector()); + } + DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap); + } } else assert(false && "invalid ObjCContainerDecl type."); } @@ -1694,14 +1769,14 @@ void Sema::ActOnAtEnd(SourceRange AtEnd, // Compares properties declared in this class to those of its // super class. ComparePropertiesInBaseAndSuper(I); - MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I)); + CompareProperties(I, DeclPtrTy::make(I)); } else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) { // Categories are used to extend the class by declaring new methods. // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. - // Merge protocol properties into category - MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C)); + // Compare protocol properties with those in category + CompareProperties(C, DeclPtrTy::make(C)); if (C->getIdentifier() == 0) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } @@ -2111,7 +2186,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, assert(DC && "ClassDecl is not a DeclContext"); ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(), - FD.D.getIdentifier(), T); + FD.D.getIdentifier(), + AtLoc, T); DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName()); if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) { Diag(PDecl->getLocation(), diag::err_duplicate_property); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 034accd..50976f7 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3082,15 +3082,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); - if (Getter || Setter) { + if (Getter) { QualType PType; - - if (Getter) - PType = Getter->getResultType(); - else - // Get the expression type from Setter's incoming parameter. - PType = (*(Setter->param_end() -1))->getType(); - // FIXME: we must check that the setter has property type. + PType = Getter->getResultType(); return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType, Setter, MemberLoc, BaseExpr)); } @@ -3663,11 +3657,21 @@ Action::OwningExprResult Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); - - QualType literalType = GetTypeFromParser(Ty); - // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); + + TypeSourceInfo *TInfo; + QualType literalType = GetTypeFromParser(Ty, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(literalType); + + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr)); +} + +Action::OwningExprResult +Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, + SourceLocation RParenLoc, ExprArg InitExpr) { + QualType literalType = TInfo->getType(); Expr *literalExpr = static_cast<Expr*>(InitExpr.get()); if (literalType->isArrayType()) { @@ -3703,8 +3707,7 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, Result.release(); - // FIXME: Store the TInfo to preserve type information better. - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType, + return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } @@ -3906,26 +3909,38 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, Action::OwningExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, SourceLocation RParenLoc, ExprArg Op) { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - assert((Ty != 0) && (Op.get() != 0) && "ActOnCastExpr(): missing type or expr"); - Expr *castExpr = (Expr *)Op.get(); - //FIXME: Preserve type source info. - QualType castType = GetTypeFromParser(Ty); + TypeSourceInfo *castTInfo; + QualType castType = GetTypeFromParser(Ty, &castTInfo); + if (!castTInfo) + castTInfo = Context.getTrivialTypeSourceInfo(castType); // If the Expr being casted is a ParenListExpr, handle it specially. + Expr *castExpr = (Expr *)Op.get(); if (isa<ParenListExpr>(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType); + return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op), + castTInfo); + + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op)); +} + +Action::OwningExprResult +Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, + SourceLocation RParenLoc, ExprArg Op) { + Expr *castExpr = static_cast<Expr*>(Op.get()); + CXXMethodDecl *Method = 0; - if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr, + CastExpr::CastKind Kind = CastExpr::CK_Unknown; + if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, Kind, Method)) return ExprError(); if (Method) { - OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind, - Method, move(Op)); + // FIXME: preserve type source info here + OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(), + Kind, Method, move(Op)); if (CastArg.isInvalid()) return ExprError(); @@ -3935,8 +3950,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, Op.release(); } - return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(), - Kind, castExpr, castType, + return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(), + Kind, castExpr, Ty, LParenLoc, RParenLoc)); } @@ -3961,8 +3976,9 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) { Action::OwningExprResult Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, SourceLocation RParenLoc, ExprArg Op, - QualType Ty) { + TypeSourceInfo *TInfo) { ParenListExpr *PE = (ParenListExpr *)Op.get(); + QualType Ty = TInfo->getType(); // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. @@ -3982,13 +3998,12 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); - return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc, - Owned(E)); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); } else { // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. Op = MaybeConvertParenListExprToParenExpr(S, move(Op)); - return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op)); } } @@ -4702,8 +4717,9 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, // Build a compound literal constructing a value of the transparent // union type from this initializer list. - E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer, - false); + TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); + E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, + Initializer, false); } Sema::AssignConvertType @@ -6785,10 +6801,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic); ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(), - E = CurBlock->TheDecl->param_end(); AI != E; ++AI) + E = CurBlock->TheDecl->param_end(); AI != E; ++AI) { + (*AI)->setOwningFunction(CurBlock->TheDecl); + // If this has an identifier, add it to the scope stack. if ((*AI)->getIdentifier()) PushOnScopeChains(*AI, CurBlock->TheScope); + } // Check for a valid sentinel attribute on this block. if (!CurBlock->isVariadic && @@ -6868,6 +6887,26 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking; BSI->TheDecl->setBody(body.takeAs<CompoundStmt>()); + + bool Good = true; + // Check goto/label use. + for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator + I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) { + LabelStmt *L = I->second; + + // Verify that we have no forward references left. If so, there was a goto + // or address of a label taken, but no definition of it. + if (L->getSubStmt() != 0) + continue; + + // Emit error. + Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName(); + Good = false; + } + BSI->LabelMap.clear(); + if (!Good) + return ExprError(); + AnalysisContext AC(BSI->TheDecl); CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); CheckUnreachable(AC); @@ -7203,8 +7242,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { AlreadyInstantiated = true; } - if (!AlreadyInstantiated) - PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); + if (!AlreadyInstantiated) { + if (isa<CXXRecordDecl>(Function->getDeclContext()) && + cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass()) + PendingLocalImplicitInstantiations.push_back(std::make_pair(Function, + Loc)); + else + PendingImplicitInstantiations.push_back(std::make_pair(Function, + Loc)); + } } // FIXME: keep track of references to static functions diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d10e11f..b004fc3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(TypeRep && "Missing type!"); - // FIXME: Preserve type source info. - QualType Ty = GetTypeFromParser(TypeRep); + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(TypeRep, &TInfo); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); unsigned NumExprs = exprs.size(); Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TypeRange.getBegin(); @@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, } return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(), - Ty, TyBeginLoc, Kind, + TInfo, TyBeginLoc, Kind, Exprs[0], RParenLoc)); } @@ -891,9 +893,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *Record = Type->getAs<RecordType>()) { llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); - const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions(); + const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip over templated conversion functions; they aren't considered. if (isa<FunctionTemplateDecl>(*I)) @@ -1448,12 +1450,14 @@ QualType Sema::CheckPointerToMemberOperands( // overkill? if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { - const char *ReplaceStr = isIndirect ? ".*" : "->*"; Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType() << - CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr); + << (int)isIndirect << lex->getType(); return QualType(); } + // 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); } if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 85889fa..ea8f4e3 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -398,7 +398,17 @@ Sema::ExprResult Sema::ActOnClassMessage( return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, selectorLoc, rbrac, Args, NumArgs); } - return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; + 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); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 1970f56..fd62e1a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -382,7 +382,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (hadError) return; - if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement) + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement || + ElementEntity.getKind() == InitializedEntity::EK_VectorElement) ElementEntity.setElementIndex(Init); if (Init >= NumInits || !ILE->getInit(Init)) { @@ -1828,12 +1829,15 @@ bool Sema::CheckInitList(const InitializedEntity &Entity, InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent) - : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index) + : Parent(&Parent), Index(Index) { - if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) + if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) { + Kind = EK_ArrayElement; Type = AT->getElementType(); - else + } else { + Kind = EK_VectorElement; Type = Parent.getType()->getAs<VectorType>()->getElementType(); + } } InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, @@ -1862,7 +1866,8 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return DeclarationName(); } @@ -1882,7 +1887,8 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: - case EK_ArrayOrVectorElement: + case EK_ArrayElement: + case EK_VectorElement: return 0; } @@ -2141,11 +2147,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // refers to. QualType ToType = AllowRValues? cv1T1 : DestType; - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), - E = Conversions->end(); - I != E; ++I) { + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), + E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) @@ -2662,9 +2667,9 @@ static void TryUserDefinedConversion(Sema &S, CXXRecordDecl *SourceRecordDecl = cast<CXXRecordDecl>(SourceRecordType->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = SourceRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::const_iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; @@ -2917,7 +2922,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Casting; case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return Sema::AA_Initializing; } @@ -2935,7 +2941,8 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity, case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: return false; case InitializedEntity::EK_Parameter: @@ -2981,7 +2988,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_Base: case InitializedEntity::EK_Member: - case InitializedEntity::EK_ArrayOrVectorElement: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_VectorElement: // We don't need to copy for any of these initialized entities. return move(CurInit); } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 5eb819a..d7d3756 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -47,6 +47,11 @@ public: /// \brief The entity being initialized is an exception object that /// is being thrown. EK_Exception, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member, + /// \brief The entity being initialized is an element of an array. + EK_ArrayElement, /// \brief The entity being initialized is an object (or array of /// objects) allocated via new. EK_New, @@ -54,12 +59,10 @@ public: EK_Temporary, /// \brief The entity being initialized is a base member subobject. EK_Base, - /// \brief The entity being initialized is a non-static data member - /// subobject. - EK_Member, - /// \brief The entity being initialized is an element of an array + /// \brief The entity being initialized is an element of a vector. /// or vector. - EK_ArrayOrVectorElement + EK_VectorElement + }; private: @@ -211,7 +214,7 @@ public: /// \brief If this is already the initializer for an array or vector /// element, sets the element index. void setElementIndex(unsigned Index) { - assert(getKind() == EK_ArrayOrVectorElement); + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement); this->Index = Index; } }; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index cda245d..f5d2a7d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -317,16 +317,16 @@ void LookupResult::resolveKind() { // Fast case: no possible ambiguity. if (N == 0) { - assert(ResultKind == NotFound); + assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation); return; } // 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[0])) + if (isa<FunctionTemplateDecl>(*Decls.begin())) ResultKind = FoundOverloaded; - else if (isa<UnresolvedUsingValueDecl>(Decls[0])) + else if (isa<UnresolvedUsingValueDecl>(*Decls.begin())) ResultKind = FoundUnresolvedValue; return; } @@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) { - if (R.isAcceptableDecl(*I)) { - R.addDecl(*I); + NamedDecl *D = *I; + if (R.isAcceptableDecl(D)) { + R.addDecl(D); Found = true; } } @@ -463,10 +464,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) { if (!Record->isDefinition()) return Found; - const UnresolvedSet *Unresolved = Record->getConversionFunctions(); - for (UnresolvedSet::iterator U = Unresolved->begin(), - UEnd = Unresolved->end(); - U != UEnd; ++U) { + const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions(); + for (UnresolvedSetImpl::iterator U = Unresolved->begin(), + UEnd = Unresolved->end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U); if (!ConvTemplate) continue; @@ -967,6 +967,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Perform qualified name lookup into the LookupCtx. if (LookupDirect(R, LookupCtx)) { R.resolveKind(); + if (isa<CXXRecordDecl>(LookupCtx)) + R.setNamingClass(cast<CXXRecordDecl>(LookupCtx)); return true; } @@ -1039,6 +1041,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, R.getLookupName().getAsOpaquePtr(), Paths)) return false; + R.setNamingClass(LookupRec); + // C++ [class.member.lookup]p2: // [...] If the resulting set of declarations are not all from // sub-objects of the same type, or the set has a nonstatic member @@ -1048,10 +1052,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; + AccessSpecifier SubobjectAccess = AS_private; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); + // Pick the best (i.e. most permissive i.e. numerically lowest) access + // across all paths. + SubobjectAccess = std::min(SubobjectAccess, Path->Access); + // Determine whether we're looking at a distinct sub-object or not. if (SubobjectType.isNull()) { // This is the first subobject we've looked at. Record its type. @@ -1106,8 +1115,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Lookup in a base class succeeded; return these results. DeclContext::lookup_iterator I, E; - for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) - R.addDecl(*I); + for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) { + NamedDecl *D = *I; + AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, + D->getAccess()); + R.addDecl(D, AS); + } R.resolveKind(); return true; } @@ -1243,7 +1256,12 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { Diag((*DI)->getLocation(), diag::note_hiding_object); // For recovery purposes, go ahead and implement the hiding. - Result.hideDecls(TagDecls); + LookupResult::Filter F = Result.makeFilter(); + while (F.hasNext()) { + if (TagDecls.count(F.next())) + F.erase(); + } + F.done(); return true; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6ec4d1b..44a8f15 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -25,7 +25,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> -#include <cstdio> namespace clang { @@ -183,51 +182,53 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// DebugPrint - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. void StandardConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { - fprintf(stderr, "%s", GetImplicitConversionName(First)); + OS << GetImplicitConversionName(First); PrintedSomething = true; } if (Second != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Second)); + OS << GetImplicitConversionName(Second); if (CopyConstructor) { - fprintf(stderr, " (by copy constructor)"); + OS << " (by copy constructor)"; } else if (DirectBinding) { - fprintf(stderr, " (direct reference binding)"); + OS << " (direct reference binding)"; } else if (ReferenceBinding) { - fprintf(stderr, " (reference binding)"); + OS << " (reference binding)"; } PrintedSomething = true; } if (Third != ICK_Identity) { if (PrintedSomething) { - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "%s", GetImplicitConversionName(Third)); + OS << GetImplicitConversionName(Third); PrintedSomething = true; } if (!PrintedSomething) { - fprintf(stderr, "No conversions required"); + OS << "No conversions required"; } } /// DebugPrint - Print this user-defined conversion sequence to standard /// error. Useful for debugging overloading issues. void UserDefinedConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); if (Before.First || Before.Second || Before.Third) { Before.DebugPrint(); - fprintf(stderr, " -> "); + OS << " -> "; } - fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str()); + OS << "'" << ConversionFunction->getNameAsString() << "'"; if (After.First || After.Second || After.Third) { - fprintf(stderr, " -> "); + OS << " -> "; After.DebugPrint(); } } @@ -235,27 +236,28 @@ void UserDefinedConversionSequence::DebugPrint() const { /// DebugPrint - Print this implicit conversion sequence to standard /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::DebugPrint() const { + llvm::raw_ostream &OS = llvm::errs(); switch (ConversionKind) { case StandardConversion: - fprintf(stderr, "Standard conversion: "); + OS << "Standard conversion: "; Standard.DebugPrint(); break; case UserDefinedConversion: - fprintf(stderr, "User-defined conversion: "); + OS << "User-defined conversion: "; UserDefined.DebugPrint(); break; case EllipsisConversion: - fprintf(stderr, "Ellipsis conversion"); + OS << "Ellipsis conversion"; break; case AmbiguousConversion: - fprintf(stderr, "Ambiguous conversion"); + OS << "Ambiguous conversion"; break; case BadConversion: - fprintf(stderr, "Bad conversion"); + OS << "Bad conversion"; break; } - fprintf(stderr, "\n"); + OS << "\n"; } void AmbiguousConversionSequence::construct() { @@ -1100,7 +1102,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, bool &IncompatibleObjC) { if (!getLangOptions().ObjC1) return false; - + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *FromObjCPtr = @@ -1141,8 +1143,23 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, QualType ToPointeeType; if (const PointerType *ToCPtr = ToType->getAs<PointerType>()) ToPointeeType = ToCPtr->getPointeeType(); - else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>()) + else if (const BlockPointerType *ToBlockPtr = + ToType->getAs<BlockPointerType>()) { + // Objective C++: We're able to convert from a pointer to any object + // to a block pointer type. + if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) { + ConvertedType = ToType; + return true; + } ToPointeeType = ToBlockPtr->getPointeeType(); + } + else if (FromType->getAs<BlockPointerType>() && + ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { + // Objective C++: We're able to convert from a block pointer type to a + // pointer to any object. + ConvertedType = ToType; + return true; + } else return false; @@ -1164,6 +1181,16 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = ToType; return true; } + // Allow conversion of pointee being objective-c pointer to another one; + // as in I* to id. + if (FromPointeeType->getAs<ObjCObjectPointerType>() && + ToPointeeType->getAs<ObjCObjectPointerType>() && + isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, + IncompatibleObjC)) { + ConvertedType = ToType; + return true; + } + // If we have pointers to functions or blocks, check whether the only // differences in the argument and result types are in Objective-C // pointer conversions. If so, we permit the conversion (but @@ -1523,9 +1550,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (CXXRecordDecl *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) { // Add all of the conversion functions as candidates. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = FromRecordDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); @@ -2756,7 +2783,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) { Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_trivial_conversion; return; } @@ -2794,7 +2821,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, case ImplicitConversionSequence::BadConversion: Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.FailureKind = ovl_fail_bad_final_conversion; break; default: @@ -2869,6 +2896,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; + Candidate.Conversions[0] = ObjectInit; return; } @@ -3270,9 +3298,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { // Skip conversion function templates; they don't tell us anything @@ -3334,10 +3362,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) { } CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl()); - const UnresolvedSet *Conversions = + const UnresolvedSetImpl *Conversions = ClassDecl->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) { QualType CanTy = Context.getCanonicalType(Conv->getConversionType()); @@ -4386,7 +4414,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { QualType FromTy = Conv.Bad.getFromType(); QualType ToTy = Conv.Bad.getToType(); - // Do some hand-waving analysis to see if the non-viability is due to a + // Do some hand-waving analysis to see if the non-viability is due + // to a qualifier mismatch. CanQualType CFromTy = S.Context.getCanonicalType(FromTy); CanQualType CToTy = S.Context.getCanonicalType(ToTy); if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>()) @@ -4436,6 +4465,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + // Diagnose references or pointers to incomplete types differently, + // since it's far from impossible that the incompleteness triggered + // the failure. + QualType TempFromTy = FromTy.getNonReferenceType(); + if (const PointerType *PTy = TempFromTy->getAs<PointerType>()) + TempFromTy = PTy->getPointeeType(); + if (TempFromTy->isIncompleteType()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << ToTy << (unsigned) isObjectArgument << I+1; + return; + } + // TODO: specialize more based on the kind of mismatch S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv) << (unsigned) FnKind << FnDesc @@ -4503,6 +4546,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: + case ovl_fail_trivial_conversion: + case ovl_fail_bad_final_conversion: return S.NoteOverloadCandidate(Fn); case ovl_fail_bad_conversion: @@ -4582,12 +4627,23 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, } } +SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { + if (Cand->Function) + return Cand->Function->getLocation(); + if (Cand->IsSurrogate) + return Cand->Surrogate->getLocation(); + return SourceLocation(); +} + struct CompareOverloadCandidatesForDisplay { Sema &S; CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {} bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { + // Fast-path this check. + if (L == R) return false; + // Order first by viability. if (L->Viable) { if (!R->Viable) return true; @@ -4600,25 +4656,132 @@ struct CompareOverloadCandidatesForDisplay { } else if (R->Viable) return false; - // Put declared functions first. - if (L->Function) { - if (!R->Function) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(), - R->Function->getLocation()); - } else if (R->Function) return false; - - // Then surrogates. - if (L->IsSurrogate) { - if (!R->IsSurrogate) return true; - return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(), - R->Surrogate->getLocation()); - } else if (R->IsSurrogate) return false; - - // And builtins just come in a jumble. - return false; + assert(L->Viable == R->Viable); + + // Criteria by which we can sort non-viable candidates: + if (!L->Viable) { + // 1. Arity mismatches come after other candidates. + if (L->FailureKind == ovl_fail_too_many_arguments || + L->FailureKind == ovl_fail_too_few_arguments) + return false; + if (R->FailureKind == ovl_fail_too_many_arguments || + R->FailureKind == ovl_fail_too_few_arguments) + return true; + + // 2. Bad conversions come first and are ordered by the number + // of bad conversions and quality of good conversions. + if (L->FailureKind == ovl_fail_bad_conversion) { + if (R->FailureKind != ovl_fail_bad_conversion) + return true; + + // If there's any ordering between the defined conversions... + // FIXME: this might not be transitive. + assert(L->Conversions.size() == R->Conversions.size()); + + int leftBetter = 0; + for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) { + switch (S.CompareImplicitConversionSequences(L->Conversions[I], + R->Conversions[I])) { + case ImplicitConversionSequence::Better: + leftBetter++; + break; + + case ImplicitConversionSequence::Worse: + leftBetter--; + break; + + case ImplicitConversionSequence::Indistinguishable: + break; + } + } + if (leftBetter > 0) return true; + if (leftBetter < 0) return false; + + } else if (R->FailureKind == ovl_fail_bad_conversion) + return false; + + // TODO: others? + } + + // Sort everything else by location. + SourceLocation LLoc = GetLocationForCandidate(L); + SourceLocation RLoc = GetLocationForCandidate(R); + + // Put candidates without locations (e.g. builtins) at the end. + if (LLoc.isInvalid()) return false; + if (RLoc.isInvalid()) return true; + + return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc); } }; +/// CompleteNonViableCandidate - Normally, overload resolution only +/// computes up to the first +void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, + Expr **Args, unsigned NumArgs) { + assert(!Cand->Viable); + + // Don't do anything on failures other than bad conversion. + if (Cand->FailureKind != ovl_fail_bad_conversion) return; + + // Skip forward to the first bad conversion. + unsigned ConvIdx = 0; + unsigned ConvCount = Cand->Conversions.size(); + while (true) { + assert(ConvIdx != ConvCount && "no bad conversion in candidate"); + ConvIdx++; + if (Cand->Conversions[ConvIdx - 1].isBad()) + break; + } + + if (ConvIdx == ConvCount) + return; + + // FIXME: these should probably be preserved from the overload + // operation somehow. + bool SuppressUserConversions = false; + bool ForceRValue = false; + + const FunctionProtoType* Proto; + unsigned ArgIdx = ConvIdx; + + if (Cand->IsSurrogate) { + QualType ConvType + = Cand->Surrogate->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + ConvType = ConvPtrType->getPointeeType(); + Proto = ConvType->getAs<FunctionProtoType>(); + ArgIdx--; + } else if (Cand->Function) { + Proto = Cand->Function->getType()->getAs<FunctionProtoType>(); + if (isa<CXXMethodDecl>(Cand->Function) && + !isa<CXXConstructorDecl>(Cand->Function)) + ArgIdx--; + } else { + // Builtin binary operator with a bad first conversion. + assert(ConvCount <= 3); + for (; ConvIdx != ConvCount; ++ConvIdx) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ConvIdx], + Cand->BuiltinTypes.ParamTypes[ConvIdx], + SuppressUserConversions, ForceRValue, + /*InOverloadResolution*/ true); + return; + } + + // Fill in the rest of the conversions. + unsigned NumArgsInProto = Proto->getNumArgs(); + for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) { + if (ArgIdx < NumArgsInProto) + Cand->Conversions[ConvIdx] + = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx), + SuppressUserConversions, ForceRValue, + /*InOverloadResolution=*/true); + else + Cand->Conversions[ConvIdx].setEllipsis(); + } +} + } // end anonymous namespace /// PrintOverloadCandidates - When overload resolution fails, prints @@ -4636,9 +4799,15 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), LastCand = CandidateSet.end(); - Cand != LastCand; ++Cand) - if (Cand->Viable || OCD == OCD_AllCandidates) + Cand != LastCand; ++Cand) { + if (Cand->Viable) Cands.push_back(Cand); + else if (OCD == OCD_AllCandidates) { + CompleteNonViableCandidate(*this, Cand, Args, NumArgs); + Cands.push_back(Cand); + } + } + std::sort(Cands.begin(), Cands.end(), CompareOverloadCandidatesForDisplay(*this)); @@ -5909,9 +6078,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { NamedDecl *D = *I; CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 20add00..f8353e3 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -390,7 +390,16 @@ namespace clang { ovl_fail_too_many_arguments, ovl_fail_too_few_arguments, ovl_fail_bad_conversion, - ovl_fail_bad_deduction + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion }; /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 7855a7f..0c207fa 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -412,10 +412,10 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions; llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs<RecordType>()) { - const UnresolvedSet *Conversions + const UnresolvedSetImpl *Conversions = cast<CXXRecordDecl>(RecordTy->getDecl()) ->getVisibleConversionFunctions(); - for (UnresolvedSet::iterator I = Conversions->begin(), + for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I)) if (Conversion->getConversionType().getNonReferenceType() @@ -879,10 +879,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Action::OwningStmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, IdentifierInfo *LabelII) { - // If we are in a block, reject all gotos for now. - if (CurBlock) - return StmtError(Diag(GotoLoc, diag::err_goto_in_block)); - // Look up the record for this label identifier. LabelStmt *&LabelDecl = getLabelMap()[LabelII]; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 2fad832..0040156 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -449,8 +449,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, Loc = KeyLoc; TemplateTypeParmDecl *Param - = TemplateTypeParmDecl::Create(Context, CurContext, Loc, - Depth, Position, ParamName, Typename, + = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), + Loc, Depth, Position, ParamName, Typename, Ellipsis); if (Invalid) Param->setInvalidDecl(); @@ -572,7 +572,8 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, } NonTypeTemplateParmDecl *Param - = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), + = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + D.getIdentifierLoc(), Depth, Position, ParamName, T, TInfo); if (Invalid) Param->setInvalidDecl(); @@ -625,8 +626,8 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. TemplateTemplateParmDecl *Param = - TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth, - Position, Name, + TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + TmpLoc, Depth, Position, Name, (TemplateParameterList*)Params); // Make sure the parameter is valid. @@ -1586,9 +1587,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { - if ((ObjectType && - computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || - (SS.isSet() && computeDeclContext(SS, EnteringContext))) { + DeclContext *LookupCtx = 0; + if (SS.isSet()) + LookupCtx = computeDeclContext(SS, EnteringContext); + if (!LookupCtx && ObjectType) + LookupCtx = computeDeclContext(QualType::getFromOpaquePtr(ObjectType)); + if (LookupCtx) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1608,8 +1612,9 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, TemplateTy Template; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, EnteringContext, Template); - if (TNK == TNK_Non_template && - isCurrentInstantiationWithDependentBases(SS)) { + if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && + isa<CXXRecordDecl>(LookupCtx) && + cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { // This is a dependent template. } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e909c4f..23a9430 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); } + Typedef->setAccess(D->getAccess()); Owner->addDecl(Typedef); return Typedef; @@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { if (D->isOutOfLine()) Var->setLexicalDeclContext(D->getLexicalDeclContext()); + Var->setAccess(D->getAccess()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; @@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) { } Field->setImplicit(D->isImplicit()); + Field->setAccess(D->getAccess()); Owner->addDecl(Field); return Field; @@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { return Inst; } + Inst->setAccess(D->getAccess()); Owner->addDecl(Inst); // First, we sort the partial specializations by location, so @@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (!Instantiated) return 0; + Instantiated->setAccess(D->getAccess()); + // Link the instantiated function template declaration to the function // template from which it was instantiated. FunctionTemplateDecl *InstTemplate @@ -717,7 +724,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -844,7 +854,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); + bool MergeWithParentScope = (TemplateParams != 0) || + !(isa<Decl>(Owner) && + cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod()); + Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -958,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); + Method->setAccess(D->getAccess()); + if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) && !Method->getFriendObjectKind()) Owner->addDecl(Method); @@ -997,7 +1012,9 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { // Allocate the parameter ParmVarDecl *Param - = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(), + = ParmVarDecl::Create(SemaRef.Context, + SemaRef.Context.getTranslationUnitDecl(), + D->getLocation(), D->getIdentifier(), T, DI, D->getStorageClass(), 0); // Mark the default argument as being uninstantiated. @@ -1542,7 +1559,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Proto->hasAnyExceptionSpec(), Exceptions.size(), Exceptions.data(), - Proto->getNoReturnAttr())); + Proto->getNoReturnAttr(), + Proto->getCallConv())); } return false; @@ -1647,8 +1665,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function)); // Introduce a new scope where local variable instantiations will be - // recorded. - LocalInstantiationScope Scope(*this); + // recorded, unless we're actually a member function within a local + // class, in which case we need to merge our results with the parent + // scope (of the enclosing function). + bool MergeWithParentScope = false; + if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext())) + MergeWithParentScope = Rec->isLocalClass(); + + LocalInstantiationScope Scope(*this, MergeWithParentScope); // Introduce the instantiated function parameters into the local // instantiation scope. @@ -1685,6 +1709,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclGroupRef DG(Function); Consumer.HandleTopLevelDecl(DG); + // This class may have local implicit instantiations that need to be + // instantiation within this scope. + PerformPendingImplicitInstantiations(/*LocalOnly=*/true); + Scope.Exit(); + if (Recursive) { // Instantiate any pending implicit instantiations found during the // instantiation of this template. @@ -2217,10 +2246,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -void Sema::PerformPendingImplicitInstantiations() { - while (!PendingImplicitInstantiations.empty()) { - PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); - PendingImplicitInstantiations.pop_front(); +void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) { + while (!PendingLocalImplicitInstantiations.empty() || + (!LocalOnly && !PendingImplicitInstantiations.empty())) { + PendingImplicitInstantiation Inst; + + if (PendingLocalImplicitInstantiations.empty()) { + Inst = PendingImplicitInstantiations.front(); + PendingImplicitInstantiations.pop_front(); + } else { + Inst = PendingLocalImplicitInstantiations.front(); + PendingLocalImplicitInstantiations.pop_front(); + } // Instantiate function definitions if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 9515834..9065761 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1374,6 +1374,21 @@ namespace { Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo); TL.setUnderlyingTInfo(TInfo); } + void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { + // By default, use the source location of the type specifier. + TL.setBuiltinLoc(DS.getTypeSpecTypeLoc()); + if (TL.needsExtraLocalData()) { + // Set info for the written builtin specifiers. + TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs(); + // Try to have a meaningful source location. + if (TL.getWrittenSignSpec() != TSS_unspecified) + // Sign spec loc overrides the others (e.g., 'unsigned long'). + TL.setBuiltinLoc(DS.getTypeSpecSignLoc()); + else if (TL.getWrittenWidthSpec() != TSW_unspecified) + // Width spec loc overrides type spec loc (e.g., 'short int'). + TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); + } + } void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(DS.getTypeSpecTypeLoc()); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 445ef0d..b2102af 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1014,15 +1014,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc, - QualType ExplicitTy, + OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg SubExpr) { - return getSema().ActOnCastExpr(/*Scope=*/0, - LParenLoc, - ExplicitTy.getAsOpaquePtr(), - RParenLoc, - move(SubExpr)); + return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, + move(SubExpr)); } /// \brief Build a new compound literal expression. @@ -1030,11 +1027,11 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RParenLoc, ExprArg Init) { - return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(), - RParenLoc, move(Init)); + return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, + move(Init)); } /// \brief Build a new extended vector element access expression. @@ -1194,30 +1191,30 @@ public: OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc, Stmt::StmtClass Class, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { switch (Class) { case Stmt::CXXStaticCastExprClass: - return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXDynamicCastExprClass: - return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXReinterpretCastExprClass: - return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); case Stmt::CXXConstCastExprClass: - return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T, + return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, move(SubExpr), RParenLoc); @@ -1235,14 +1232,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ dynamic_cast expression. @@ -1251,14 +1249,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ reinterpret_cast expression. @@ -1267,14 +1266,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ const_cast expression. @@ -1283,14 +1283,15 @@ public: /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, - QualType T, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { - return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast, - LAngleLoc, T.getAsOpaquePtr(), RAngleLoc, - LParenLoc, move(SubExpr), RParenLoc); + return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast, + TInfo, move(SubExpr), + SourceRange(LAngleLoc, RAngleLoc), + SourceRange(LParenLoc, RParenLoc)); } /// \brief Build a new C++ functional-style cast expression. @@ -1298,13 +1299,13 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange, - QualType T, + TypeSourceInfo *TInfo, SourceLocation LParenLoc, ExprArg SubExpr, SourceLocation RParenLoc) { void *Sub = SubExpr.takeAs<Expr>(); return getSema().ActOnCXXTypeConstructExpr(TypeRange, - T.getAsOpaquePtr(), + TInfo->getType().getAsOpaquePtr(), LParenLoc, Sema::MultiExprArg(getSema(), &Sub, 1), /*CommaLocs=*/0, @@ -2137,7 +2138,11 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template<typename Derived> QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB, BuiltinTypeLoc T) { - return TransformTypeSpecType(TLB, T); + BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType()); + NewT.setBuiltinLoc(T.getBuiltinLoc()); + if (T.needsExtraLocalData()) + NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs(); + return T.getType(); } template<typename Derived> @@ -3815,15 +3820,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { - QualType T; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - T = getDerived().TransformType(E->getTypeAsWritten()); - if (T.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -3833,11 +3840,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T, + return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(), + NewT, E->getRParenLoc(), move(SubExpr)); } @@ -3845,28 +3853,25 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) { - QualType T; - { - // FIXME: Source location isn't quite accurate. - SourceLocation FakeTypeLoc - = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc()); - TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName()); - - T = getDerived().TransformType(E->getType()); - if (T.isNull()) - return SemaRef.ExprError(); - } + TypeSourceInfo *OldT = E->getTypeSourceInfo(); + TypeSourceInfo *NewT = getDerived().TransformType(OldT); + if (!NewT) + return SemaRef.ExprError(); OwningExprResult Init = getDerived().TransformExpr(E->getInitializer()); if (Init.isInvalid()) return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - T == E->getType() && + OldT == NewT && Init.get() == E->getInitializer()) return SemaRef.Owned(E->Retain()); - return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T, + // Note: the expression type doesn't necessarily match the + // type-as-written, but that's okay, because it should always be + // derivable from the initializer. + + return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), NewT, /*FIXME:*/E->getInitializer()->getLocEnd(), move(Init)); } @@ -4237,15 +4242,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { // FIXME: Source location isn't quite accurate. SourceLocation TypeStartLoc = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4255,7 +4262,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); @@ -4269,7 +4276,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), E->getStmtClass(), FakeLAngleLoc, - ExplicitTy, + NewT, FakeRAngleLoc, FakeRAngleLoc, move(SubExpr), @@ -4305,12 +4312,14 @@ template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { - QualType ExplicitTy; + TypeSourceInfo *OldT; + TypeSourceInfo *NewT; { TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName()); - ExplicitTy = getDerived().TransformType(E->getTypeAsWritten()); - if (ExplicitTy.isNull()) + OldT = E->getTypeInfoAsWritten(); + NewT = getDerived().TransformType(OldT); + if (!NewT) return SemaRef.ExprError(); } @@ -4320,14 +4329,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr( return SemaRef.ExprError(); if (!getDerived().AlwaysRebuild() && - ExplicitTy == E->getTypeAsWritten() && + OldT == NewT && SubExpr.get() == E->getSubExpr()) return SemaRef.Owned(E->Retain()); // FIXME: The end of the type's source range is wrong return getDerived().RebuildCXXFunctionalCastExpr( /*FIXME:*/SourceRange(E->getTypeBeginLoc()), - ExplicitTy, + NewT, /*FIXME:*/E->getSubExpr()->getLocStart(), move(SubExpr), E->getRParenLoc()); |