diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2010-03-21 10:50:08 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2010-03-21 10:50:08 +0000 |
commit | 1e255aab650a7fa2047fd953cae65b12215280af (patch) | |
tree | 508d4388db78f87d35bf26a0400b4b03bc4c1f13 /lib | |
parent | 1033b7c1e32962948b01a25145829f17bc70a8de (diff) | |
download | FreeBSD-src-1e255aab650a7fa2047fd953cae65b12215280af.zip FreeBSD-src-1e255aab650a7fa2047fd953cae65b12215280af.tar.gz |
Update clang to r99115.
Diffstat (limited to 'lib')
86 files changed, 2755 insertions, 1471 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 8230cde..7f5c9b1 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -43,8 +43,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), - SourceMgr(SM), LangOpts(LOpts), - LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), + SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) { ObjCIdRedefinitionType = QualType(); @@ -413,201 +412,6 @@ namespace { }; } -/// \brief Determine whether the given comment is a Doxygen-style comment. -/// -/// \param Start the start of the comment text. -/// -/// \param End the end of the comment text. -/// -/// \param Member whether we want to check whether this is a member comment -/// (which requires a < after the Doxygen-comment delimiter). Otherwise, -/// we only return true when we find a non-member comment. -static bool -isDoxygenComment(SourceManager &SourceMgr, SourceRange Comment, - bool Member = false) { - bool Invalid = false; - const char *BufferStart - = SourceMgr.getBufferData(SourceMgr.getFileID(Comment.getBegin()), - &Invalid).data(); - if (Invalid) - return false; - - const char *Start = BufferStart + SourceMgr.getFileOffset(Comment.getBegin()); - const char* End = BufferStart + SourceMgr.getFileOffset(Comment.getEnd()); - - if (End - Start < 4) - return false; - - assert(Start[0] == '/' && "Not a comment?"); - if (Start[1] == '*' && !(Start[2] == '!' || Start[2] == '*')) - return false; - if (Start[1] == '/' && !(Start[2] == '!' || Start[2] == '/')) - return false; - - return (Start[3] == '<') == Member; -} - -/// \brief Retrieve the comment associated with the given declaration, if -/// it has one. -const char *ASTContext::getCommentForDecl(const Decl *D) { - if (!D) - return 0; - - // Check whether we have cached a comment string for this declaration - // already. - llvm::DenseMap<const Decl *, std::string>::iterator Pos - = DeclComments.find(D); - if (Pos != DeclComments.end()) - return Pos->second.c_str(); - - // If we have an external AST source and have not yet loaded comments from - // that source, do so now. - if (ExternalSource && !LoadedExternalComments) { - std::vector<SourceRange> LoadedComments; - ExternalSource->ReadComments(LoadedComments); - - if (!LoadedComments.empty()) - Comments.insert(Comments.begin(), LoadedComments.begin(), - LoadedComments.end()); - - LoadedExternalComments = true; - } - - // If there are no comments anywhere, we won't find anything. - if (Comments.empty()) - return 0; - - // If the declaration doesn't map directly to a location in a file, we - // can't find the comment. - SourceLocation DeclStartLoc = D->getLocStart(); - if (DeclStartLoc.isInvalid() || !DeclStartLoc.isFileID()) - return 0; - - // Find the comment that occurs just before this declaration. - std::vector<SourceRange>::iterator LastComment - = std::lower_bound(Comments.begin(), Comments.end(), - SourceRange(DeclStartLoc), - BeforeInTranslationUnit(&SourceMgr)); - - // Decompose the location for the start of the declaration and find the - // beginning of the file buffer. - std::pair<FileID, unsigned> DeclStartDecomp - = SourceMgr.getDecomposedLoc(DeclStartLoc); - bool Invalid = false; - const char *FileBufferStart - = SourceMgr.getBufferData(DeclStartDecomp.first, &Invalid).data(); - if (Invalid) - return 0; - - // First check whether we have a comment for a member. - if (LastComment != Comments.end() && - !isa<TagDecl>(D) && !isa<NamespaceDecl>(D) && - isDoxygenComment(SourceMgr, *LastComment, true)) { - std::pair<FileID, unsigned> LastCommentEndDecomp - = SourceMgr.getDecomposedLoc(LastComment->getEnd()); - if (DeclStartDecomp.first == LastCommentEndDecomp.first && - SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second) - == SourceMgr.getLineNumber(LastCommentEndDecomp.first, - LastCommentEndDecomp.second)) { - // The Doxygen member comment comes after the declaration starts and - // is on the same line and in the same file as the declaration. This - // is the comment we want. - std::string &Result = DeclComments[D]; - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), - FileBufferStart + LastCommentEndDecomp.second + 1); - return Result.c_str(); - } - } - - if (LastComment == Comments.begin()) - return 0; - --LastComment; - - // Decompose the end of the comment. - std::pair<FileID, unsigned> LastCommentEndDecomp - = SourceMgr.getDecomposedLoc(LastComment->getEnd()); - - // If the comment and the declaration aren't in the same file, then they - // aren't related. - if (DeclStartDecomp.first != LastCommentEndDecomp.first) - return 0; - - // Check that we actually have a Doxygen comment. - if (!isDoxygenComment(SourceMgr, *LastComment)) - return 0; - - // Compute the starting line for the declaration and for the end of the - // comment (this is expensive). - unsigned DeclStartLine - = SourceMgr.getLineNumber(DeclStartDecomp.first, DeclStartDecomp.second); - unsigned CommentEndLine - = SourceMgr.getLineNumber(LastCommentEndDecomp.first, - LastCommentEndDecomp.second); - - // If the comment does not end on the line prior to the declaration, then - // the comment is not associated with the declaration at all. - if (CommentEndLine + 1 != DeclStartLine) - return 0; - - // We have a comment, but there may be more comments on the previous lines. - // Keep looking so long as the comments are still Doxygen comments and are - // still adjacent. - unsigned ExpectedLine - = SourceMgr.getSpellingLineNumber(LastComment->getBegin()) - 1; - std::vector<SourceRange>::iterator FirstComment = LastComment; - while (FirstComment != Comments.begin()) { - // Look at the previous comment - --FirstComment; - std::pair<FileID, unsigned> Decomp - = SourceMgr.getDecomposedLoc(FirstComment->getEnd()); - - // If this previous comment is in a different file, we're done. - if (Decomp.first != DeclStartDecomp.first) { - ++FirstComment; - break; - } - - // If this comment is not a Doxygen comment, we're done. - if (!isDoxygenComment(SourceMgr, *FirstComment)) { - ++FirstComment; - break; - } - - // If the line number is not what we expected, we're done. - unsigned Line = SourceMgr.getLineNumber(Decomp.first, Decomp.second); - if (Line != ExpectedLine) { - ++FirstComment; - break; - } - - // Set the next expected line number. - ExpectedLine - = SourceMgr.getSpellingLineNumber(FirstComment->getBegin()) - 1; - } - - // The iterator range [FirstComment, LastComment] contains all of the - // BCPL comments that, together, are associated with this declaration. - // Form a single comment block string for this declaration that concatenates - // all of these comments. - std::string &Result = DeclComments[D]; - while (FirstComment != LastComment) { - std::pair<FileID, unsigned> DecompStart - = SourceMgr.getDecomposedLoc(FirstComment->getBegin()); - std::pair<FileID, unsigned> DecompEnd - = SourceMgr.getDecomposedLoc(FirstComment->getEnd()); - Result.append(FileBufferStart + DecompStart.second, - FileBufferStart + DecompEnd.second + 1); - ++FirstComment; - } - - // Append the last comment line. - Result.append(FileBufferStart + - SourceMgr.getFileOffset(LastComment->getBegin()), - FileBufferStart + LastCommentEndDecomp.second + 1); - return Result.c_str(); -} - //===----------------------------------------------------------------------===// // Type Sizing and Analysis //===----------------------------------------------------------------------===// @@ -4315,6 +4119,41 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, return false; } +/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written +/// for providing type-safty for objective-c pointers used to pass/return +/// arguments in block literals. When passed as arguments, passing 'A*' where +/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is +/// not OK. For the return type, the opposite is not OK. +bool ASTContext::canAssignObjCInterfacesInBlockPointer( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + if (RHSOPT->isObjCBuiltinType()) + return true; + + if (LHSOPT->isObjCBuiltinType()) { + return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); + } + + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false); + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (LHS && RHS) { // We have 2 user-defined types. + if (LHS != RHS) { + if (LHS->getDecl()->isSuperClassOf(RHS->getDecl())) + return false; + if (RHS->getDecl()->isSuperClassOf(LHS->getDecl())) + return true; + } + else + return true; + } + return false; +} + /// getIntersectionOfProtocols - This routine finds the intersection of set /// of protocols inherited from two distinct objective-c pointer objects. /// It is used to build composite qualifier list of the composite type of @@ -4451,7 +4290,12 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } -QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { +bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { + return !mergeTypes(LHS, RHS, true).isNull(); +} + +QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, + bool OfBlockPointer) { const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>(); const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); @@ -4460,7 +4304,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { bool allRTypes = true; // Check return type - QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType()); + QualType retType; + if (OfBlockPointer) + retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true); + else + retType = mergeTypes(lbase->getResultType(), rbase->getResultType()); if (retType.isNull()) return QualType(); if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType())) allLTypes = false; @@ -4500,7 +4348,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { for (unsigned i = 0; i < lproto_nargs; i++) { QualType largtype = lproto->getArgType(i).getUnqualifiedType(); QualType rargtype = rproto->getArgType(i).getUnqualifiedType(); - QualType argtype = mergeTypes(largtype, rargtype); + QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer); if (argtype.isNull()) return QualType(); types.push_back(argtype); if (getCanonicalType(argtype) != getCanonicalType(largtype)) @@ -4554,7 +4402,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { return getFunctionNoProtoType(retType, NoReturn, lcc); } -QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { +QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, + bool OfBlockPointer) { // C++ [expr]: If an expression initially has the type "reference to T", the // type is adjusted to "T" prior to any further analysis, the expression // designates the object or function denoted by the reference, and the @@ -4681,7 +4530,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { // Merge two block pointer types, while trying to preserve typedef info QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType(); QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType(); - QualType ResultType = mergeTypes(LHSPointee, RHSPointee); + QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) return LHS; @@ -4732,7 +4581,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { ArrayType::ArraySizeModifier(), 0); } case Type::FunctionNoProto: - return mergeFunctionTypes(LHS, RHS); + return mergeFunctionTypes(LHS, RHS, OfBlockPointer); case Type::Record: case Type::Enum: return QualType(); @@ -4761,12 +4610,19 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { return QualType(); } case Type::ObjCObjectPointer: { + if (OfBlockPointer) { + if (canAssignObjCInterfacesInBlockPointer( + LHS->getAs<ObjCObjectPointerType>(), + RHS->getAs<ObjCObjectPointerType>())) + return LHS; + return QualType(); + } if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(), RHS->getAs<ObjCObjectPointerType>())) return LHS; return QualType(); - } + } } return QualType(); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index f568d1c..6c9a45e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -430,7 +430,10 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { for (; I!=End; ++I) QualName += *I + "::"; - QualName += getNameAsString(); + if (getDeclName()) + QualName += getNameAsString(); + else + QualName += "<anonymous>"; return QualName; } diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 7d1033d..ab6b9e1 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -743,7 +743,10 @@ ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, } ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { - return getClassInterface()->FindCategoryDeclaration(getIdentifier()); + // The class interface might be NULL if we are working with invalid code. + if (const ObjCInterfaceDecl *ID = getClassInterface()) + return ID->FindCategoryDeclaration(getIdentifier()); + return 0; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1b3202d..6a71e92 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -227,7 +227,12 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { llvm::raw_svector_ostream Out(Name); Out << (MD->isInstanceMethod() ? '-' : '+'); Out << '['; - Out << MD->getClassInterface()->getNameAsString(); + + // For incorrect code, there might not be an ObjCInterfaceDecl. Do + // a null check to avoid a crash. + if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) + Out << ID->getNameAsString(); + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) { Out << '('; @@ -1104,11 +1109,11 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { if (m->isArrow()) return LV_Valid; Expr *BaseExp = m->getBase(); - if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass) + if (BaseExp->getStmtClass() == ObjCPropertyRefExprClass || + BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) return LV_SubObjCPropertySetting; return - (BaseExp->getStmtClass() == ObjCImplicitSetterGetterRefExprClass) ? - LV_SubObjCPropertyGetterSetting : BaseExp->isLvalue(Ctx); + BaseExp->isLvalue(Ctx); } case UnaryOperatorClass: if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) @@ -1324,8 +1329,6 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { return MLV_InvalidExpression; case LV_MemberFunction: return MLV_MemberFunction; case LV_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; - case LV_SubObjCPropertyGetterSetting: - return MLV_SubObjCPropertyGetterSetting; case LV_ClassTemporary: return MLV_ClassTemporary; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e036692..eeeeb5c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -406,27 +406,34 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluatePointer(PExp, ResultLValue, Info)) return APValue(); - llvm::APSInt AdditionalOffset(32); + llvm::APSInt AdditionalOffset; if (!EvaluateInteger(IExp, AdditionalOffset, Info)) return APValue(); - QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType(); - CharUnits SizeOfPointee; + // Compute the new offset in the appropriate width. + + QualType PointeeType = + PExp->getType()->getAs<PointerType>()->getPointeeType(); + llvm::APSInt SizeOfPointee(AdditionalOffset); // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) - SizeOfPointee = CharUnits::One(); + SizeOfPointee = 1; else - SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); - - CharUnits Offset = ResultLValue.getLValueOffset(); + SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity(); + llvm::APSInt Offset(AdditionalOffset); + Offset = ResultLValue.getLValueOffset().getQuantity(); if (E->getOpcode() == BinaryOperator::Add) - Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee; + Offset += AdditionalOffset * SizeOfPointee; else - Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee; + Offset -= AdditionalOffset * SizeOfPointee; - return APValue(ResultLValue.getLValueBase(), Offset); + // Sign extend prior to converting back to a char unit. + if (Offset.getBitWidth() < 64) + Offset.extend(64); + return APValue(ResultLValue.getLValueBase(), + CharUnits::fromQuantity(Offset.getLimitedValue())); } APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 09a6173..0c4896d 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Type.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -412,10 +413,12 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { return; std::string Buffer; + bool HasKindDecoration = false; // We don't print tags unless this is an elaborated type. // In C, we just assume every RecordType is an elaborated type. if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) { + HasKindDecoration = true; Buffer += D->getKindName(); Buffer += ' '; } @@ -425,15 +428,31 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { // this will always be empty. AppendScope(D->getDeclContext(), Buffer); - const char *ID; if (const IdentifierInfo *II = D->getIdentifier()) - ID = II->getNameStart(); + Buffer += II->getNameStart(); else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); - ID = Typedef->getIdentifier()->getNameStart(); - } else - ID = "<anonymous>"; - Buffer += ID; + Buffer += Typedef->getIdentifier()->getNameStart(); + } else { + // Make an unambiguous representation for anonymous types, e.g. + // <anonymous enum at /usr/include/string.h:120:9> + llvm::raw_string_ostream OS(Buffer); + OS << "<anonymous"; + + // Suppress the redundant tag keyword if we just printed one. + // We don't have to worry about ElaboratedTypes here because you can't + // refer to an anonymous type with one. + if (!HasKindDecoration) + OS << " " << D->getKindName(); + + PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( + D->getLocation()); + OS << " at " << PLoc.getFilename() + << ':' << PLoc.getLine() + << ':' << PLoc.getColumn() + << '>'; + OS.flush(); + } // If this is a class template specialization, print the template // arguments. diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index 126d640..7412b95 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -80,24 +80,24 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const { return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr); } -unsigned FullSourceLoc::getInstantiationLineNumber() const { +unsigned FullSourceLoc::getInstantiationLineNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getInstantiationLineNumber(*this); + return SrcMgr->getInstantiationLineNumber(*this, Invalid); } -unsigned FullSourceLoc::getInstantiationColumnNumber() const { +unsigned FullSourceLoc::getInstantiationColumnNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getInstantiationColumnNumber(*this); + return SrcMgr->getInstantiationColumnNumber(*this, Invalid); } -unsigned FullSourceLoc::getSpellingLineNumber() const { +unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getSpellingLineNumber(*this); + return SrcMgr->getSpellingLineNumber(*this, Invalid); } -unsigned FullSourceLoc::getSpellingColumnNumber() const { +unsigned FullSourceLoc::getSpellingColumnNumber(bool *Invalid) const { assert(isValid()); - return SrcMgr->getSpellingColumnNumber(*this); + return SrcMgr->getSpellingColumnNumber(*this, Invalid); } bool FullSourceLoc::isInSystemHeader() const { @@ -105,18 +105,18 @@ bool FullSourceLoc::isInSystemHeader() const { return SrcMgr->isInSystemHeader(*this); } -const char *FullSourceLoc::getCharacterData() const { +const char *FullSourceLoc::getCharacterData(bool *Invalid) const { assert(isValid()); - return SrcMgr->getCharacterData(*this); + return SrcMgr->getCharacterData(*this, Invalid); } -const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { +const llvm::MemoryBuffer* FullSourceLoc::getBuffer(bool *Invalid) const { assert(isValid()); - return SrcMgr->getBuffer(SrcMgr->getFileID(*this)); + return SrcMgr->getBuffer(SrcMgr->getFileID(*this), Invalid); } -llvm::StringRef FullSourceLoc::getBufferData() const { - return getBuffer()->getBuffer(); +llvm::StringRef FullSourceLoc::getBufferData(bool *Invalid) const { + return getBuffer(Invalid)->getBuffer(); } std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const { diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 4007ccf..6def967 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -32,14 +32,14 @@ using llvm::MemoryBuffer; //===----------------------------------------------------------------------===// ContentCache::~ContentCache() { - delete Buffer; + delete Buffer.getPointer(); } /// getSizeBytesMapped - Returns the number of bytes actually mapped for /// this ContentCache. This can be 0 if the MemBuffer was not actually /// instantiated. unsigned ContentCache::getSizeBytesMapped() const { - return Buffer ? Buffer->getBufferSize() : 0; + return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0; } /// getSize - Returns the size of the content encapsulated by this ContentCache. @@ -47,15 +47,16 @@ unsigned ContentCache::getSizeBytesMapped() const { /// scratch buffer. If the ContentCache encapsulates a source file, that /// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { - return Buffer ? (unsigned) Buffer->getBufferSize() - : (unsigned) Entry->getSize(); + return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() + : (unsigned) Entry->getSize(); } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { - assert(B != Buffer); + assert(B != Buffer.getPointer()); - delete Buffer; - Buffer = B; + delete Buffer.getPointer(); + Buffer.setPointer(B); + Buffer.setInt(false); } const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, @@ -64,12 +65,13 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, *Invalid = false; // Lazily create the Buffer for ContentCaches that wrap files. - if (!Buffer && Entry) { + if (!Buffer.getPointer() && Entry) { std::string ErrorStr; struct stat FileInfo; - Buffer = MemoryBuffer::getFile(Entry->getName(), &ErrorStr, - Entry->getSize(), &FileInfo); - + Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr, + Entry->getSize(), &FileInfo)); + Buffer.setInt(false); + // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer // exists. Most likely, we were using a stat cache with an invalid entry but @@ -80,34 +82,31 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // currently handle returning a null entry here. Ideally we should detect // that we are in an inconsistent situation and error out as quickly as // possible. - if (!Buffer) { + if (!Buffer.getPointer()) { const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); - Buffer = MemoryBuffer::getNewMemBuffer(Entry->getSize(), "<invalid>"); - char *Ptr = const_cast<char*>(Buffer->getBufferStart()); + Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(), + "<invalid>")); + char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; Diag.Report(diag::err_cannot_open_file) << Entry->getName() << ErrorStr; - if (Invalid) - *Invalid = true; - } else { - // Check that the file's size and modification time is the same as - // in the file entry (which may have come from a stat cache). - if (FileInfo.st_size != Entry->getSize()) { - Diag.Report(diag::err_file_size_changed) - << Entry->getName() << (unsigned)Entry->getSize() - << (unsigned)FileInfo.st_size; - if (Invalid) - *Invalid = true; - } else if (FileInfo.st_mtime != Entry->getModificationTime()) { - Diag.Report(diag::err_file_modified) << Entry->getName(); - if (Invalid) - *Invalid = true; - } + Buffer.setInt(true); + } else if (FileInfo.st_size != Entry->getSize() || + FileInfo.st_mtime != Entry->getModificationTime() || + FileInfo.st_ino != Entry->getInode()) { + // Check that the file's size, modification time, and inode are + // the same as in the file entry (which may have come from a + // stat cache). + Diag.Report(diag::err_file_modified) << Entry->getName(); + Buffer.setInt(true); } } - return Buffer; + if (Invalid) + *Invalid = Buffer.getInt(); + + return Buffer.getPointer(); } unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { @@ -412,7 +411,7 @@ FileID SourceManager::createFileID(const ContentCache *File, = SLocEntry::get(Offset, FileInfo::get(IncludePos, File, FileCharacter)); SLocEntryLoaded[PreallocatedID] = true; FileID FID = FileID::get(PreallocatedID); - return LastFileIDLookup = FID; + return FID; } SLocEntryTable.push_back(SLocEntry::get(NextOffset, @@ -475,15 +474,14 @@ bool SourceManager::overrideFileContents(const FileEntry *SourceFile, } llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { + bool MyInvalid = false; + const llvm::MemoryBuffer *Buf = getBuffer(FID, &MyInvalid); if (Invalid) - *Invalid = false; - - const llvm::MemoryBuffer *Buf = getBuffer(FID); - if (!Buf) { - if (*Invalid) - *Invalid = true; + *Invalid = MyInvalid; + + if (MyInvalid) return ""; - } + return Buf->getBuffer(); } diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 10136f3..7c53991 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -72,7 +72,9 @@ public: /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values. /// It updatees the GRState object in place with the values removed. - Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, Stmt* Loc, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); void iterBindings(Store store, BindingsHandler& f); @@ -250,6 +252,7 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { } Store BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, + const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 0cf593b..7272b34 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -36,6 +36,23 @@ BugReporterContext::~BugReporterContext() { if ((*I)->isOwnedByReporterContext()) delete *I; } +void BugReporterContext::addVisitor(BugReporterVisitor* visitor) { + if (!visitor) + return; + + llvm::FoldingSetNodeID ID; + visitor->Profile(ID); + void *InsertPos; + + if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) { + delete visitor; + return; + } + + CallbacksSet.InsertNode(visitor, InsertPos); + Callbacks = F.Add(visitor, Callbacks); +} + //===----------------------------------------------------------------------===// // Helper routines for walking the ExplodedGraph and fetching statements. //===----------------------------------------------------------------------===// @@ -1613,7 +1630,9 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, else return; + // Register node visitors. R->registerInitialVisitors(PDB, N); + bugreporter::registerNilReceiverVisitor(PDB); switch (PDB.getGenerationScheme()) { case PathDiagnosticClient::Extensive: diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 6cf41b1..1d6994b 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -92,6 +92,13 @@ public: FindLastStoreBRVisitor(SVal v, const MemRegion *r) : R(r), V(v), satisfied(false), StoreSite(0) {} + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + static int tag = 0; + ID.AddPointer(&tag); + ID.AddPointer(R); + ID.Add(V); + } + PathDiagnosticPiece* VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext& BRC) { @@ -129,8 +136,8 @@ public: return NULL; satisfied = true; - std::string sbuf; - llvm::raw_string_ostream os(sbuf); + llvm::SmallString<256> sbuf; + llvm::raw_svector_ostream os(sbuf); if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { @@ -239,6 +246,13 @@ public: TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} + void Profile(llvm::FoldingSetNodeID &ID) const { + static int tag = 0; + ID.AddPointer(&tag); + ID.AddBoolean(Assumption); + ID.Add(Constraint); + } + PathDiagnosticPiece* VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext& BRC) { @@ -365,3 +379,52 @@ void clang::bugreporter::registerFindLastStore(BugReporterContext& BRC, BRC.addVisitor(new FindLastStoreBRVisitor(V, R)); } + + +namespace { +class NilReceiverVisitor : public BugReporterVisitor { +public: + NilReceiverVisitor() {} + + void Profile(llvm::FoldingSetNodeID &ID) const { + static int x = 0; + ID.AddPointer(&x); + } + + PathDiagnosticPiece* VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext& BRC) { + + const PostStmt *P = N->getLocationAs<PostStmt>(); + if (!P) + return 0; + const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>(); + if (!ME) + return 0; + const Expr *Receiver = ME->getReceiver(); + if (!Receiver) + return 0; + const GRState *state = N->getState(); + const SVal &V = state->getSVal(Receiver); + const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V); + if (!DV) + return 0; + state = state->Assume(*DV, true); + if (state) + return 0; + + // The receiver was nil, and hence the method was skipped. + // Register a BugReporterVisitor to issue a message telling us how + // the receiver was null. + bugreporter::registerTrackNullOrUndefValue(BRC, Receiver, N); + // Issue a message saying that the method was skipped. + PathDiagnosticLocation L(Receiver, BRC.getSourceManager()); + return new PathDiagnosticEventPiece(L, "No method actually called " + "because the receiver is nil"); + } +}; +} // end anonymous namespace + +void clang::bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) { + BRC.addVisitor(new NilReceiverVisitor()); +} diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index 9013c38..32cf753 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -24,7 +24,7 @@ namespace { class CallAndMessageChecker : public CheckerVisitor<CallAndMessageChecker> { BugType *BT_call_null; - BugType *BT_call_undef; + BugType *BT_call_undef; BugType *BT_call_arg; BugType *BT_msg_undef; BugType *BT_msg_arg; @@ -44,12 +44,20 @@ public: bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME); private: + bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex, + const char *BT_desc, BugType *&BT); + void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, ExplodedNode *N); - + void HandleNilReceiver(CheckerContext &C, const GRState *state, - const ObjCMessageExpr *ME); + const ObjCMessageExpr *ME); + + void LazyInit_BT(const char *desc, BugType *&BT) { + if (!BT) + BT = new BuiltinBug(desc); + } }; } // end anonymous namespace @@ -62,19 +70,127 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, ExplodedNode *N = C.GenerateSink(); if (!N) return; - + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, bugreporter::GetCalleeExpr(N)); C.EmitReport(R); } -void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, +bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, + const Expr *Ex, + const char *BT_desc, + BugType *&BT) { + + const SVal &V = C.getState()->getSVal(Ex); + + if (V.isUndef()) { + if (ExplodedNode *N = C.GenerateSink()) { + LazyInit_BT(BT_desc, BT); + + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); + R->addRange(Ex->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex); + C.EmitReport(R); + } + return true; + } + + if (const nonloc::LazyCompoundVal *LV = + dyn_cast<nonloc::LazyCompoundVal>(&V)) { + + class FindUninitializedField { + public: + llvm::SmallVector<const FieldDecl *, 10> FieldChain; + private: + ASTContext &C; + StoreManager &StoreMgr; + MemRegionManager &MrMgr; + Store store; + public: + FindUninitializedField(ASTContext &c, StoreManager &storeMgr, + MemRegionManager &mrMgr, Store s) + : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} + + bool Find(const TypedRegion *R) { + QualType T = R->getValueType(C); + if (const RecordType *RT = T->getAsStructureType()) { + const RecordDecl *RD = RT->getDecl()->getDefinition(); + assert(RD && "Referred record has no definition"); + for (RecordDecl::field_iterator I = + RD->field_begin(), E = RD->field_end(); I!=E; ++I) { + const FieldRegion *FR = MrMgr.getFieldRegion(*I, R); + FieldChain.push_back(*I); + T = (*I)->getType(); + if (T->getAsStructureType()) { + if (Find(FR)) + return true; + } + else { + const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR)); + if (V.isUndef()) + return true; + } + FieldChain.pop_back(); + } + } + + return false; + } + }; + + const LazyCompoundValData *D = LV->getCVData(); + FindUninitializedField F(C.getASTContext(), + C.getState()->getStateManager().getStoreManager(), + C.getValueManager().getRegionManager(), + D->getStore()); + + if (F.Find(D->getRegion())) { + if (ExplodedNode *N = C.GenerateSink()) { + LazyInit_BT(BT_desc, BT); + llvm::SmallString<512> Str; + llvm::raw_svector_ostream os(Str); + os << "Passed-by-value struct argument contains uninitialized data"; + + if (F.FieldChain.size() == 1) + os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString() + << "')"; + else { + os << " (e.g., via the field chain: '"; + bool first = true; + for (llvm::SmallVectorImpl<const FieldDecl *>::iterator + DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ + if (first) + first = false; + else + os << '.'; + os << (*DI)->getNameAsString(); + } + os << "')"; + } + + // Generate a report for this bug. + EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N); + R->addRange(Ex->getSourceRange()); + + // FIXME: enhance track back for uninitialized value for arbitrary + // memregions + C.EmitReport(R); + } + return true; + } + } + + return false; +} + +void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE){ - + const Expr *Callee = CE->getCallee()->IgnoreParens(); SVal L = C.getState()->getSVal(Callee); - + if (L.isUndef()) { if (!BT_call_undef) BT_call_undef = @@ -82,31 +198,20 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, EmitBadCall(BT_call_undef, C, CE); return; } - + if (isa<loc::ConcreteInt>(L)) { if (!BT_call_null) BT_call_null = new BuiltinBug("Called function pointer is null (null dereference)"); EmitBadCall(BT_call_null, C, CE); - } - - for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) { - if (C.getState()->getSVal(*I).isUndef()) { - if (ExplodedNode *N = C.GenerateSink()) { - if (!BT_call_arg) - BT_call_arg = new BuiltinBug("Pass-by-value argument in function call" - " is undefined"); - // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg, - BT_call_arg->getName(), N); - R->addRange((*I)->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); - C.EmitReport(R); - return; - } - } } + + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) + if (PreVisitProcessArg(C, *I, + "Pass-by-value argument in function call is" + " undefined", BT_call_arg)) + return; } void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, @@ -132,23 +237,11 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C, // Check for any arguments that are uninitialized/undefined. for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(), - E = ME->arg_end(); I != E; ++I) { - if (state->getSVal(*I).isUndef()) { - if (ExplodedNode *N = C.GenerateSink()) { - if (!BT_msg_arg) - BT_msg_arg = - new BuiltinBug("Pass-by-value argument in message expression" - " is undefined"); - // Generate a report for this bug. - EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg, - BT_msg_arg->getName(), N); - R->addRange((*I)->getSourceRange()); - R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I); - C.EmitReport(R); + E = ME->arg_end(); I != E; ++I) + if (PreVisitProcessArg(C, *I, + "Pass-by-value argument in message expression " + "is undefined", BT_msg_arg)) return; - } - } - } } bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, @@ -160,24 +253,24 @@ bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C, void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME, ExplodedNode *N) { - + if (!BT_msg_ret) BT_msg_ret = new BuiltinBug("Receiver in message expression is " "'nil' and returns a garbage value"); - + llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); os << "The receiver of message '" << ME->getSelector().getAsString() << "' is nil and returns a value of type '" << ME->getType().getAsString() << "' that will be garbage"; - + EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N); const Expr *receiver = ME->getReceiver(); report->addRange(receiver->getSourceRange()); - report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, + report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, receiver); - C.EmitReport(report); + C.EmitReport(report); } static bool SupportsNilWithFloatRet(const llvm::Triple &triple) { @@ -188,11 +281,11 @@ static bool SupportsNilWithFloatRet(const llvm::Triple &triple) { void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const GRState *state, const ObjCMessageExpr *ME) { - + // Check the return type of the message expression. A message to nil will // return different values depending on the return type and the architecture. QualType RetTy = ME->getType(); - + ASTContext &Ctx = C.getASTContext(); CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); @@ -216,7 +309,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, if (CanRetTy != Ctx.VoidTy && C.getPredecessor()->getParentMap().isConsumedExpr(ME)) { // Compute: sizeof(void *) and sizeof(return type) - const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); + const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); if (voidPtrSize < returnTypeSize && @@ -247,6 +340,6 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, C.GenerateNode(state->BindExpr(ME, V)); return; } - + C.addTransition(state); } diff --git a/lib/Checker/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp index 31f9390..d6ea187 100644 --- a/lib/Checker/CheckDeadStores.cpp +++ b/lib/Checker/CheckDeadStores.cpp @@ -220,16 +220,25 @@ public: if (E->isConstantInitializer(Ctx)) return; - // Special case: check for initializations from constant - // variables. - // - // e.g. extern const int MyConstant; - // int x = MyConstant; - // if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) - if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + // Special case: check for initialization from constant + // variables. + // + // e.g. extern const int MyConstant; + // int x = MyConstant; + // if (VD->hasGlobalStorage() && - VD->getType().isConstQualified()) return; + VD->getType().isConstQualified()) + return; + // Special case: check for initialization from scalar + // parameters. This is often a form of defensive + // programming. Non-scalars are still an error since + // because it more likely represents an actual algorithmic + // bug. + if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType()) + return; + } Report(V, DeadInit, V->getLocation(), E->getSourceRange()); } diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp index 07a54fb..2af9ffa 100644 --- a/lib/Checker/FlatStore.cpp +++ b/lib/Checker/FlatStore.cpp @@ -44,7 +44,9 @@ public: } SVal ArrayToPointer(Loc Array); - Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, Stmt* Loc, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots){ return store; } diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index e64ba94..3ace552 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -481,7 +481,9 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { SymbolReaper SymReaper(BasePred->getLocationContext(), SymMgr); CleanedState = AMgr.shouldPurgeDead() - ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, SymReaper) + ? StateMgr.RemoveDeadBindings(EntryNode->getState(), CurrentStmt, + BasePred->getLocationContext()->getCurrentStackFrame(), + SymReaper) : EntryNode->getState(); // Process any special transfer function for dead symbols. diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp index 97ede1d..2defbcd 100644 --- a/lib/Checker/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -35,6 +35,7 @@ GRStateManager::~GRStateManager() { const GRState* GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, + const StackFrameContext *LCtx, SymbolReaper& SymReaper) { // This code essentially performs a "mark-and-sweep" of the VariableBindings. @@ -50,7 +51,7 @@ GRStateManager::RemoveDeadBindings(const GRState* state, Stmt* Loc, state, RegionRoots); // Clean up the store. - NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, SymReaper, + NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, Loc, LCtx, SymReaper, RegionRoots); return ConstraintMgr->RemoveDeadBindings(getPersistentState(NewState), diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index 307ef78..c2b702a 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -354,7 +354,9 @@ public: // Part of public interface to class. /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. - Store RemoveDeadBindings(Store store, Stmt* Loc, SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, Stmt* Loc, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots); const GRState *EnterStackFrame(const GRState *state, @@ -1678,12 +1680,14 @@ class RemoveDeadBindingsWorker : llvm::SmallVector<const SymbolicRegion*, 12> Postponed; SymbolReaper &SymReaper; Stmt *Loc; + const StackFrameContext *CurrentLCtx; + public: RemoveDeadBindingsWorker(RegionStoreManager &rm, GRStateManager &stateMgr, RegionBindings b, SymbolReaper &symReaper, - Stmt *loc) + Stmt *loc, const StackFrameContext *LCtx) : ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b), - SymReaper(symReaper), Loc(loc) {} + SymReaper(symReaper), Loc(loc), CurrentLCtx(LCtx) {} // Called by ClusterAnalysis. void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C); @@ -1713,6 +1717,15 @@ void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, return; } + + // CXXThisRegion in the current or parent location context is live. + if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) { + const StackArgumentsSpaceRegion *StackReg = + cast<StackArgumentsSpaceRegion>(TR->getSuperRegion()); + const StackFrameContext *RegCtx = StackReg->getStackFrame(); + if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx)) + AddToWorkList(TR, C); + } } void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR, @@ -1799,11 +1812,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() { } Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc, + const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) { RegionBindings B = GetRegionBindings(store); - RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc); + RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, Loc, LCtx); W.GenerateClusters(); // Enqueue the region roots onto the worklist. diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 706e441..419ed73 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -25,17 +25,47 @@ using namespace clang; using namespace CodeGen; using namespace llvm; +static void EmitMemoryBarrier(CodeGenFunction &CGF, + bool LoadLoad, bool LoadStore, + bool StoreLoad, bool StoreStore, + bool Device) { + Value *True = llvm::ConstantInt::getTrue(CGF.getLLVMContext()); + Value *False = llvm::ConstantInt::getFalse(CGF.getLLVMContext()); + Value *C[5] = { LoadLoad ? True : False, + LoadStore ? True : False, + StoreLoad ? True : False, + StoreStore ? True : False, + Device ? True : False }; + CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::memory_barrier), + C, C + 5); +} + +// The atomic builtins are also full memory barriers. This is a utility for +// wrapping a call to the builtins with memory barriers. +static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn, + Value **ArgBegin, Value **ArgEnd) { + // FIXME: We need a target hook for whether this applies to device memory or + // not. + bool Device = true; + + // Create barriers both before and after the call. + EmitMemoryBarrier(CGF, true, true, true, true, Device); + Value *Result = CGF.Builder.CreateCall(Fn, ArgBegin, ArgEnd); + EmitMemoryBarrier(CGF, true, true, true, true, Device); + return Result; +} + /// Utility to insert an atomic instruction based on Instrinsic::ID /// and the expression node. -static RValue EmitBinaryAtomic(CodeGenFunction& CGF, +static RValue EmitBinaryAtomic(CodeGenFunction &CGF, Intrinsic::ID Id, const CallExpr *E) { + Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)), + CGF.EmitScalarExpr(E->getArg(1)) }; const llvm::Type *ResType[2]; ResType[0] = CGF.ConvertType(E->getType()); ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); - return RValue::get(CGF.Builder.CreateCall2(AtomF, - CGF.EmitScalarExpr(E->getArg(0)), - CGF.EmitScalarExpr(E->getArg(1)))); + return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2)); } /// Utility to insert an atomic instruction based Instrinsic::ID and @@ -48,15 +78,14 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction& CGF, ResType[0] = CGF.ConvertType(E->getType()); ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); - Value *Ptr = CGF.EmitScalarExpr(E->getArg(0)); - Value *Operand = CGF.EmitScalarExpr(E->getArg(1)); - Value *Result = CGF.Builder.CreateCall2(AtomF, Ptr, Operand); + Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)), + CGF.EmitScalarExpr(E->getArg(1)) }; + Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2); if (Id == Intrinsic::atomic_load_nand) Result = CGF.Builder.CreateNot(Result); - - return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Operand)); + return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1])); } static llvm::ConstantInt *getInt32(llvm::LLVMContext &Context, int32_t Value) { @@ -585,33 +614,31 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_val_compare_and_swap_2: case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: - case Builtin::BI__sync_val_compare_and_swap_16: - { + case Builtin::BI__sync_val_compare_and_swap_16: { const llvm::Type *ResType[2]; ResType[0]= ConvertType(E->getType()); ResType[1] = ConvertType(E->getArg(0)->getType()); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); - return RValue::get(Builder.CreateCall3(AtomF, - EmitScalarExpr(E->getArg(0)), - EmitScalarExpr(E->getArg(1)), - EmitScalarExpr(E->getArg(2)))); + Value *Args[3] = { EmitScalarExpr(E->getArg(0)), + EmitScalarExpr(E->getArg(1)), + EmitScalarExpr(E->getArg(2)) }; + return RValue::get(EmitCallWithBarrier(*this, AtomF, Args, Args + 3)); } case Builtin::BI__sync_bool_compare_and_swap_1: case Builtin::BI__sync_bool_compare_and_swap_2: case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: - case Builtin::BI__sync_bool_compare_and_swap_16: - { + case Builtin::BI__sync_bool_compare_and_swap_16: { const llvm::Type *ResType[2]; ResType[0]= ConvertType(E->getArg(1)->getType()); ResType[1] = llvm::PointerType::getUnqual(ResType[0]); Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); Value *OldVal = EmitScalarExpr(E->getArg(1)); - Value *PrevVal = Builder.CreateCall3(AtomF, - EmitScalarExpr(E->getArg(0)), - OldVal, - EmitScalarExpr(E->getArg(2))); + Value *Args[3] = { EmitScalarExpr(E->getArg(0)), + OldVal, + EmitScalarExpr(E->getArg(2)) }; + Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3); Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal); // zext bool to int. return RValue::get(Builder.CreateZExt(Result, ConvertType(E->getType()))); @@ -623,6 +650,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); + case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: case Builtin::BI__sync_lock_release_4: @@ -638,10 +666,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__sync_synchronize: { - Value *C[5]; - C[0] = C[1] = C[2] = C[3] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 1); - C[4] = llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0); - Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5); + // We assume like gcc appears to, that this only applies to cached memory. + EmitMemoryBarrier(*this, true, true, true, true, false); return RValue::get(0); } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 7752cf7..b88001c 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -165,19 +165,21 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); // Switch any previous uses to the alias. - const char *MangledName = getMangledName(AliasDecl); - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; + MangleBuffer MangledName; + getMangledName(MangledName, AliasDecl); + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { assert(Entry->isDeclaration() && "definition already exists for alias"); assert(Entry->getType() == AliasType && "declaration exists with different type"); + Alias->takeName(Entry); Entry->replaceAllUsesWith(Alias); Entry->eraseFromParent(); + } else { + Alias->setName(MangledName.getString()); } - Entry = Alias; // Finally, set up the alias with its proper name and attributes. - Alias->setName(MangledName); SetCommonAttributes(AliasDecl.getDecl(), Alias); return false; @@ -214,8 +216,9 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, llvm::GlobalValue * CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, CXXCtorType Type) { - const char *Name = getMangledCXXCtorName(D, Type); - if (llvm::GlobalValue *V = GlobalDeclMap[Name]) + MangleBuffer Name; + getMangledCXXCtorName(Name, D, Type); + if (llvm::GlobalValue *V = GetGlobalValue(Name)) return V; const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>(); @@ -226,13 +229,10 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, - CXXCtorType Type) { - llvm::SmallString<256> Name; - getMangleContext().mangleCXXCtor(D, Type, Name); - - Name += '\0'; - return UniqueMangledName(Name.begin(), Name.end()); +void CodeGenModule::getMangledCXXCtorName(MangleBuffer &Name, + const CXXConstructorDecl *D, + CXXCtorType Type) { + getMangleContext().mangleCXXCtor(D, Type, Name.getBuffer()); } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { @@ -279,8 +279,9 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, llvm::GlobalValue * CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type) { - const char *Name = getMangledCXXDtorName(D, Type); - if (llvm::GlobalValue *V = GlobalDeclMap[Name]) + MangleBuffer Name; + getMangledCXXDtorName(Name, D, Type); + if (llvm::GlobalValue *V = GetGlobalValue(Name)) return V; const llvm::FunctionType *FTy = @@ -290,13 +291,10 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } -const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D, - CXXDtorType Type) { - llvm::SmallString<256> Name; - getMangleContext().mangleCXXDtor(D, Type, Name); - - Name += '\0'; - return UniqueMangledName(Name.begin(), Name.end()); +void CodeGenModule::getMangledCXXDtorName(MangleBuffer &Name, + const CXXDestructorDecl *D, + CXXDtorType Type) { + getMangleContext().mangleCXXDtor(D, Type, Name.getBuffer()); } llvm::Constant * @@ -470,12 +468,10 @@ CodeGenModule::GetAddrOfThunk(GlobalDecl GD, OutName); else getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); - OutName += '\0'; - const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); // Get function for mangled name const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); - return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); + return GetOrCreateLLVMFunction(OutName, Ty, GlobalDecl()); } llvm::Constant * @@ -484,10 +480,8 @@ CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); // Compute mangled name - llvm::SmallString<256> OutName; - getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); - OutName += '\0'; - const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + llvm::SmallString<256> Name; + getMangleContext().mangleCovariantThunk(MD, Adjustment, Name); // Get function for mangled name const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); @@ -528,9 +522,6 @@ void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { llvm::Constant *SubExpr = cast<llvm::ConstantExpr>(FnConst)->getOperand(0); llvm::Function *OldFn = cast<llvm::Function>(SubExpr); - std::string Name = OldFn->getNameStr(); - GlobalDeclMap.erase(UniqueMangledName(Name.data(), - Name.data() + Name.size() + 1)); llvm::Constant *NewFnConst; if (!ReturnAdjustment.isEmpty()) NewFnConst = GetAddrOfCovariantThunk(GD, CoAdj); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 60aa4e7..ad97d08 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -104,12 +104,20 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { void CGDebugInfo::CreateCompileUnit() { // Get absolute path name. + SourceManager &SM = CGM.getContext().getSourceManager(); std::string MainFileName = CGM.getCodeGenOpts().MainFileName; if (MainFileName.empty()) MainFileName = "<unknown>"; + llvm::sys::Path AbsFileName(MainFileName); AbsFileName.makeAbsolute(); + std::string MainFileDir; + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) + MainFileDir = MainFile->getDir()->getName(); + else + MainFileDir = AbsFileName.getDirname(); + unsigned LangTag; const LangOptions &LO = CGM.getLangOptions(); if (LO.CPlusPlus) { @@ -138,7 +146,7 @@ void CGDebugInfo::CreateCompileUnit() { // Create new compile unit. TheCU = DebugFactory.CreateCompileUnit( - LangTag, AbsFileName.getLast(), AbsFileName.getDirname(), Producer, true, + LangTag, AbsFileName.getLast(), MainFileDir, Producer, true, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); } @@ -561,13 +569,13 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method); llvm::StringRef MethodName = getFunctionName(Method); - llvm::StringRef MethodLinkageName; llvm::DIType MethodTy = getOrCreateMethodType(Method, Unit); // Since a single ctor/dtor corresponds to multiple functions, it doesn't // make sense to give a single ctor/dtor a linkage name. + MangleBuffer MethodLinkageName; if (!IsCtorOrDtor) - MethodLinkageName = CGM.getMangledName(Method); + CGM.getMangledName(MethodLinkageName, Method); SourceManager &SM = CGM.getContext().getSourceManager(); @@ -1299,7 +1307,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, CGBuilderTy &Builder) { llvm::StringRef Name; - llvm::StringRef LinkageName; + MangleBuffer LinkageName; const Decl *D = GD.getDecl(); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -1318,11 +1326,11 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); // Use mangled name as linkage name for c/c++ functions. - LinkageName = CGM.getMangledName(GD); + CGM.getMangledName(LinkageName, GD); } else { // Use llvm function name as linkage name. Name = Fn->getName(); - LinkageName = Name; + LinkageName.setString(Name); if (!Name.empty() && Name[0] == '\01') Name = Name.substr(1); } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 1dc083f..4eb95af 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -103,13 +103,18 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, const char *Separator) { CodeGenModule &CGM = CGF.CGM; - if (CGF.getContext().getLangOptions().CPlusPlus) - return CGM.getMangledName(&D); + if (CGF.getContext().getLangOptions().CPlusPlus) { + MangleBuffer Name; + CGM.getMangledName(Name, &D); + return Name.getString().str(); + } std::string ContextName; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) - ContextName = CGM.getMangledName(FD); - else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CGF.CurFuncDecl)) { + MangleBuffer Name; + CGM.getMangledName(Name, FD); + ContextName = Name.getString().str(); + } else if (isa<ObjCMethodDecl>(CGF.CurFuncDecl)) ContextName = CGF.CurFn->getName(); else // FIXME: What about in a block?? diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 0de3b0b..40c18ca 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "clang/CodeGen/CodeGenOptions.h" using namespace clang; using namespace CodeGen; @@ -64,7 +65,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); } else - DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); } @@ -92,6 +93,12 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *DeclPtr) { + // Generate a global destructor entry if not using __cxa_atexit. + if (!CGM.getCodeGenOpts().CXAAtExit) { + CGM.AddCXXDtorEntry(DtorFn, DeclPtr); + return; + } + const llvm::Type *Int8PtrTy = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); @@ -150,10 +157,9 @@ CodeGenModule::EmitCXXGlobalInitFunc() { false); // Create our global initialization function. - // FIXME: Should this be tweakable by targets? llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, - "__cxx_global_initialization", &TheModule); + "_GLOBAL__I_a", &TheModule); CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, &CXXGlobalInits[0], @@ -161,6 +167,28 @@ CodeGenModule::EmitCXXGlobalInitFunc() { AddGlobalCtor(Fn); } +void CodeGenModule::AddCXXDtorEntry(llvm::Constant *DtorFn, + llvm::Constant *Object) { + CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object)); +} + +void CodeGenModule::EmitCXXGlobalDtorFunc() { + if (CXXGlobalDtors.empty()) + return; + + const llvm::FunctionType *FTy + = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), + false); + + // Create our global destructor function. + llvm::Function *Fn = + llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, + "_GLOBAL__D_a", &TheModule); + + CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors); + AddGlobalDtor(Fn); +} + void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D) { StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), @@ -184,6 +212,20 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, FinishFunction(); } +void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, + const std::vector<std::pair<llvm::Constant*, llvm::Constant*> > + &DtorsAndObjects) { + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), + SourceLocation()); + + // Emit the dtors, in reverse order from construction. + for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) + Builder.CreateCall(DtorsAndObjects[e - i - 1].first, + DtorsAndObjects[e - i - 1].second); + + FinishFunction(); +} + static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) { // int __cxa_guard_acquire(__int64_t *guard_object); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 142cb81..1e15066 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -486,8 +486,6 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); - llvm::SmallVector<llvm::Value*, 8> Args; - Args.clear(); SelectorArgs.push_back(Exc); SelectorArgs.push_back(Personality); @@ -584,12 +582,11 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - Args.clear(); - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 0)); - Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::Value *Args[] = { + Exc, Personality, + llvm::ConstantInt::getNullValue(llvm::Type::getInt32Ty(VMContext)) + }; + Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); Builder.CreateStore(Exc, RethrowPtr); EmitBranchThroughCleanup(FinallyRethrow); @@ -600,7 +597,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); Builder.CreateInvoke(getEndCatchFn(*this), Cont, TerminateHandler, - Args.begin(), Args.begin()); + &Args[0], &Args[0]); EmitBlock(Cont); if (Info.SwitchBlock) EmitBlock(Info.SwitchBlock); @@ -677,12 +674,8 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() { // C string type. Used in lots of places. PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty); - llvm::SmallVector<llvm::Value*, 8> Args; - Args.clear(); - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(Null); - CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::Value *Args[] = { Exc, Personality, Null }; + CGF.Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); CGF.EmitBlock(CleanupEntryBB); @@ -731,12 +724,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); // We are required to emit this call to satisfy LLVM, even // though we don't use the result. - llvm::SmallVector<llvm::Value*, 8> Args; - Args.push_back(Exc); - Args.push_back(Personality); - Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), - 1)); - Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + llvm::Value *Args[] = { + Exc, Personality, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 1) + }; + Builder.CreateCall(llvm_eh_selector, &Args[0], llvm::array_endof(Args)); llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this)); TerminateCall->setDoesNotReturn(); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 2436357..119819b 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1634,7 +1634,7 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCCategoryImplDecl *OCD = dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext()); std::string CategoryName = OCD ? OCD->getNameAsString() : ""; - std::string ClassName = OMD->getClassInterface()->getNameAsString(); + std::string ClassName = CD->getName(); std::string MethodName = OMD->getSelector().getAsString(); bool isClassMethod = !OMD->isInstanceMethod(); diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 9bcf986..df30f47 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" +#include <algorithm> #include <cstdio> using namespace clang; @@ -1147,6 +1148,12 @@ private: ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; + } }; /// MethodInfo - Contains information about a method in a vtable. @@ -1191,6 +1198,12 @@ private: ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; + } }; /// ThunkInfo - The 'this' pointer adjustment as well as an optional return @@ -1206,8 +1219,12 @@ private: ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) : This(This), Return(Return) { } - - bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return; + } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } }; typedef llvm::DenseMap<uint64_t, ThunkInfo> ThunksInfoMapTy; @@ -1215,6 +1232,16 @@ private: /// Thunks - The thunks by vtable index in the vtable currently being built. ThunksInfoMapTy Thunks; + typedef llvm::DenseMap<const CXXMethodDecl *, + llvm::SmallVector<ThunkInfo, 1> > MethodThunksMapTy; + + /// MethodThunks - A map that contains all the thunks needed for all methods + /// in the vtable currently being built. + MethodThunksMapTy MethodThunks; + + /// AddThunk - Add a thunk for the given method. + void AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk); + /// ComputeThisAdjustments - Compute the 'this' pointer adjustments for the /// part of the vtable we're currently building. void ComputeThisAdjustments(); @@ -1330,6 +1357,20 @@ public: void dumpLayout(llvm::raw_ostream&); }; +void VtableBuilder::AddThunk(const CXXMethodDecl *MD, ThunkInfo &Thunk) { + if (isBuildingConstructorVtable()) + return; + + llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD]; + + // Check if we have this thunk already. + if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) != + ThunksVector.end()) + return; + + ThunksVector.push_back(Thunk); +} + /// OverridesMethodInBases - Checks whether whether this virtual member /// function overrides a member function in any of the given bases. /// Returns the overridden member function, or null if none was found. @@ -1382,6 +1423,8 @@ void VtableBuilder::ComputeThisAdjustments() { // Add an adjustment for the deleting destructor as well. Thunks[VtableIndex + 1].This = ThisAdjustment; } + + AddThunk(Overrider.Method, Thunks[VtableIndex]); } /// Clear the method info map. @@ -2182,20 +2225,25 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << '\n'; - if (!isBuildingConstructorVtable() && MostDerivedClass->getNumVBases()) { - Out << "Virtual base offset offsets for '"; - Out << MostDerivedClass->getQualifiedNameAsString() << "'.\n"; - + if (isBuildingConstructorVtable()) + return; + + if (MostDerivedClass->getNumVBases()) { // We store the virtual base class names and their offsets in a map to get // a stable order. - std::map<std::string, int64_t> ClassNamesAndOffsets; + std::map<std::string, int64_t> ClassNamesAndOffsets; for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), E = VBaseOffsetOffsets.end(); I != E; ++I) { std::string ClassName = I->first->getQualifiedNameAsString(); int64_t OffsetOffset = I->second; ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); } + + Out << "Virtual base offset offsets for '"; + Out << MostDerivedClass->getQualifiedNameAsString() << "' ("; + Out << ClassNamesAndOffsets.size(); + Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; for (std::map<std::string, int64_t>::const_iterator I = ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); @@ -2204,6 +2252,52 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << "\n"; } + + if (!MethodThunks.empty()) { + + // We store the method names in a map to get a stable order. + std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls; + + for (MethodThunksMapTy::const_iterator I = MethodThunks.begin(), + E = MethodThunks.end(); I != E; ++I) { + const CXXMethodDecl *MD = I->first; + std::string MethodName = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + + MethodNamesAndDecls.insert(std::make_pair(MethodName, MD)); + } + + for (std::map<std::string, const CXXMethodDecl *>::const_iterator I = + MethodNamesAndDecls.begin(), E = MethodNamesAndDecls.end(); + I != E; ++I) { + const std::string &MethodName = I->first; + const CXXMethodDecl *MD = I->second; + const llvm::SmallVector<ThunkInfo, 1> &ThunksVector = MethodThunks[MD]; + + Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size(); + Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n"; + + for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) { + const ThunkInfo &Thunk = ThunksVector[I]; + + Out << llvm::format("%4d | ", I); + + // If this function pointer has a 'this' pointer adjustment, dump it. + if (!Thunk.This.isEmpty()) { + Out << "this: "; + Out << Thunk.This.NonVirtual << " nv"; + + if (Thunk.This.VCallOffsetOffset) { + Out << ", " << Thunk.This.VCallOffsetOffset; + Out << " v"; + } + } + + Out << '\n'; + } + } + } } } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 88d6413..bd12c4a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1231,6 +1231,12 @@ public: llvm::Constant **Decls, unsigned NumDecls); + /// GenerateCXXGlobalDtorFunc - Generates code for destroying global + /// variables. + void GenerateCXXGlobalDtorFunc(llvm::Function *Fn, + const std::vector<std::pair<llvm::Constant*, + llvm::Constant*> > &DtorsAndObjects); + void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D); void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index f41db14..b4b5bbd 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -81,6 +81,7 @@ void CodeGenModule::createObjCRuntime() { void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); + EmitCXXGlobalDtorFunc(); if (Runtime) if (llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction()) AddGlobalCtor(ObjCInitFunction); @@ -163,15 +164,15 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, } } -const char *CodeGenModule::getMangledName(const GlobalDecl &GD) { +void CodeGenModule::getMangledName(MangleBuffer &Buffer, GlobalDecl GD) { const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(ND)) - return getMangledCXXCtorName(D, GD.getCtorType()); + return getMangledCXXCtorName(Buffer, D, GD.getCtorType()); if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND)) - return getMangledCXXDtorName(D, GD.getDtorType()); + return getMangledCXXDtorName(Buffer, D, GD.getDtorType()); - return getMangledName(ND); + return getMangledName(Buffer, ND); } /// \brief Retrieves the mangled name for the given declaration. @@ -180,23 +181,19 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) { /// const char* containing the mangled name. Otherwise, returns /// the unmangled name. /// -const char *CodeGenModule::getMangledName(const NamedDecl *ND) { +void CodeGenModule::getMangledName(MangleBuffer &Buffer, + const NamedDecl *ND) { if (!getMangleContext().shouldMangleDeclName(ND)) { assert(ND->getIdentifier() && "Attempt to mangle unnamed decl."); - return ND->getNameAsCString(); + Buffer.setString(ND->getNameAsCString()); + return; } - llvm::SmallString<256> Name; - getMangleContext().mangleName(ND, Name); - Name += '\0'; - return UniqueMangledName(Name.begin(), Name.end()); + getMangleContext().mangleName(ND, Buffer.getBuffer()); } -const char *CodeGenModule::UniqueMangledName(const char *NameStart, - const char *NameEnd) { - assert(*(NameEnd - 1) == '\0' && "Mangled name must be null terminated!"); - - return MangledNames.GetOrCreateValue(NameStart, NameEnd).getKeyData(); +llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) { + return getModule().getNamedValue(Name); } /// AddGlobalCtor - Add a function to the list that will be called before @@ -505,11 +502,12 @@ void CodeGenModule::EmitDeferred() { GlobalDecl D = DeferredDeclsToEmit.back(); DeferredDeclsToEmit.pop_back(); - // The mangled name for the decl must have been emitted in GlobalDeclMap. // Look it up to see if it was defined with a stronger definition (e.g. an // extern inline function with a strong function redefinition). If so, // just ignore the deferred decl. - llvm::GlobalValue *CGRef = GlobalDeclMap[getMangledName(D)]; + MangleBuffer Name; + getMangledName(Name, D); + llvm::GlobalValue *CGRef = GetGlobalValue(Name); assert(CGRef && "Deferred decl wasn't referenced?"); if (!CGRef->isDeclaration()) @@ -644,18 +642,14 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(VD->getType()); - // Unique the name through the identifier table. - const char *AliaseeName = - getContext().Idents.get(AA->getAliasee()).getNameStart(); - // See if there is already something with the target's name in the module. - llvm::GlobalValue *Entry = GlobalDeclMap[AliaseeName]; + llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee()); llvm::Constant *Aliasee; if (isa<llvm::FunctionType>(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl()); + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl()); else - Aliasee = GetOrCreateLLVMGlobal(AliaseeName, + Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); if (!Entry) { llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee); @@ -676,7 +670,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // If this is an alias definition (which otherwise looks like a declaration) // emit it now. if (Global->hasAttr<AliasAttr>()) - return EmitAliasDefinition(Global); + return EmitAliasDefinition(GD); // Ignore declarations, they will be emitted on their first use. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Global)) { @@ -696,8 +690,9 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { if (MayDeferGeneration(Global)) { // If the value has already been used, add it directly to the // DeferredDeclsToEmit list. - const char *MangledName = getMangledName(GD); - if (GlobalDeclMap.count(MangledName)) + MangleBuffer MangledName; + getMangledName(MangledName, GD); + if (GetGlobalValue(MangledName)) DeferredDeclsToEmit.push_back(GD); else { // Otherwise, remember that we saw a deferred decl with this name. The @@ -753,11 +748,12 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the function when it is first created. -llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, - const llvm::Type *Ty, - GlobalDecl D) { +llvm::Constant * +CodeGenModule::GetOrCreateLLVMFunction(llvm::StringRef MangledName, + const llvm::Type *Ty, + GlobalDecl D) { // Lookup the entry, lazily creating it if necessary. - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.count(Entry)) { const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl()); @@ -786,17 +782,15 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName, } llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty), llvm::Function::ExternalLinkage, - "", &getModule()); - F->setName(MangledName); + MangledName, &getModule()); + assert(F->getName() == MangledName && "name was uniqued!"); if (D.getDecl()) SetFunctionAttributes(D, F, IsIncompleteFunction); - Entry = F; // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. - llvm::DenseMap<const char*, GlobalDecl>::iterator DDI = - DeferredDecls.find(MangledName); + llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). @@ -839,16 +833,16 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType()); - return GetOrCreateLLVMFunction(getMangledName(GD), Ty, GD); + MangleBuffer MangledName; + getMangledName(MangledName, GD); + return GetOrCreateLLVMFunction(MangledName, Ty, GD); } /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant * CodeGenModule::CreateRuntimeFunction(const llvm::FunctionType *FTy, - const char *Name) { - // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getNameStart(); + llvm::StringRef Name) { return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl()); } @@ -870,11 +864,12 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D) { /// /// If D is non-null, it specifies a decl that correspond to this. This is used /// to set the attributes on the global when it is first created. -llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, - const llvm::PointerType*Ty, - const VarDecl *D) { +llvm::Constant * +CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, + const llvm::PointerType *Ty, + const VarDecl *D) { // Lookup the entry, lazily creating it if necessary. - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { if (WeakRefReferences.count(Entry)) { if (D && !D->hasAttr<WeakAttr>()) @@ -893,8 +888,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end // of the file. - llvm::DenseMap<const char*, GlobalDecl>::iterator DDI = - DeferredDecls.find(MangledName); + llvm::StringMap<GlobalDecl>::iterator DDI = DeferredDecls.find(MangledName); if (DDI != DeferredDecls.end()) { // Move the potentially referenced deferred decl to the DeferredDeclsToEmit // list, and remove it from DeferredDecls (since we don't need it anymore). @@ -905,9 +899,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, - 0, "", 0, + 0, MangledName, 0, false, Ty->getAddressSpace()); - GV->setName(MangledName); // Handle things which are present even on external declarations. if (D) { @@ -926,7 +919,7 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMGlobal(const char *MangledName, GV->setThreadLocal(D->isThreadSpecified()); } - return Entry = GV; + return GV; } @@ -943,16 +936,17 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, const llvm::PointerType *PTy = llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); - return GetOrCreateLLVMGlobal(getMangledName(D), PTy, D); + + MangleBuffer MangledName; + getMangledName(MangledName, D); + return GetOrCreateLLVMGlobal(MangledName, PTy, D); } /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant * CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty, - const char *Name) { - // Convert Name to be a uniqued string from the IdentifierInfo table. - Name = getContext().Idents.get(Name).getNameStart(); + llvm::StringRef Name) { return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0); } @@ -963,8 +957,9 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { // If we have not seen a reference to this variable yet, place it // into the deferred declarations table to be emitted if needed // later. - const char *MangledName = getMangledName(D); - if (GlobalDeclMap.count(MangledName) == 0) { + MangleBuffer MangledName; + getMangledName(MangledName, D); + if (!GetGlobalValue(MangledName)) { DeferredDecls[MangledName] = D; return; } @@ -1133,12 +1128,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) { - // Remove the old entry from GlobalDeclMap so that we'll create a new one. - GlobalDeclMap.erase(getMangledName(D)); + // Move the old entry aside so that we'll create a new one. + Entry->setName(llvm::StringRef()); // Make a new global with the correct type, this is now guaranteed to work. GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalVar(D, InitType)); - GV->takeName(cast<llvm::GlobalValue>(Entry)); // Replace all uses of the old global with the new global llvm::Constant *NewPtrForOldDecl = @@ -1296,11 +1290,10 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // // This happens if there is a prototype for a function // (e.g. "int f()") and then a definition of a different type - // (e.g. "int f(int x)"). Start by making a new function of the - // correct type, RAUW, then steal the name. - GlobalDeclMap.erase(getMangledName(D)); + // (e.g. "int f(int x)"). Move the old function aside so that it + // doesn't interfere with GetAddrOfFunction. + OldFn->setName(llvm::StringRef()); llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty)); - NewFn->takeName(OldFn); // If this is an implementation of a function without a prototype, try to // replace any existing uses of the function (which may be calls) with uses @@ -1336,23 +1329,29 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { AddGlobalDtor(Fn, DA->getPriority()); } -void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { +void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { + const ValueDecl *D = cast<ValueDecl>(GD.getDecl()); const AliasAttr *AA = D->getAttr<AliasAttr>(); assert(AA && "Not an alias?"); - const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + MangleBuffer MangledName; + getMangledName(MangledName, GD); - // Unique the name through the identifier table. - const char *AliaseeName = - getContext().Idents.get(AA->getAliasee()).getNameStart(); + // If there is a definition in the module, then it wins over the alias. + // This is dubious, but allow it to be safe. Just ignore the alias. + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (Entry && !Entry->isDeclaration()) + return; + + const llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. llvm::Constant *Aliasee; if (isa<llvm::FunctionType>(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AliaseeName, DeclTy, GlobalDecl()); + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl()); else - Aliasee = GetOrCreateLLVMGlobal(AliaseeName, + Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); // Create the new alias itself, but don't set a name yet. @@ -1361,18 +1360,9 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { llvm::Function::ExternalLinkage, "", Aliasee, &getModule()); - // See if there is already something with the alias' name in the module. - const char *MangledName = getMangledName(D); - llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName]; - - if (Entry && !Entry->isDeclaration()) { - // If there is a definition in the module, then it wins over the alias. - // This is dubious, but allow it to be safe. Just ignore the alias. - GA->eraseFromParent(); - return; - } - if (Entry) { + assert(Entry->isDeclaration()); + // If there is a declaration in the module, then we had an extern followed // by the alias, as in: // extern int test6(); @@ -1380,16 +1370,15 @@ void CodeGenModule::EmitAliasDefinition(const ValueDecl *D) { // int test6() __attribute__((alias("test7"))); // // Remove it and replace uses of it with the alias. + GA->takeName(Entry); Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA, Entry->getType())); Entry->eraseFromParent(); + } else { + GA->setName(MangledName.getString()); } - // Now we know that there is no conflict, set the name. - Entry = GA; - GA->setName(MangledName); - // Set attributes which are particular to an alias; this is a // specialization of the attributes which may be set on a global // variable/function. @@ -1426,8 +1415,6 @@ llvm::Value *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD, const llvm::FunctionType *Ty = cast<llvm::FunctionType>(getTypes().ConvertType(FD->getType())); - // Unique the name through the identifier table. - Name = getContext().Idents.get(Name).getNameStart(); return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl(FD)); } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 9077ade..febb856 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -73,7 +73,7 @@ namespace CodeGen { class CodeGenFunction; class CGDebugInfo; class CGObjCRuntime; - + class MangleBuffer; /// CodeGenModule - This class organizes the cross-function state that is used /// while generating LLVM code. @@ -103,38 +103,16 @@ class CodeGenModule : public BlockModule { llvm::Function *MemMoveFn; llvm::Function *MemSetFn; - /// GlobalDeclMap - Mapping of decl names (represented as unique - /// character pointers from either the identifier table or the set - /// of mangled names) to global variables we have already - /// emitted. Note that the entries in this map are the actual - /// globals and therefore may not be of the same type as the decl, - /// they should be bitcasted on retrieval. Also note that the - /// globals are keyed on their source mangled name, not the global name - /// (which may change with attributes such as asm-labels). The key - /// to this map should be generated using getMangledName(). - /// - /// Note that this map always lines up exactly with the contents of the LLVM - /// IR symbol table, but this is quicker to query since it is doing uniqued - /// pointer lookups instead of full string lookups. - llvm::DenseMap<const char*, llvm::GlobalValue*> GlobalDeclMap; - // WeakRefReferences - A set of references that have only been seen via // a weakref so far. This is used to remove the weak of the reference if we ever // see a direct reference or a definition. llvm::SmallPtrSet<llvm::GlobalValue*, 10> WeakRefReferences; - /// \brief Contains the strings used for mangled names. - /// - /// FIXME: Eventually, this should map from the semantic/canonical - /// declaration for each global entity to its mangled name (if it - /// has one). - llvm::StringSet<> MangledNames; - /// DeferredDecls - This contains all the decls which have definitions but /// which are deferred for emission and therefore should only be output if /// they are actually used. If a decl is in this, then it is known to have - /// not been referenced yet. The key to this map is a uniqued mangled name. - llvm::DenseMap<const char*, GlobalDecl> DeferredDecls; + /// not been referenced yet. + llvm::StringMap<GlobalDecl> DeferredDecls; /// DeferredDeclsToEmit - This is a list of deferred decls which we have seen /// that *are* actually referenced. These get code generated when the module @@ -160,10 +138,14 @@ class CodeGenModule : public BlockModule { llvm::StringMap<llvm::Constant*> CFConstantStringMap; llvm::StringMap<llvm::Constant*> ConstantStringMap; - /// CXXGlobalInits - Variables with global initializers that need to run + /// CXXGlobalInits - Global variables with initializers that need to run /// before main. std::vector<llvm::Constant*> CXXGlobalInits; + /// CXXGlobalDtors - Global destructor functions and arguments that need to + /// run on termination. + std::vector<std::pair<llvm::Constant*,llvm::Constant*> > CXXGlobalDtors; + /// CFConstantStringClassRef - Cached reference to the class for constant /// strings. This value has type int * but is actually an Obj-C class pointer. llvm::Constant *CFConstantStringClassRef; @@ -343,14 +325,18 @@ public: void AddAnnotation(llvm::Constant *C) { Annotations.push_back(C); } + /// AddCXXDtorEntry - Add a destructor and object to add to the C++ global + /// destructor function. + void AddCXXDtorEntry(llvm::Constant *DtorFn, llvm::Constant *Object); + /// CreateRuntimeFunction - Create a new runtime function with the specified /// type and name. llvm::Constant *CreateRuntimeFunction(const llvm::FunctionType *Ty, - const char *Name); + llvm::StringRef Name); /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty, - const char *Name); + llvm::StringRef Name); void UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. @@ -422,13 +408,14 @@ public: AttributeListType &PAL, unsigned &CallingConv); - const char *getMangledName(const GlobalDecl &D); - - const char *getMangledName(const NamedDecl *ND); - const char *getMangledCXXCtorName(const CXXConstructorDecl *D, - CXXCtorType Type); - const char *getMangledCXXDtorName(const CXXDestructorDecl *D, - CXXDtorType Type); + void getMangledName(MangleBuffer &Buffer, GlobalDecl D); + void getMangledName(MangleBuffer &Buffer, const NamedDecl *ND); + void getMangledCXXCtorName(MangleBuffer &Buffer, + const CXXConstructorDecl *D, + CXXCtorType Type); + void getMangledCXXDtorName(MangleBuffer &Buffer, + const CXXDestructorDecl *D, + CXXDtorType Type); void EmitTentativeDefinition(const VarDecl *D); @@ -456,14 +443,12 @@ public: std::vector<const CXXRecordDecl*> DeferredVtables; private: - /// UniqueMangledName - Unique a name by (if necessary) inserting it into the - /// MangledNames string map. - const char *UniqueMangledName(const char *NameStart, const char *NameEnd); + llvm::GlobalValue *GetGlobalValue(llvm::StringRef Ref); - llvm::Constant *GetOrCreateLLVMFunction(const char *MangledName, + llvm::Constant *GetOrCreateLLVMFunction(llvm::StringRef MangledName, const llvm::Type *Ty, GlobalDecl D); - llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName, + llvm::Constant *GetOrCreateLLVMGlobal(llvm::StringRef MangledName, const llvm::PointerType *PTy, const VarDecl *D); @@ -492,7 +477,7 @@ private: void EmitGlobalFunctionDefinition(GlobalDecl GD); void EmitGlobalVarDefinition(const VarDecl *D); - void EmitAliasDefinition(const ValueDecl *D); + void EmitAliasDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); // C++ related functions. @@ -519,9 +504,12 @@ private: /// a C++ destructor Decl. void EmitCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); - /// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals. + /// EmitCXXGlobalInitFunc - Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); + /// EmitCXXGlobalDtorFunc - Emit the function that destroys C++ globals. + void EmitCXXGlobalDtorFunc(); + void EmitCXXGlobalVarDeclInitFunc(const VarDecl *D); // FIXME: Hardcoding priority here is gross. diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 32555ab..f2a73f1 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -469,8 +469,26 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { mangleName(Qualifier->getAsNamespace()); break; case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - mangleType(QualType(Qualifier->getAsType(), 0)); + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *QTy = Qualifier->getAsType(); + + if (const TemplateSpecializationType *TST = + dyn_cast<TemplateSpecializationType>(QTy)) { + if (!mangleSubstitution(QualType(TST, 0))) { + TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); + assert(TD && "FIXME: Support dependent template names"); + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TST->getArgs(), + TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } else { + // We use the QualType mangle type variant here because it handles + // substitutions. + mangleType(QualType(QTy, 0)); + } + } break; case NestedNameSpecifier::Identifier: // Member expressions can have these without prefixes. @@ -1144,29 +1162,8 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { void CXXNameMangler::mangleType(const TypenameType *T) { // Typename types are always nested Out << 'N'; - - const Type *QTy = T->getQualifier()->getAsType(); - if (const TemplateSpecializationType *TST = - dyn_cast<TemplateSpecializationType>(QTy)) { - if (!mangleSubstitution(QualType(TST, 0))) { - TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); - assert(TD && "FIXME: Support dependent template names"); - mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TST->getArgs(), - TST->getNumArgs()); - addSubstitution(QualType(TST, 0)); - } - } else if (const TemplateTypeParmType *TTPT = - dyn_cast<TemplateTypeParmType>(QTy)) { - // We use the QualType mangle type variant here because it handles - // substitutions. - mangleType(QualType(TTPT, 0)); - } else - assert(false && "Unhandled type!"); - + mangleUnresolvedScope(T->getQualifier()); mangleSourceName(T->getIdentifier()); - Out << 'E'; } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 97f94b6..62656b9 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -21,10 +21,8 @@ #include "CGCXX.h" #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" - -namespace llvm { - template<typename T> class SmallVectorImpl; -} +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" namespace clang { class ASTContext; @@ -37,6 +35,33 @@ namespace clang { namespace CodeGen { class CovariantThunkAdjustment; class ThunkAdjustment; + +/// MangleBuffer - a convenient class for storing a name which is +/// either the result of a mangling or is a constant string with +/// external memory ownership. +class MangleBuffer { +public: + void setString(llvm::StringRef Ref) { + String = Ref; + } + + llvm::SmallVectorImpl<char> &getBuffer() { + return Buffer; + } + + llvm::StringRef getString() const { + if (!String.empty()) return String; + return Buffer.str(); + } + + operator llvm::StringRef() const { + return getString(); + } + +private: + llvm::StringRef String; + llvm::SmallString<256> Buffer; +}; /// MangleContext - Context for tracking state which persists across multiple /// calls to the C++ name mangler. diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp index a09ba09..7e61a1d 100644 --- a/lib/Driver/Arg.cpp +++ b/lib/Driver/Arg.cpp @@ -10,6 +10,7 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/raw_ostream.h" using namespace clang::driver; @@ -155,14 +156,12 @@ SeparateArg::SeparateArg(const Option *Opt, unsigned Index, unsigned _NumValues, void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const { if (getOption().hasForceJoinedRender()) { assert(getNumValues() == 1 && "Cannot force joined render with > 1 args."); - // FIXME: Avoid std::string. - std::string Joined(getOption().getName()); - Joined += Args.getArgString(getIndex()); - Output.push_back(Args.MakeArgString(Joined.c_str())); + Output.push_back(Args.MakeArgString(llvm::StringRef(getOption().getName()) + + getValue(Args, 0))); } else { Output.push_back(Args.getArgString(getIndex())); for (unsigned i = 0; i < NumValues; ++i) - Output.push_back(Args.getArgString(getIndex() + 1 + i)); + Output.push_back(getValue(Args, i)); } } diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index b819cda..227f79a 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -61,10 +61,21 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, OS << " \"" << C->getExecutable() << '"'; for (ArgStringList::const_iterator it = C->getArguments().begin(), ie = C->getArguments().end(); it != ie; ++it) { - if (Quote) - OS << " \"" << *it << '"'; - else - OS << ' ' << *it; + OS << ' '; + if (!Quote) { + OS << *it; + continue; + } + + // Quote the argument and escape shell special characters; this isn't + // really complete but is good enough. + OS << '"'; + for (const char *s = *it; *s; ++s) { + if (*s == '"' || *s == '\\' || *s == '$') + OS << '\\'; + OS << *s; + } + OS << '"'; } OS << Terminator; } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) { @@ -123,8 +134,34 @@ int Compilation::ExecuteCommand(const Command &C, std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); Argv[C.getArguments().size() + 1] = 0; - if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v)) - PrintJob(llvm::errs(), C, "\n", false); + if (getDriver().CCCEcho || getDriver().CCPrintOptions || + getArgs().hasArg(options::OPT_v)) { + llvm::raw_ostream *OS = &llvm::errs(); + + // Follow gcc implementation of CC_PRINT_OPTIONS; we could also cache the + // output stream. + if (getDriver().CCPrintOptions && getDriver().CCPrintOptionsFilename) { + std::string Error; + OS = new llvm::raw_fd_ostream(getDriver().CCPrintOptionsFilename, + Error, + llvm::raw_fd_ostream::F_Append); + if (!Error.empty()) { + getDriver().Diag(clang::diag::err_drv_cc_print_options_failure) + << Error; + FailingCommand = &C; + delete OS; + return 1; + } + } + + if (getDriver().CCPrintOptions) + *OS << "[Logging clang options]"; + + PrintJob(*OS, C, "\n", /*Quote=*/getDriver().CCPrintOptions); + + if (OS != &llvm::errs()) + delete OS; + } std::string Error; int Res = diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 3257ee5..acfff38 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -51,10 +51,10 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, DefaultImageName(_DefaultImageName), DriverTitle("clang \"gcc-compatible\" driver"), Host(0), - CCCGenericGCCName("gcc"), CCCIsCXX(false), CCCEcho(false), - CCCPrintBindings(false), CheckInputsExist(true), CCCUseClang(true), - CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), - SuppressMissingInputWarning(false) { + CCCGenericGCCName("gcc"), CCPrintOptionsFilename(0), CCCIsCXX(false), + CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false), + CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true), + CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { if (IsProduction) { // In a "production" build, only use clang on architectures we expect to // work, and don't use clang C++. diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index f69d5d8..de1e459 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -167,11 +167,13 @@ Option *OptTable::CreateOption(unsigned id) const { if (info.Flags & RenderAsInput) Opt->setNoOptAsInput(true); if (info.Flags & RenderJoined) { - assert(info.Kind == Option::SeparateClass && "Invalid option."); + assert((info.Kind == Option::JoinedOrSeparateClass || + info.Kind == Option::SeparateClass) && "Invalid option."); Opt->setForceJoinedRender(true); } if (info.Flags & RenderSeparate) { - assert(info.Kind == Option::JoinedClass && "Invalid option."); + assert((info.Kind == Option::JoinedOrSeparateClass || + info.Kind == Option::JoinedClass) && "Invalid option."); Opt->setForceSeparateRender(true); } if (info.Flags & Unsupported) diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 2f8d714..105eab0 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -394,9 +394,9 @@ DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, // this. Perhaps put under -pedantic? if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) - OSXVersion = 0; + OSXTarget = 0; else - iPhoneVersion = 0; + iPhoneOSTarget = 0; } if (OSXTarget) { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 6dd64de..0d5b2a3 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -96,6 +96,8 @@ public: return TargetIsIPhoneOS; } + bool isTargetInitialized() const { return TargetInitialized; } + void getTargetVersion(unsigned (&Res)[3]) const { assert(TargetInitialized && "Target not initialized!"); Res[0] = TargetVersion[0]; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index bc52100..1c34df0 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -655,6 +655,12 @@ static std::string getEffectiveClangTriple(const Driver &D, } else { const toolchains::Darwin &DarwinTC( reinterpret_cast<const toolchains::Darwin&>(TC)); + + // If the target isn't initialized (e.g., an unknown Darwin platform, return + // the default triple). + if (!DarwinTC.isTargetInitialized()) + return Triple.getTriple(); + unsigned Version[3]; DarwinTC.getTargetVersion(Version); @@ -686,6 +692,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + bool KernelOrKext = Args.hasArg(options::OPT_mkernel, + options::OPT_fapple_kext); const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; @@ -870,7 +878,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.hasFlag(options::OPT_fasynchronous_unwind_tables, options::OPT_fno_asynchronous_unwind_tables, getToolChain().IsUnwindTablesDefault() && - !Args.hasArg(options::OPT_mkernel)); + !KernelOrKext); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); @@ -1029,12 +1037,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + // -fhosted is default. + if (KernelOrKext || Args.hasFlag(options::OPT_ffreestanding, + options::OPT_fhosted, + false)) + CmdArgs.push_back("-ffreestanding"); + // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); - Args.AddLastArg(CmdArgs, options::OPT_ffreestanding); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions); + + // -flax-vector-conversions is default. + if (!Args.hasFlag(options::OPT_flax_vector_conversions, + options::OPT_fno_lax_vector_conversions)) + CmdArgs.push_back("-fno-lax-vector-conversions"); + Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics); Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only); @@ -1080,6 +1098,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks"); } + // -fno-access-control is default (for now). + if (Args.hasFlag(options::OPT_faccess_control, + options::OPT_fno_access_control, + false)) + CmdArgs.push_back("-faccess-control"); + // -fexceptions=0 is default. if (needsExceptions(Args, InputType, getToolChain().getTriple())) CmdArgs.push_back("-fexceptions"); @@ -1088,7 +1112,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fsjlj-exceptions"); // -frtti is default. - if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) + if (KernelOrKext || + !Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) CmdArgs.push_back("-fno-rtti"); // -fsigned-char is default. @@ -1101,6 +1126,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_threadsafe_statics)) CmdArgs.push_back("-fno-threadsafe-statics"); + // -fuse-cxa-atexit is default. + if (KernelOrKext || !Args.hasFlag(options::OPT_fuse_cxa_atexit, + options::OPT_fno_use_cxa_atexit)) + CmdArgs.push_back("-fno-use-cxa-atexit"); + // -fms-extensions=0 is default. if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 3bf1fab..935c415 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -83,7 +83,7 @@ public: return false; } - virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI) { + virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) { HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); } @@ -293,8 +293,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { - Clang.takeSourceManager(); - Clang.takeFileManager(); Clang.takeDiagnosticClient(); Clang.takeDiagnostics(); return 0; diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index 02d6cec..d069e8f 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -164,11 +164,12 @@ public: } // end anonymous namespace typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap; -typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap; -typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy; namespace { class PTHWriter { + typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap; + typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy; + IDMap IM; llvm::raw_fd_ostream& Out; Preprocessor& PP; @@ -272,7 +273,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { // Pad 0's so that we emit tokens to a 4-byte alignment. // This speed up reading them back in. Pad(Out, 4); - Offset off = (Offset) Out.tell(); + Offset TokenOff = (Offset) Out.tell(); // Keep track of matching '#if' ... '#endif'. typedef std::vector<std::pair<Offset, unsigned> > PPCondTable; @@ -418,7 +419,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { Emit32(PPCond.size()); for (unsigned i = 0, e = PPCond.size(); i!=e; ++i) { - Emit32(PPCond[i].first - off); + Emit32(PPCond[i].first - TokenOff); uint32_t x = PPCond[i].second; assert(x != 0 && "PPCond entry not backpatched."); // Emit zero for #endifs. This allows us to do checking when @@ -426,7 +427,7 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { Emit32(x == i ? 0 : x); } - return PTHEntry(off, PPCondOff); + return PTHEntry(TokenOff, PPCondOff); } Offset PTHWriter::EmitCachedSpellings() { @@ -452,7 +453,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) { // Write the name of the MainFile. if (!MainFile.empty()) { - EmitString(MainFile); + EmitString(MainFile); } else { // String with 0 bytes. Emit16(0); @@ -549,7 +550,8 @@ void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { // Lex through the entire file. This will populate SourceManager with // all of the header information. Token Tok; - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 3bc5661..7b4932d 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -107,15 +107,13 @@ void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel, static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, unsigned argc, char **argv, - llvm::OwningPtr<DiagnosticClient> &DiagClient) { + Diagnostic &Diags) { std::string ErrorInfo; - llvm::raw_ostream *OS = - new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); + llvm::OwningPtr<llvm::raw_ostream> OS( + new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); if (!ErrorInfo.empty()) { - // FIXME: Do not fail like this. - llvm::errs() << "error opening -dump-build-information file '" - << DiagOpts.DumpBuildInformation << "', option ignored!\n"; - delete OS; + Diags.Report(diag::err_fe_unable_to_open_logfile) + << DiagOpts.DumpBuildInformation << ErrorInfo; return; } @@ -126,8 +124,8 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, // Chain in a diagnostic client which will log the diagnostics. DiagnosticClient *Logger = - new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); - DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); + new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); + Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger)); } void CompilerInstance::createDiagnostics(int Argc, char **Argv) { @@ -165,13 +163,12 @@ Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, if (Opts.VerifyDiagnostics) DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); + Diags->setClient(DiagClient.take()); if (!Opts.DumpBuildInformation.empty()) - SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); + SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); // Configure our handling of diagnostics. - Diags->setClient(DiagClient.take()); - if (ProcessWarningOptions(*Diags, Opts)) - return 0; + ProcessWarningOptions(*Diags, Opts); return Diags.take(); } @@ -227,6 +224,9 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, PP->setPTHManager(PTHMgr); } + if (PPOpts.DetailedRecord) + PP->createPreprocessingRecord(); + InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts); // Handle generating dependencies, if requested. @@ -429,12 +429,7 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, SourceManager &SourceMgr, const FrontendOptions &Opts) { // Figure out where to get and map in the main file. - if (Opts.EmptyInputOnly) { - const char *EmptyStr = ""; - llvm::MemoryBuffer *SB = - llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); - SourceMgr.createMainFileIDForMemBuffer(SB); - } else if (InputFile != "-") { + if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (File) SourceMgr.createMainFileID(File, SourceLocation()); if (SourceMgr.getMainFileID().isInvalid()) { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 5798f2f..6e18f34 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -154,6 +154,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mcode-model"); Res.push_back(Opts.CodeModel); } + if (!Opts.CXAAtExit) + Res.push_back("-fno-use-cxa-atexit"); + if (Opts.CXXCtorDtorAliases) + Res.push_back("-mconstructor-aliases"); if (!Opts.DebugPass.empty()) { Res.push_back("-mdebug-pass"); Res.push_back(Opts.DebugPass); @@ -180,8 +184,6 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mrelocation-model"); Res.push_back(Opts.RelocationModel); } - if (Opts.CXXCtorDtorAliases) - Res.push_back("-mconstructor-aliases"); if (!Opts.VerifyModule) Res.push_back("-disable-llvm-verifier"); } @@ -288,6 +290,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::FixIt: return "-fixit"; case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; + case frontend::InitOnly: return "-init-only"; case frontend::ParseNoop: return "-parse-noop"; case frontend::ParsePrintCallbacks: return "-parse-print-callbacks"; case frontend::ParseSyntaxOnly: return "-fsyntax-only"; @@ -310,8 +313,6 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-no-code-completion-debug-printer"); if (Opts.DisableFree) Res.push_back("-disable-free"); - if (Opts.EmptyInputOnly) - Res.push_back("-empty-input-only"); if (Opts.RelocatablePCH) Res.push_back("-relocatable-pch"); if (Opts.ShowHelp) @@ -575,6 +576,8 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, } if (!Opts.UsePredefines) Res.push_back("-undef"); + if (Opts.DetailedRecord) + Res.push_back("-detailed-preprocessing-record"); if (!Opts.ImplicitPCHInclude.empty()) { Res.push_back("-include-pch"); Res.push_back(Opts.ImplicitPCHInclude); @@ -783,6 +786,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); + Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); + Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.CodeModel = getLastArgValue(Args, OPT_mcode_model); Opts.DebugPass = getLastArgValue(Args, OPT_mdebug_pass); Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); @@ -793,7 +798,6 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); - Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); @@ -876,6 +880,8 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.ProgramAction = frontend::GeneratePCH; break; case OPT_emit_pth: Opts.ProgramAction = frontend::GeneratePTH; break; + case OPT_init_only: + Opts.ProgramAction = frontend::InitOnly; break; case OPT_parse_noop: Opts.ProgramAction = frontend::ParseNoop; break; case OPT_parse_print_callbacks: @@ -913,7 +919,6 @@ ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Diagnostic &Diags) { Opts.DebugCodeCompletionPrinter = !Args.hasArg(OPT_no_code_completion_debug_printer); Opts.DisableFree = Args.hasArg(OPT_disable_free); - Opts.EmptyInputOnly = Args.hasArg(OPT_empty_input_only); Opts.FixItLocations.clear(); for (arg_iterator it = Args.filtered_begin(OPT_fixit_at), @@ -1232,7 +1237,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, else Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); - + Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); // Add macros from the command line. for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 1e210b4..251b8e4 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -23,6 +23,18 @@ using namespace clang; //===----------------------------------------------------------------------===// +// Custom Actions +//===----------------------------------------------------------------------===// + +ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + return new ASTConsumer(); +} + +void InitOnlyAction::ExecuteAction() { +} + +//===----------------------------------------------------------------------===// // AST Consumer Actions //===----------------------------------------------------------------------===// @@ -185,7 +197,8 @@ void DumpTokensAction::ExecuteAction() { Preprocessor &PP = getCompilerInstance().getPreprocessor(); // Start preprocessing the specified input file. Token Tok; - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; do { PP.Lex(Tok); PP.DumpToken(Tok, true); @@ -213,7 +226,8 @@ void ParseOnlyAction::ExecuteAction() { llvm::OwningPtr<Action> PA(new MinimalAction(PP)); Parser P(PP, *PA); - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; P.ParseTranslationUnit(); } @@ -222,7 +236,8 @@ void PreprocessOnlyAction::ExecuteAction() { Token Tok; // Start parsing the specified input file. - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); @@ -237,7 +252,8 @@ void PrintParseAction::ExecuteAction() { llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); Parser P(PP, *PA); - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; P.ParseTranslationUnit(); } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 49eb2a0..e659ff0 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/OnDiskHashTable.h" @@ -150,7 +151,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, std::pair<llvm::StringRef,llvm::StringRef> Split = llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); llvm::StringRef Left = Split.first, Right = Split.second; - assert(Left != PP.getPredefines() && "Missing PCH include entry!"); + if (Left == PP.getPredefines()) { + Error("Missing PCH include entry!"); + return true; + } // If the predefines is equal to the joined left and right halves, we're done! if (Left.size() + Right.size() == PCHPredef.size() && @@ -300,8 +304,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, return false; } -void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI) { - PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++); +void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, + unsigned ID) { + PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); + ++NumHeaderInfos; } void PCHValidator::ReadCounter(unsigned Value) { @@ -321,8 +327,9 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot), - NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), NumStatementsRead(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), @@ -338,8 +345,9 @@ PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, IdentifierOffsets(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), Comments(0), NumComments(0), isysroot(isysroot), - NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), MacroDefinitionOffsets(0), + NumPreallocatedPreprocessingEntities(0), + isysroot(isysroot), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), NumStatementsRead(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), @@ -601,10 +609,8 @@ public: typedef OnDiskChainedHashTable<PCHIdentifierLookupTrait> PCHIdentifierLookupTable; -bool PCHReader::Error(const char *Msg) { - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg); - Diag(DiagID); - return true; +void PCHReader::Error(const char *Msg) { + Diag(diag::err_fe_pch_malformed) << Msg; } /// \brief Check the contents of the predefines buffer against the @@ -850,17 +856,6 @@ PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { return Failure; break; - case pch::SM_HEADER_FILE_INFO: { - HeaderFileInfo HFI; - HFI.isImport = Record[0]; - HFI.DirInfo = Record[1]; - HFI.NumIncludes = Record[2]; - HFI.ControllingMacroID = Record[3]; - if (Listener) - Listener->ReadHeaderFileInfo(HFI); - break; - } - case pch::SM_SLOC_FILE_ENTRY: case pch::SM_SLOC_BUFFER_ENTRY: case pch::SM_SLOC_INSTANTIATION_ENTRY: @@ -910,6 +905,11 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } + if (Record.size() < 8) { + Error("source location entry is incorrect"); + return Failure; + } + FileID FID = SourceMgr.createFileID(File, SourceLocation::getFromRawEncoding(Record[1]), (SrcMgr::CharacteristicKind)Record[2], @@ -918,6 +918,14 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()) .setHasLineDirectives(); + // Reconstruct header-search information for this file. + HeaderFileInfo HFI; + HFI.isImport = Record[4]; + HFI.DirInfo = Record[5]; + HFI.NumIncludes = Record[6]; + HFI.ControllingMacroID = Record[7]; + if (Listener) + Listener->ReadHeaderFileInfo(HFI, File->getUID()); break; } @@ -928,8 +936,12 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { Record.clear(); unsigned RecCode = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); - assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file"); - (void)RecCode; + + if (RecCode != pch::SM_SLOC_BUFFER_BLOB) { + Error("PCH record has invalid code"); + return Failure; + } + llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(BlobStart, BlobStart + BlobLen - 1, @@ -1038,12 +1050,14 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { MacroInfo *MI = PP->AllocateMacroInfo(Loc); MI->setIsUsed(isUsed); + unsigned NextIndex = 3; if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[3]; bool isGNUVarArgs = Record[4]; MacroArgs.clear(); unsigned NumArgs = Record[5]; + NextIndex = 6 + NumArgs; for (unsigned i = 0; i != NumArgs; ++i) MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i])); @@ -1061,6 +1075,13 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { // Remember that we saw this macro last so that we add the tokens that // form its body to it. Macro = MI; + + if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) { + // We have a macro definition. Load it now. + PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro, + getMacroDefinition(Record[NextIndex])); + } + ++NumMacrosRead; break; } @@ -1081,6 +1102,64 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) { Macro->AddTokenToBody(Tok); break; } + + case pch::PP_MACRO_INSTANTIATION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + MacroInstantiation *MI + = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[1]), + SourceLocation::getFromRawEncoding(Record[2])), + getMacroDefinition(Record[4])); + PPRec.SetPreallocatedEntity(Record[0], MI); + return; + } + + case pch::PP_MACRO_DEFINITION: { + // If we already have a macro, that means that we've hit the end + // of the definition of the macro we were looking for. We're + // done. + if (Macro) + return; + + if (!PP->getPreprocessingRecord()) { + Error("missing preprocessing record in PCH file"); + return; + } + + PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); + if (PPRec.getPreprocessedEntity(Record[0])) + return; + + if (Record[1] >= MacroDefinitionsLoaded.size()) { + Error("out-of-bounds macro definition record"); + return; + } + + MacroDefinition *MD + = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]), + SourceLocation::getFromRawEncoding(Record[5]), + SourceRange( + SourceLocation::getFromRawEncoding(Record[2]), + SourceLocation::getFromRawEncoding(Record[3]))); + PPRec.SetPreallocatedEntity(Record[0], MD); + MacroDefinitionsLoaded[Record[1]] = MD; + return; + } } } } @@ -1130,16 +1209,32 @@ void PCHReader::ReadDefinedMacros() { case pch::PP_MACRO_OBJECT_LIKE: case pch::PP_MACRO_FUNCTION_LIKE: - DecodeIdentifierInfo(Record[0]); + DecodeIdentifierInfo(Record[0]); break; case pch::PP_TOKEN: // Ignore tokens. break; + + case pch::PP_MACRO_INSTANTIATION: + case pch::PP_MACRO_DEFINITION: + // Read the macro record. + ReadMacroRecord(Cursor.GetCurrentBitNo()); + break; } } } +MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) { + if (ID == 0 || ID >= MacroDefinitionsLoaded.size()) + return 0; + + if (!MacroDefinitionsLoaded[ID]) + ReadMacroRecord(MacroDefinitionOffsets[ID]); + + return MacroDefinitionsLoaded[ID]; +} + /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. @@ -1408,11 +1503,6 @@ PCHReader::ReadPCHBlock() { MaybeAddSystemRootToFilename(OriginalFileName); break; - case pch::COMMENT_RANGES: - Comments = (SourceRange *)BlobStart; - NumComments = BlobLen / sizeof(SourceRange); - break; - case pch::VERSION_CONTROL_BRANCH_REVISION: { const std::string &CurBranch = getClangFullRepositoryVersion(); llvm::StringRef PCHBranch(BlobStart, BlobLen); @@ -1422,6 +1512,19 @@ PCHReader::ReadPCHBlock() { } break; } + + case pch::MACRO_DEFINITION_OFFSETS: + MacroDefinitionOffsets = (const uint32_t *)BlobStart; + if (PP) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]); + } else { + NumPreallocatedPreprocessingEntities = Record[0]; + } + + MacroDefinitionsLoaded.resize(Record[1]); + break; } } Error("premature end of bitstream in PCH file"); @@ -1553,6 +1656,18 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { return Success; } +void PCHReader::setPreprocessor(Preprocessor &pp) { + PP = &pp; + + if (NumPreallocatedPreprocessingEntities) { + if (!PP->getPreprocessingRecord()) + PP->createPreprocessingRecord(); + PP->getPreprocessingRecord()->SetExternalSource(*this, + NumPreallocatedPreprocessingEntities); + NumPreallocatedPreprocessingEntities = 0; + } +} + void PCHReader::InitializeContext(ASTContext &Ctx) { Context = &Ctx; assert(Context && "Passed null context!"); @@ -1584,29 +1699,44 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { Context->setObjCFastEnumerationStateType(GetType(FastEnum)); if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) { QualType FileType = GetType(File); - assert(!FileType.isNull() && "FILE type is NULL"); + if (FileType.isNull()) { + Error("FILE type is NULL"); + return; + } if (const TypedefType *Typedef = FileType->getAs<TypedefType>()) Context->setFILEDecl(Typedef->getDecl()); else { const TagType *Tag = FileType->getAs<TagType>(); - assert(Tag && "Invalid FILE type in PCH file"); + if (!Tag) { + Error("Invalid FILE type in PCH file"); + return; + } Context->setFILEDecl(Tag->getDecl()); } } if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) { QualType Jmp_bufType = GetType(Jmp_buf); - assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL"); + if (Jmp_bufType.isNull()) { + Error("jmp_bug type is NULL"); + return; + } if (const TypedefType *Typedef = Jmp_bufType->getAs<TypedefType>()) Context->setjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Jmp_bufType->getAs<TagType>(); - assert(Tag && "Invalid jmp_bug type in PCH file"); + if (!Tag) { + Error("Invalid jmp_bug type in PCH file"); + return; + } Context->setjmp_bufDecl(Tag->getDecl()); } } if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) { QualType Sigjmp_bufType = GetType(Sigjmp_buf); - assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL"); + if (Sigjmp_bufType.isNull()) { + Error("sigjmp_buf type is NULL"); + return; + } if (const TypedefType *Typedef = Sigjmp_bufType->getAs<TypedefType>()) Context->setsigjmp_bufDecl(Typedef->getDecl()); else { @@ -1799,10 +1929,8 @@ bool PCHReader::ParseLanguageOptions( return false; } -void PCHReader::ReadComments(std::vector<SourceRange> &Comments) { - Comments.resize(NumComments); - std::copy(this->Comments, this->Comments + NumComments, - Comments.begin()); +void PCHReader::ReadPreprocessedEntities() { + ReadDefinedMacros(); } /// \brief Read and return the type at the given offset. @@ -1823,45 +1951,65 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { unsigned Code = DeclsCursor.ReadCode(); switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { case pch::TYPE_EXT_QUAL: { - assert(Record.size() == 2 && - "Incorrect encoding of extended qualifier type"); + if (Record.size() != 2) { + Error("Incorrect encoding of extended qualifier type"); + return QualType(); + } QualType Base = GetType(Record[0]); Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); return Context->getQualifiedType(Base, Quals); } case pch::TYPE_COMPLEX: { - assert(Record.size() == 1 && "Incorrect encoding of complex type"); + if (Record.size() != 1) { + Error("Incorrect encoding of complex type"); + return QualType(); + } QualType ElemType = GetType(Record[0]); return Context->getComplexType(ElemType); } case pch::TYPE_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getPointerType(PointeeType); } case pch::TYPE_BLOCK_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of block pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of block pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getBlockPointerType(PointeeType); } case pch::TYPE_LVALUE_REFERENCE: { - assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type"); + if (Record.size() != 1) { + Error("Incorrect encoding of lvalue reference type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getLValueReferenceType(PointeeType); } case pch::TYPE_RVALUE_REFERENCE: { - assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type"); + if (Record.size() != 1) { + Error("Incorrect encoding of rvalue reference type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getRValueReferenceType(PointeeType); } case pch::TYPE_MEMBER_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of member pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of member pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); QualType ClassType = GetType(Record[1]); return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr()); @@ -1957,7 +2105,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { cast<UnresolvedUsingTypenameDecl>(GetDecl(Record[0]))); case pch::TYPE_TYPEDEF: - assert(Record.size() == 1 && "incorrect encoding of typedef type"); + if (Record.size() != 1) { + Error("incorrect encoding of typedef type"); + return QualType(); + } return Context->getTypeDeclType(cast<TypedefDecl>(GetDecl(Record[0]))); case pch::TYPE_TYPEOF_EXPR: @@ -1976,15 +2127,24 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getDecltypeType(ReadTypeExpr()); case pch::TYPE_RECORD: - assert(Record.size() == 1 && "incorrect encoding of record type"); + if (Record.size() != 1) { + Error("incorrect encoding of record type"); + return QualType(); + } return Context->getTypeDeclType(cast<RecordDecl>(GetDecl(Record[0]))); case pch::TYPE_ENUM: - assert(Record.size() == 1 && "incorrect encoding of enum type"); + if (Record.size() != 1) { + Error("incorrect encoding of enum type"); + return QualType(); + } return Context->getTypeDeclType(cast<EnumDecl>(GetDecl(Record[0]))); case pch::TYPE_ELABORATED: { - assert(Record.size() == 2 && "incorrect encoding of elaborated type"); + if (Record.size() != 2) { + Error("incorrect encoding of elaborated type"); + return QualType(); + } unsigned Tag = Record[1]; return Context->getElaboratedType(GetType(Record[0]), (ElaboratedType::TagKind) Tag); @@ -2329,8 +2489,12 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, llvm::SmallVectorImpl<pch::DeclID> &Decls) { assert(DC->hasExternalLexicalStorage() && "DeclContext has no lexical decls in storage"); + uint64_t Offset = DeclContextOffsets[DC].first; - assert(Offset && "DeclContext has no lexical decls in storage"); + if (Offset == 0) { + Error("DeclContext has no lexical decls in storage"); + return true; + } // Keep track of where we are in the stream, then jump back there // after reading this context. @@ -2342,8 +2506,10 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, RecordData Record; unsigned Code = DeclsCursor.ReadCode(); unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - (void)RecCode; - assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block"); + if (RecCode != pch::DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; + } // Load all of the declaration IDs Decls.clear(); @@ -2357,7 +2523,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, assert(DC->hasExternalVisibleStorage() && "DeclContext has no visible decls in storage"); uint64_t Offset = DeclContextOffsets[DC].second; - assert(Offset && "DeclContext has no visible decls in storage"); + if (Offset == 0) { + Error("DeclContext has no visible decls in storage"); + return true; + } // Keep track of where we are in the stream, then jump back there // after reading this context. @@ -2369,8 +2538,11 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, RecordData Record; unsigned Code = DeclsCursor.ReadCode(); unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - (void)RecCode; - assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block"); + if (RecCode != pch::DECL_CONTEXT_VISIBLE) { + Error("Expected visible block"); + return true; + } + if (Record.size() == 0) return false; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index c256b41..4752cd3 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -21,6 +21,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/FileManager.h" @@ -563,9 +564,10 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(SOURCE_LOCATION_PRELOADS); RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); - RECORD(COMMENT_RANGES); RECORD(VERSION_CONTROL_BRANCH_REVISION); - + RECORD(UNUSED_STATIC_FUNCS); + RECORD(MACRO_DEFINITION_OFFSETS); + // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); RECORD(SM_SLOC_FILE_ENTRY); @@ -573,14 +575,15 @@ void PCHWriter::WriteBlockInfoBlock() { RECORD(SM_SLOC_BUFFER_BLOB); RECORD(SM_SLOC_INSTANTIATION_ENTRY); RECORD(SM_LINE_TABLE); - RECORD(SM_HEADER_FILE_INFO); // Preprocessor Block. BLOCK(PREPROCESSOR_BLOCK); RECORD(PP_MACRO_OBJECT_LIKE); RECORD(PP_MACRO_FUNCTION_LIKE); RECORD(PP_TOKEN); - + RECORD(PP_MACRO_INSTANTIATION); + RECORD(PP_MACRO_DEFINITION); + // Decls and Types block. BLOCK(DECLTYPES_BLOCK); RECORD(TYPE_EXT_QUAL); @@ -918,6 +921,11 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives + // HeaderFileInfo fields. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name return Stream.EmitAbbrev(Abbrev); } @@ -1019,20 +1027,6 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Stream.EmitRecord(pch::SM_LINE_TABLE, Record); } - // Write out entries for all of the header files we know about. - HeaderSearch &HS = PP.getHeaderSearchInfo(); - Record.clear(); - for (HeaderSearch::header_file_iterator I = HS.header_file_begin(), - E = HS.header_file_end(); - I != E; ++I) { - Record.push_back(I->isImport); - Record.push_back(I->DirInfo); - Record.push_back(I->NumIncludes); - AddIdentifierRef(I->ControllingMacro, Record); - Stream.EmitRecord(pch::SM_HEADER_FILE_INFO, Record); - Record.clear(); - } - // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector<uint32_t> SLocEntryOffsets; @@ -1069,6 +1063,16 @@ void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // The source location entry is a file. The blob associated // with this entry is the file name. + // Emit header-search information associated with this file. + HeaderFileInfo HFI; + HeaderSearch &HS = PP.getHeaderSearchInfo(); + if (Content->Entry->getUID() < HS.header_file_size()) + HFI = HS.header_file_begin()[Content->Entry->getUID()]; + Record.push_back(HFI.isImport); + Record.push_back(HFI.DirInfo); + Record.push_back(HFI.NumIncludes); + AddIdentifierRef(HFI.ControllingMacro, Record); + // Turn the file name into an absolute path, if it isn't already. const char *Filename = Content->Entry->getName(); llvm::sys::Path FilePath(Filename, strlen(Filename)); @@ -1174,6 +1178,7 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { // Loop over all the macro definitions that are live at the end of the file, // emitting each to the PP section. + PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); I != E; ++I) { // FIXME: This emits macros in hash table order, we should do it in a stable @@ -1203,6 +1208,12 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { I != E; ++I) AddIdentifierRef(*I, Record); } + + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI))); + Stream.EmitRecord(Code, Record); Record.clear(); @@ -1230,25 +1241,68 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) { } ++NumMacros; } + + // If the preprocessor has a preprocessing record, emit it. + unsigned NumPreprocessingRecords = 0; + if (PPRec) { + for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end(); + E != EEnd; ++E) { + Record.clear(); + + if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { + Record.push_back(NumPreprocessingRecords++); + AddSourceLocation(MI->getSourceRange().getBegin(), Record); + AddSourceLocation(MI->getSourceRange().getEnd(), Record); + AddIdentifierRef(MI->getName(), Record); + Record.push_back(getMacroDefinitionID(MI->getDefinition())); + Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record); + continue; + } + + if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*E)) { + // Record this macro definition's location. + pch::IdentID ID = getMacroDefinitionID(MD); + if (ID != MacroDefinitionOffsets.size()) { + if (ID > MacroDefinitionOffsets.size()) + MacroDefinitionOffsets.resize(ID + 1); + + MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo(); + } else + MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); + + Record.push_back(NumPreprocessingRecords++); + Record.push_back(ID); + AddSourceLocation(MD->getSourceRange().getBegin(), Record); + AddSourceLocation(MD->getSourceRange().getEnd(), Record); + AddIdentifierRef(MD->getName(), Record); + AddSourceLocation(MD->getLocation(), Record); + Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record); + continue; + } + } + } + Stream.ExitBlock(); -} - -void PCHWriter::WriteComments(ASTContext &Context) { - using namespace llvm; - - if (Context.Comments.empty()) - return; - - BitCodeAbbrev *CommentAbbrev = new BitCodeAbbrev(); - CommentAbbrev->Add(BitCodeAbbrevOp(pch::COMMENT_RANGES)); - CommentAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned CommentCode = Stream.EmitAbbrev(CommentAbbrev); - - RecordData Record; - Record.push_back(pch::COMMENT_RANGES); - Stream.EmitRecordWithBlob(CommentCode, Record, - (const char*)&Context.Comments[0], - Context.Comments.size() * sizeof(SourceRange)); + + // Write the offsets table for the preprocessing record. + if (NumPreprocessingRecords > 0) { + // Write the offsets table for identifier IDs. + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + Record.clear(); + Record.push_back(pch::MACRO_DEFINITION_OFFSETS); + Record.push_back(NumPreprocessingRecords); + Record.push_back(MacroDefinitionOffsets.size()); + Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, + (const char *)&MacroDefinitionOffsets.front(), + MacroDefinitionOffsets.size() * sizeof(uint32_t)); + } } //===----------------------------------------------------------------------===// @@ -2009,13 +2063,12 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, // Write the remaining PCH contents. RecordData Record; - Stream.EnterSubblock(pch::PCH_BLOCK_ID, 4); + Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); WriteMetadata(Context, isysroot); WriteLanguageOptions(Context.getLangOptions()); if (StatCalls && !isysroot) WriteStatCache(*StatCalls, isysroot); WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - WriteComments(Context); // Write the record of special types. Record.clear(); @@ -2149,6 +2202,16 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } +pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) { + if (MD == 0) + return 0; + + pch::IdentID &ID = MacroDefinitions[MD]; + if (ID == 0) + ID = MacroDefinitions.size(); + return ID; +} + void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { if (SelRef.getAsOpaquePtr() == 0) { Record.push_back(0); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 44e0e13..02afd24 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -448,7 +448,8 @@ static int MacroIDCompare(const void* a, const void* b) { static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) { // -dM mode just scans and ignores all tokens in the files, then dumps out // the macro table at the end. - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; Token Tok; do PP.Lex(Tok); @@ -495,7 +496,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, PP.addPPCallbacks(Callbacks); // After we have configured the preprocessor, enter the main file. - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; // Consume all of the tokens that come from the predefines buffer. Those // should not be emitted into the output and are guaranteed to be at the diff --git a/lib/Frontend/RewriteMacros.cpp b/lib/Frontend/RewriteMacros.cpp index 954e8e2..4ffb297 100644 --- a/lib/Frontend/RewriteMacros.cpp +++ b/lib/Frontend/RewriteMacros.cpp @@ -101,7 +101,8 @@ void clang::RewriteMacrosInInput(Preprocessor &PP, llvm::raw_ostream *OS) { // Get the first preprocessing token. - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; Token PPTok; PP.Lex(PPTok); diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index 4bf507d..ea9635e 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -31,7 +31,7 @@ #include <algorithm> using namespace clang; -bool clang::ProcessWarningOptions(Diagnostic &Diags, +void clang::ProcessWarningOptions(Diagnostic &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); @@ -122,6 +122,4 @@ bool clang::ProcessWarningOptions(Diagnostic &Diags, if (Diags.setDiagnosticGroupMapping(OptStart, Mapping)) Diags.Report(diag::warn_unknown_warning_option) << ("-W" + Opt); } - - return false; } diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index fec0154..b09a627 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -33,7 +33,6 @@ typedef double __m128d __attribute__((__vector_size__(16))); typedef long long __m128i __attribute__((__vector_size__(16))); -typedef int __v4si __attribute__((__vector_size__(16))); typedef short __v8hi __attribute__((__vector_size__(16))); typedef char __v16qi __attribute__((__vector_size__(16))); diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h new file mode 100644 index 0000000..f24352b --- /dev/null +++ b/lib/Headers/nmmintrin.h @@ -0,0 +1,35 @@ +/*===---- nmmintrin.h - SSE intrinsics -------------------------------------=== +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +* +*===-----------------------------------------------------------------------=== +*/ + +#ifndef _NMMINTRIN_H +#define _NMMINTRIN_H + +#ifndef __SSE4_2__ +#error "SSE4.2 instruction set not enabled" +#else + +/* To match expectations of gcc we put the sse4.2 definitions into smmintrin.h, + just include it now then. */ +#include <smmintrin.h> +#endif /* __SSE4_2__ */ +#endif /* _NMMINTRIN_H */
\ No newline at end of file diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h index 972b2e0..9c8d53d 100644 --- a/lib/Headers/smmintrin.h +++ b/lib/Headers/smmintrin.h @@ -337,6 +337,118 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2) /* SSE4 Multiple Packed Sums of Absolute Difference. */ #define _mm_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw128((X), (Y), (M)) +/* These definitions are normally in nmmintrin.h, but gcc puts them in here + so we'll do the same. */ +#ifdef __SSE4_2__ + +/* These specify the type of data that we're comparing. */ +#define _SIDD_UBYTE_OPS 0x00 +#define _SIDD_UWORD_OPS 0x01 +#define _SIDD_SBYTE_OPS 0x02 +#define _SIDD_SWORD_OPS 0x03 + +/* These specify the type of comparison operation. */ +#define _SIDD_CMP_EQUAL_ANY 0x00 +#define _SIDD_CMP_RANGES 0x04 +#define _SIDD_CMP_EQUAL_EACH 0x08 +#define _SIDD_CMP_EQUAL_ORDERED 0x0c + +/* These macros specify the polarity of the operation. */ +#define _SIDD_POSITIVE_POLARITY 0x00 +#define _SIDD_NEGATIVE_POLARITY 0x10 +#define _SIDD_MASKED_POSITIVE_POLARITY 0x20 +#define _SIDD_MASKED_NEGATIVE_POLARITY 0x30 + +/* These macros are used in _mm_cmpXstri() to specify the return. */ +#define _SIDD_LEAST_SIGNIFICANT 0x00 +#define _SIDD_MOST_SIGNIFICANT 0x40 + +/* These macros are used in _mm_cmpXstri() to specify the return. */ +#define _SIDD_BIT_MASK 0x00 +#define _SIDD_UNIT_MASK 0x40 + +/* SSE4.2 Packed Comparison Intrinsics. */ +#define _mm_cmpistrm(A, B, M) __builtin_ia32_pcmpistrm128((A), (B), (M)) +#define _mm_cmpistri(A, B, M) __builtin_ia32_pcmpistri128((A), (B), (M)) + +#define _mm_cmpestrm(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestrm128((A), (LA), (B), (LB), (M)) +#define _mm_cmpestri(X, LX, Y, LY, M) \ + __builtin_ia32_pcmpestri128((A), (LA), (B), (LB), (M)) + +/* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */ +#define _mm_cmpistra(A, LA, B, LB, M) \ + __builtin_ia32_pcmpistria128((A), (LA), (B), (LB), (M)) +#define _mm_cmpistrc(A, LA, B, LB, M) \ + __builtin_ia32_pcmpistric128((A), (LA), (B), (LB), (M)) +#define _mm_cmpistro(A, LA, B, LB, M) \ + __builtin_ia32_pcmpistrio128((A), (LA), (B), (LB), (M)) +#define _mm_cmpistrs(A, LA, B, LB, M) \ + __builtin_ia32_pcmpistris128((A), (LA), (B), (LB), (M)) +#define _mm_cmpistrz(A, LA, B, LB, M) \ + __builtin_ia32_pcmpistriz128((A), (LA), (B), (LB), (M)) + +#define _mm_cmpestra(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestria128((A), (LA), (B), (LB), (M)) +#define _mm_cmpestrc(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestric128((A), (LA), (B), (LB), (M)) +#define _mm_cmpestro(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestrio128((A), (LA), (B), (LB), (M)) +#define _mm_cmpestrs(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestris128((A), (LA), (B), (LB), (M)) +#define _mm_cmpestrz(A, LA, B, LB, M) \ + __builtin_ia32_pcmpestriz128((A), (LA), (B), (LB), (M)) + +/* SSE4.2 Compare Packed Data -- Greater Than. */ +static inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_cmpgt_epi64(__m128i __V1, __m128i __V2) +{ + return __builtin_ia32_pcmpgtq((__v2di)__V1, (__v2di)__V2); +} + +/* SSE4.2 Accumulate CRC32. */ +static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +_mm_crc32_u8(unsigned int __C, unsigned char __D) +{ + return __builtin_ia32_crc32qi(__C, __D); +} + +static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +_mm_crc32_u16(unsigned int __C, unsigned short __D) +{ + return __builtin_ia32_crc32hi(__C, __D); +} + +static inline unsigned int __attribute__((__always_inline__, __nodebug__)) +_mm_crc32_u32(unsigned int __C, unsigned int __D) +{ + return __builtin_ia32_crc32si(__C, __D); +} + +#ifdef __x86_64__ +static inline unsigned long long __attribute__((__always_inline__, __nodebug__)) +_mm_crc32_u64(unsigned long long __C, unsigned long long __D) +{ + return __builtin_ia32_crc32di(__C, __D); +} +#endif /* __x86_64__ */ + +/* SSE4.2 Population Count. */ +static inline int __attribute__((__always_inline__, __nodebug__)) +_mm_popcnt_u32(unsigned int __A) +{ + return __builtin_popcount(__A); +} + +#ifdef __x86_64__ +static inline long long __attribute__((__always_inline__, __nodebug__)) +_mm_popcnt_u64(unsigned long long __A) +{ + return __builtin_popcountll(__A); +} +#endif /* __x86_64__ */ + +#endif /* __SSE4_2__ */ #endif /* __SSE4_1__ */ #endif /* _SMMINTRIN_H */ diff --git a/lib/Headers/varargs.h b/lib/Headers/varargs.h new file mode 100644 index 0000000..b5477d0 --- /dev/null +++ b/lib/Headers/varargs.h @@ -0,0 +1,26 @@ +/*===---- varargs.h - Variable argument handling -------------------------------------=== +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +* +*===-----------------------------------------------------------------------=== +*/ +#ifndef __VARARGS_H +#define __VARARGS_H + #error "Please use <stdarg.h> instead of <varargs.h>" +#endif diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 2f3888b..06e616b 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -30,6 +30,7 @@ #include <mmintrin.h> +typedef int __v4si __attribute__((__vector_size__(16))); typedef float __v4sf __attribute__((__vector_size__(16))); typedef float __m128 __attribute__((__vector_size__(16))); @@ -150,28 +151,24 @@ _mm_max_ps(__m128 a, __m128 b) static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_and_ps(__m128 a, __m128 b) { - typedef int __v4si __attribute__((__vector_size__(16))); return (__m128)((__v4si)a & (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_andnot_ps(__m128 a, __m128 b) { - typedef int __v4si __attribute__((__vector_size__(16))); return (__m128)(~(__v4si)a & (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_or_ps(__m128 a, __m128 b) { - typedef int __v4si __attribute__((__vector_size__(16))); return (__m128)((__v4si)a | (__v4si)b); } static inline __m128 __attribute__((__always_inline__, __nodebug__)) _mm_xor_ps(__m128 a, __m128 b) { - typedef int __v4si __attribute__((__vector_size__(16))); return (__m128)((__v4si)a ^ (__v4si)b); } diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt index 81a1e01..632fbc6 100644 --- a/lib/Lex/CMakeLists.txt +++ b/lib/Lex/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_library(clangLex PPMacroExpansion.cpp PTHLexer.cpp Pragma.cpp + PreprocessingRecord.cpp Preprocessor.cpp PreprocessorLexer.cpp ScratchBuffer.cpp diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 6cdb96f..2f89142 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -1036,7 +1036,11 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { // If this BCPL-style comment is in a macro definition, transmogrify it into // a C-style block comment. - std::string Spelling = PP->getSpelling(Result); + bool Invalid = false; + std::string Spelling = PP->getSpelling(Result, &Invalid); + if (Invalid) + return true; + assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?"); Spelling[1] = '*'; // Change prefix to "/*". Spelling += "*/"; // add suffix. diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index 2f1a34c..89f6368 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -208,24 +208,31 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, if (Tok.is(tok::string_literal) || // "foo" Tok.is(tok::wide_string_literal) || // L"foo" Tok.is(tok::char_constant)) { // 'x' and L'x'. - std::string Str = Lexer::Stringify(PP.getSpelling(Tok)); - Result.append(Str.begin(), Str.end()); + bool Invalid = false; + std::string TokStr = PP.getSpelling(Tok, &Invalid); + if (!Invalid) { + std::string Str = Lexer::Stringify(TokStr); + Result.append(Str.begin(), Str.end()); + } } else { // Otherwise, just append the token. Do some gymnastics to get the token // in place and avoid copies where possible. unsigned CurStrLen = Result.size(); Result.resize(CurStrLen+Tok.getLength()); const char *BufPtr = &Result[CurStrLen]; - unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr); - - // If getSpelling returned a pointer to an already uniqued version of the - // string instead of filling in BufPtr, memcpy it onto our string. - if (BufPtr != &Result[CurStrLen]) - memcpy(&Result[CurStrLen], BufPtr, ActualTokLen); - - // If the token was dirty, the spelling may be shorter than the token. - if (ActualTokLen != Tok.getLength()) - Result.resize(CurStrLen+ActualTokLen); + bool Invalid = false; + unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr, &Invalid); + + if (!Invalid) { + // If getSpelling returned a pointer to an already uniqued version of + // the string instead of filling in BufPtr, memcpy it onto our string. + if (BufPtr != &Result[CurStrLen]) + memcpy(&Result[CurStrLen], BufPtr, ActualTokLen); + + // If the token was dirty, the spelling may be shorter than the token. + if (ActualTokLen != Tok.getLength()) + Result.resize(CurStrLen+ActualTokLen); + } } } diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index cddc6cf..7b60101 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -71,7 +71,11 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); if (II == 0) { - std::string Spelling = getSpelling(MacroNameTok); + bool Invalid = false; + std::string Spelling = getSpelling(MacroNameTok, &Invalid); + if (Invalid) + return; + const IdentifierInfo &Info = Identifiers.get(Spelling); if (Info.isCPlusPlusOperatorKeyword()) // C++ 2.5p2: Alternative tokens behave the same as its primary token @@ -204,7 +208,12 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // to spell an i/e in a strange way that is another letter. Skipping this // allows us to avoid looking up the identifier info for #define/#undef and // other common directives. - const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation()); + bool Invalid = false; + const char *RawCharData = SourceMgr.getCharacterData(Tok.getLocation(), + &Invalid); + if (Invalid) + return; + char FirstChar = RawCharData[0]; if (FirstChar >= 'a' && FirstChar <= 'z' && FirstChar != 'i' && FirstChar != 'e') { @@ -614,8 +623,11 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, llvm::SmallString<64> IntegerBuffer; IntegerBuffer.resize(DigitTok.getLength()); const char *DigitTokBegin = &IntegerBuffer[0]; - unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin); - + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(DigitTok, DigitTokBegin, &Invalid); + if (Invalid) + return true; + // Verify that we have a simple digit-sequence, and compute the value. This // is always a simple digit string computed in decimal, so we do this manually // here. @@ -900,8 +912,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { // Verify that there is nothing after the string, other than EOM. CheckEndOfDirective("ident"); - if (Callbacks) - Callbacks->Ident(Tok.getLocation(), getSpelling(StrTok)); + if (Callbacks) { + bool Invalid = false; + std::string Str = getSpelling(StrTok, &Invalid); + if (!Invalid) + Callbacks->Ident(Tok.getLocation(), Str); + } } //===----------------------------------------------------------------------===// diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 81e6bf8..6d1c132 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -80,8 +80,10 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, } // Get the MemoryBuffer for this FID, if it fails, we fail. - const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID); - if (!InputFile) + bool Invalid = false; + const llvm::MemoryBuffer *InputFile = getSourceManager().getBuffer(FID, + &Invalid); + if (Invalid) return true; EnterSourceFileWithLexer(new Lexer(FID, InputFile, *this), CurDir); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 5fe2ef1..ffae8ab 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -542,9 +542,13 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok, return false; case tok::angle_string_literal: - case tok::string_literal: - Filename = PP.getSpelling(Tok, FilenameBuffer); + case tok::string_literal: { + bool Invalid = false; + Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); + if (Invalid) + return false; break; + } case tok::less: // This could be a <foo/bar.h> file coming from a macro expansion. In this diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 654d460..92332a0 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -287,7 +287,10 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Reserve a buffer to get the spelling. llvm::SmallString<128> FilenameBuffer; - llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer); + bool Invalid = false; + llvm::StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); + if (Invalid) + return; bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp new file mode 100644 index 0000000..6966c38 --- /dev/null +++ b/lib/Lex/PreprocessingRecord.cpp @@ -0,0 +1,128 @@ +//===--- PreprocessingRecord.cpp - Record of Preprocessing ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PreprocessingRecord class, which maintains a record +// of what occurred during preprocessing, and its helpers. +// +//===----------------------------------------------------------------------===// +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Token.h" + +using namespace clang; + +ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } + +void PreprocessingRecord::MaybeLoadPreallocatedEntities() const { + if (!ExternalSource || LoadedPreallocatedEntities) + return; + + LoadedPreallocatedEntities = true; + ExternalSource->ReadPreprocessedEntities(); +} + +PreprocessingRecord::PreprocessingRecord() + : ExternalSource(0), NumPreallocatedEntities(0), + LoadedPreallocatedEntities(false) +{ +} + +PreprocessingRecord::iterator +PreprocessingRecord::begin(bool OnlyLocalEntities) { + if (OnlyLocalEntities) + return PreprocessedEntities.begin() + NumPreallocatedEntities; + + MaybeLoadPreallocatedEntities(); + return PreprocessedEntities.begin(); +} + +PreprocessingRecord::iterator PreprocessingRecord::end(bool OnlyLocalEntities) { + if (!OnlyLocalEntities) + MaybeLoadPreallocatedEntities(); + + return PreprocessedEntities.end(); +} + +PreprocessingRecord::const_iterator +PreprocessingRecord::begin(bool OnlyLocalEntities) const { + if (OnlyLocalEntities) + return PreprocessedEntities.begin() + NumPreallocatedEntities; + + MaybeLoadPreallocatedEntities(); + return PreprocessedEntities.begin(); +} + +PreprocessingRecord::const_iterator +PreprocessingRecord::end(bool OnlyLocalEntities) const { + if (!OnlyLocalEntities) + MaybeLoadPreallocatedEntities(); + + return PreprocessedEntities.end(); +} + +void PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) { + PreprocessedEntities.push_back(Entity); +} + +void PreprocessingRecord::SetExternalSource( + ExternalPreprocessingRecordSource &Source, + unsigned NumPreallocatedEntities) { + assert(!ExternalSource && + "Preprocessing record already has an external source"); + ExternalSource = &Source; + this->NumPreallocatedEntities = NumPreallocatedEntities; + PreprocessedEntities.insert(PreprocessedEntities.begin(), + NumPreallocatedEntities, 0); +} + +void PreprocessingRecord::SetPreallocatedEntity(unsigned Index, + PreprocessedEntity *Entity) { + assert(Index < NumPreallocatedEntities &&"Out-of-bounds preallocated entity"); + PreprocessedEntities[Index] = Entity; +} + +void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, + MacroDefinition *MD) { + MacroDefinitions[Macro] = MD; +} + +MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) { + llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos + = MacroDefinitions.find(MI); + if (Pos == MacroDefinitions.end()) + return 0; + + return Pos->second; +} + +void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI) { + if (MacroDefinition *Def = findMacroDefinition(MI)) + PreprocessedEntities.push_back( + new (*this) MacroInstantiation(Id.getIdentifierInfo(), + Id.getLocation(), + Def)); +} + +void PreprocessingRecord::MacroDefined(const IdentifierInfo *II, + const MacroInfo *MI) { + SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc()); + MacroDefinition *Def + = new (*this) MacroDefinition(II, MI->getDefinitionLoc(), R); + MacroDefinitions[MI] = Def; + PreprocessedEntities.push_back(Def); +} + +void PreprocessingRecord::MacroUndefined(const IdentifierInfo *II, + const MacroInfo *MI) { + llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos + = MacroDefinitions.find(MI); + if (Pos != MacroDefinitions.end()) + MacroDefinitions.erase(Pos); +} + diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 5584b18..9d59300 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -31,6 +31,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Pragma.h" +#include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/ScratchBuffer.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -53,7 +54,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0), Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0), - CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0) { + CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -232,8 +233,9 @@ bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, return false; // Load the actual file's contents. - const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); - if (!Buffer) + bool Invalid = false; + const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File, &Invalid); + if (Invalid) return true; // Find the byte position of the truncation point. @@ -427,10 +429,11 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart, // Figure out how many physical characters away the specified instantiation // character is. This needs to take into consideration newlines and // trigraphs. - const char *TokPtr = SourceMgr.getCharacterData(TokStart); + bool Invalid = false; + const char *TokPtr = SourceMgr.getCharacterData(TokStart, &Invalid); // If they request the first char of the token, we're trivially done. - if (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr)) + if (Invalid || (CharNo == 0 && Lexer::isObviouslySimpleCharacter(*TokPtr))) return TokStart; unsigned PhysOffset = 0; @@ -486,7 +489,7 @@ SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc, /// EnterMainSourceFile - Enter the specified FileID as the main source file, /// which implicitly adds the builtin defines etc. -void Preprocessor::EnterMainSourceFile() { +bool Preprocessor::EnterMainSourceFile() { // We do not allow the preprocessor to reenter the main file. Doing so will // cause FileID's to accumulate information from both runs (e.g. #line // information) and predefined macros aren't guaranteed to be set properly. @@ -495,8 +498,8 @@ void Preprocessor::EnterMainSourceFile() { // Enter the main file source buffer. std::string ErrorStr; - bool Res = EnterSourceFile(MainFileID, 0, ErrorStr); - assert(!Res && "Entering main file should not fail!"); + if (EnterSourceFile(MainFileID, 0, ErrorStr)) + return true; // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. @@ -513,8 +516,7 @@ void Preprocessor::EnterMainSourceFile() { assert(!FID.isInvalid() && "Could not create FileID for predefines?"); // Start parsing the predefines. - Res = EnterSourceFile(FID, 0, ErrorStr); - assert(!Res && "Entering predefines should not fail!"); + return EnterSourceFile(FID, 0, ErrorStr); } @@ -626,3 +628,11 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { } CommentHandler::~CommentHandler() { } + +void Preprocessor::createPreprocessingRecord() { + if (Record) + return; + + Record = new PreprocessingRecord; + addPPCallbacks(Record); +} diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index dbd1b84..56bb073 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -396,12 +396,17 @@ bool TokenLexer::PasteTokens(Token &Tok) { // Get the spelling of the LHS token in Buffer. const char *BufPtr = &Buffer[0]; - unsigned LHSLen = PP.getSpelling(Tok, BufPtr); + bool Invalid = false; + unsigned LHSLen = PP.getSpelling(Tok, BufPtr, &Invalid); if (BufPtr != &Buffer[0]) // Really, we want the chars in Buffer! memcpy(&Buffer[0], BufPtr, LHSLen); - + if (Invalid) + return true; + BufPtr = &Buffer[LHSLen]; - unsigned RHSLen = PP.getSpelling(RHS, BufPtr); + unsigned RHSLen = PP.getSpelling(RHS, BufPtr, &Invalid); + if (Invalid) + return true; if (BufPtr != &Buffer[LHSLen]) // Really, we want the chars in Buffer! memcpy(&Buffer[LHSLen], BufPtr, RHSLen); diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index b96dff5..a66dd96 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -54,7 +54,6 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { if (AttrName.startswith("__") && AttrName.endswith("__")) AttrName = AttrName.substr(2, AttrName.size() - 4); - // FIXME: Hand generating this is neither smart nor efficient. return llvm::StringSwitch<AttributeList::Kind>(AttrName) .Case("weak", AT_weak) .Case("weakref", AT_weakref) @@ -93,6 +92,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("dllimport", AT_dllimport) .Case("dllexport", AT_dllexport) .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("gcc_tdiag", IgnoredAttribute) // GCC diagnostics type checking. .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) .Case("visibility", AT_visibility) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 12c5b6c..cff35b7 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -110,7 +110,7 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - // check if we have a "paramterized" attribute + // check if we have a "parameterized" attribute if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b92e753..9e232cb 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -167,7 +167,10 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallString<8> LangBuffer; // LangBuffer is guaranteed to be big enough. - llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer); + bool Invalid = false; + llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); + if (Invalid) + return DeclPtrTy(); SourceLocation Loc = ConsumeStringToken(); @@ -1517,6 +1520,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); + + if (TagDecl) + Actions.ActOnTagDefinitionError(CurScope, TagDecl); return; } } @@ -1593,11 +1599,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParseLexedMethodDefs(getCurrentClass()); } + Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); + // Leave the class scope. ParsingDef.Pop(); ClassScope.Exit(); - - Actions.ActOnTagFinishDefinition(CurScope, TagDecl, RBraceLoc); } /// ParseConstructorInitializer - Parse a C++ constructor initializer, diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e7a771e..d45aaed 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -21,20 +21,6 @@ #include "ParsePragma.h" using namespace clang; -/// \brief A comment handler that passes comments found by the preprocessor -/// to the parser action. -class ActionCommentHandler : public CommentHandler { - Action &Actions; - -public: - explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { } - - virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) { - Actions.ActOnComment(Comment); - return false; - } -}; - Parser::Parser(Preprocessor &pp, Action &actions) : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), @@ -59,9 +45,6 @@ Parser::Parser(Preprocessor &pp, Action &actions) WeakHandler.reset(new PragmaWeakHandler(&PP.getIdentifierTable().get("weak"), actions)); PP.AddPragmaHandler(0, WeakHandler.get()); - - CommentHandler.reset(new ActionCommentHandler(actions)); - PP.AddCommentHandler(CommentHandler.get()); } /// If a crash happens while the parser is active, print out a line indicating @@ -317,7 +300,6 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(0, WeakHandler.get()); WeakHandler.reset(); - PP.RemoveCommentHandler(CommentHandler.get()); } /// Initialize - Warm up the parser. diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp new file mode 100644 index 0000000..c4ceec0 --- /dev/null +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -0,0 +1,369 @@ +//=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines analysis_warnings::[Policy,Executor]. +// Together they are used by Sema to issue warnings based on inexpensive +// static analysis algorithms in libAnalysis. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "AnalysisBasedWarnings.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/Analyses/ReachableCode.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/Casting.h" +#include <queue> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Unreachable code analysis. +//===----------------------------------------------------------------------===// + +namespace { + class UnreachableCodeHandler : public reachable_code::Callback { + Sema &S; + public: + UnreachableCodeHandler(Sema &s) : S(s) {} + + void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { + S.Diag(L, diag::warn_unreachable) << R1 << R2; + } + }; +} + +/// CheckUnreachable - Check for unreachable code. +static void CheckUnreachable(Sema &S, AnalysisContext &AC) { + UnreachableCodeHandler UC(S); + reachable_code::FindUnreachableCode(AC, UC); +} + +//===----------------------------------------------------------------------===// +// Check for missing return value. +//===----------------------------------------------------------------------===// + +enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, + AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; + +/// 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. +static ControlFlowKind 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 = reachable_code::ScanReachableFromBlock(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 += reachable_code::ScanReachableFromBlock(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; +} + +struct CheckFallThroughDiagnostics { + unsigned diag_MaybeFallThrough_HasNoReturn; + unsigned diag_MaybeFallThrough_ReturnsNonVoid; + unsigned diag_AlwaysFallThrough_HasNoReturn; + unsigned diag_AlwaysFallThrough_ReturnsNonVoid; + unsigned diag_NeverFallThroughOrReturn; + bool funMode; + + static CheckFallThroughDiagnostics MakeForFunction() { + CheckFallThroughDiagnostics D; + D.diag_MaybeFallThrough_HasNoReturn = + diag::warn_falloff_noreturn_function; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::warn_maybe_falloff_nonvoid_function; + D.diag_AlwaysFallThrough_HasNoReturn = + diag::warn_falloff_noreturn_function; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::warn_falloff_nonvoid_function; + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_function; + D.funMode = true; + return D; + } + + static CheckFallThroughDiagnostics MakeForBlock() { + CheckFallThroughDiagnostics D; + D.diag_MaybeFallThrough_HasNoReturn = + diag::err_noreturn_block_has_return_expr; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::err_maybe_falloff_nonvoid_block; + D.diag_AlwaysFallThrough_HasNoReturn = + diag::err_noreturn_block_has_return_expr; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::err_falloff_nonvoid_block; + D.diag_NeverFallThroughOrReturn = + diag::warn_suggest_noreturn_block; + D.funMode = false; + return D; + } + + bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, + bool HasNoReturn) const { + if (funMode) { + return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn) + && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid); + } + + // For blocks. + return ReturnsVoid && !HasNoReturn + && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block) + == Diagnostic::Ignored || !ReturnsVoid); + } +}; + +/// 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. +static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, + QualType BlockTy, + const CheckFallThroughDiagnostics& CD, + AnalysisContext &AC) { + + bool ReturnsVoid = false; + bool HasNoReturn = false; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + ReturnsVoid = FD->getResultType()->isVoidType(); + HasNoReturn = FD->hasAttr<NoReturnAttr>() || + FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); + } + else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + ReturnsVoid = MD->getResultType()->isVoidType(); + HasNoReturn = MD->hasAttr<NoReturnAttr>(); + } + else if (isa<BlockDecl>(D)) { + if (const FunctionType *FT = + BlockTy->getPointeeType()->getAs<FunctionType>()) { + if (FT->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FT->getNoReturnAttr()) + HasNoReturn = true; + } + } + + Diagnostic &Diags = S.getDiagnostics(); + + // Short circuit for compilation speed. + if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) + return; + + // FIXME: Function try block + if (const CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { + switch (CheckFallThrough(AC)) { + case MaybeFallThrough: + if (HasNoReturn) + S.Diag(Compound->getRBracLoc(), + CD.diag_MaybeFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(Compound->getRBracLoc(), + CD.diag_MaybeFallThrough_ReturnsNonVoid); + break; + case AlwaysFallThrough: + if (HasNoReturn) + S.Diag(Compound->getRBracLoc(), + CD.diag_AlwaysFallThrough_HasNoReturn); + else if (!ReturnsVoid) + S.Diag(Compound->getRBracLoc(), + CD.diag_AlwaysFallThrough_ReturnsNonVoid); + break; + case NeverFallThroughOrReturn: + if (ReturnsVoid && !HasNoReturn) + S.Diag(Compound->getLBracLoc(), + CD.diag_NeverFallThroughOrReturn); + break; + case NeverFallThrough: + break; + } + } +} + +//===----------------------------------------------------------------------===// +// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based +// warnings on a function, method, or block. +//===----------------------------------------------------------------------===// + +clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) { + Diagnostic &D = S.getDiagnostics(); + + enableCheckFallThrough = 1; + + enableCheckUnreachable = (unsigned) + (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored); +} + +void clang::sema::AnalysisBasedWarnings::IssueWarnings(const Decl *D, + QualType BlockTy) { + + assert(BlockTy.isNull() || isa<BlockDecl>(D)); + + // Do not do any analysis for declarations in system headers if we are + // going to just ignore them. + if (S.getDiagnostics().getSuppressSystemWarnings() && + S.SourceMgr.isInSystemHeader(D->getLocation())) + return; + + // We avoid doing analysis-based warnings when there are errors for + // two reasons: + // (1) The CFGs often can't be constructed (if the body is invalid), so + // don't bother trying. + // (2) The code already has problems; running the analysis just takes more + // time. + if (S.getDiagnostics().hasErrorOccurred()) + return; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // For function templates, class templates and member function templates + // we'll do the analysis at instantiation time. + if (FD->isDependentContext()) + return; + } + + const Stmt *Body = D->getBody(); + assert(Body); + + // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 + // explosion for destrutors that can result and the compile time hit. + AnalysisContext AC(D, false); + + // Warning: check missing 'return' + if (enableCheckFallThrough) { + const CheckFallThroughDiagnostics &CD = + (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() + : CheckFallThroughDiagnostics::MakeForFunction()); + CheckFallThroughForBody(S, D, Body, BlockTy, CD, AC); + } + + // Warning: check for unreachable code + if (enableCheckUnreachable) + CheckUnreachable(S, AC); +} diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h new file mode 100644 index 0000000..39da1b1 --- /dev/null +++ b/lib/Sema/AnalysisBasedWarnings.h @@ -0,0 +1,35 @@ +//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisBasedWarnings, a worker object used by Sema +// that issues warnings based on dataflow-analysis. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H +#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H + +namespace clang { namespace sema { + +class AnalysisBasedWarnings { + Sema &S; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + +public: + + AnalysisBasedWarnings(Sema &s); + void IssueWarnings(const Decl *D, QualType BlockTy = QualType()); + + void disableCheckFallThrough() { enableCheckFallThrough = 0; } +}; + +}} // end namespace clang::sema + +#endif diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 237803a..ac0dfd6 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangSema + AnalysisBasedWarnings.cpp CodeCompleteConsumer.cpp IdentifierResolver.cpp JumpDiagnostics.cpp diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h index 69d1351..63c6ee3 100644 --- a/lib/Sema/CXXFieldCollector.h +++ b/lib/Sema/CXXFieldCollector.h @@ -58,7 +58,10 @@ public: } /// getCurNumField - The number of fields added to the currently parsed class. - size_t getCurNumFields() const { return FieldCount.back(); } + size_t getCurNumFields() const { + assert(!FieldCount.empty() && "no currently-parsed class"); + return FieldCount.back(); + } /// getCurFields - Pointer to array of fields added to the currently parsed /// class. diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp index 898b3c2..7cd3989 100644 --- a/lib/Sema/ParseAST.cpp +++ b/lib/Sema/ParseAST.cpp @@ -44,7 +44,8 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); Parser P(PP, S); - PP.EnterMainSourceFile(); + if (PP.EnterMainSourceFile()) + return; // Initialize the parser. P.Initialize(); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3b4afef..7112687 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -399,8 +399,3 @@ BlockScopeInfo *Sema::getCurBlock() { return dyn_cast<BlockScopeInfo>(FunctionScopes.back()); } - -void Sema::ActOnComment(SourceRange Comment) { - Context.Comments.push_back(Comment); -} - diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4c25844..b529e5b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -42,7 +42,6 @@ namespace llvm { } namespace clang { - class AnalysisContext; class ASTContext; class ASTConsumer; class CodeCompleteConsumer; @@ -321,6 +320,14 @@ public: Diag(0) { } + AccessedEntity(MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl) + : Access(FoundDecl.getAccess()), IsMember(true), + Target(FoundDecl.getDecl()), NamingClass(NamingClass), + Diag(0) { + } + AccessedEntity(BaseNonce _, CXXRecordDecl *BaseClass, CXXRecordDecl *DerivedClass, @@ -678,8 +685,6 @@ public: /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } - virtual void ActOnComment(SourceRange Comment); - //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // @@ -778,6 +783,7 @@ public: const LookupResult &Previous, Scope *S); void DiagnoseFunctionSpecifiers(Declarator& D); + void DiagnoseShadow(Scope *S, Declarator &D, const LookupResult& R); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -938,6 +944,10 @@ public: virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, SourceLocation RBraceLoc); + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable + /// error parsing the definition of a tag. + virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl); + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, @@ -1126,12 +1136,12 @@ public: typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; void AddOverloadCandidate(NamedDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet); void AddOverloadCandidate(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, @@ -1141,20 +1151,21 @@ public: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); - void AddMethodCandidate(NamedDecl *Decl, AccessSpecifier Access, + void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false, bool ForceRValue = false); - void AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, + void AddMethodCandidate(CXXMethodDecl *Method, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -1163,24 +1174,24 @@ public: bool SuppressUserConversions = false, bool ForceRValue = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool ForceRValue = false); void AddConversionCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet); void AddSurrogateCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectTy, Expr **Args, unsigned NumArgs, @@ -1284,9 +1295,6 @@ public: OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, SourceLocation OpLoc); - /// CheckUnreachable - Check for unreachable code. - void CheckUnreachable(AnalysisContext &); - /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. @@ -1294,15 +1302,9 @@ public: CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. - void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, AnalysisContext &); - void CheckFallThroughForBlock(QualType BlockTy, Stmt *, AnalysisContext &); bool CheckParmsForFunctionDef(FunctionDecl *FD); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); - enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1, - AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 }; - ControlFlowKind CheckFallThrough(AnalysisContext &); - Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup @@ -2473,10 +2475,11 @@ public: bool IsImplicitConstructor, bool AnyErrors); - /// MarkBaseAndMemberDestructorsReferenced - Given a destructor decl, - /// mark all its non-trivial member and base destructor declarations - /// as referenced. - void MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor); + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, + /// mark all the non-trivial destructors of its members and bases as + /// referenced. + void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, + CXXRecordDecl *Record); /// ClassesWithUnmarkedVirtualMembers - Contains record decls whose virtual /// members need to be marked as referenced at the end of the translation @@ -2617,11 +2620,13 @@ public: AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); + AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, AccessSpecifier Access); @@ -2634,8 +2639,7 @@ public: AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, - NamedDecl *D, - AccessSpecifier Access); + DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index f0a38d5..40b320c 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -52,7 +52,7 @@ bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, namespace { struct EffectiveContext { - EffectiveContext() : Record(0), Function(0) {} + EffectiveContext() : Function(0) {} explicit EffectiveContext(DeclContext *DC) { if (isa<FunctionDecl>(DC)) { @@ -60,18 +60,28 @@ struct EffectiveContext { DC = Function->getDeclContext(); } else Function = 0; - - if (isa<CXXRecordDecl>(DC)) - Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); - else - Record = 0; + + // C++ [class.access.nest]p1: + // A nested class is a member and as such has the same access + // rights as any other member. + // C++ [class.access]p2: + // A member of a class can also access all the names to which + // the class has access. + // This implies that the privileges of nesting are transitive. + while (isa<CXXRecordDecl>(DC)) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); + Records.push_back(Record); + DC = Record->getDeclContext(); + } } - bool isClass(const CXXRecordDecl *R) const { - return R->getCanonicalDecl() == Record; + bool includesClass(const CXXRecordDecl *R) const { + R = R->getCanonicalDecl(); + return std::find(Records.begin(), Records.end(), R) + != Records.end(); } - CXXRecordDecl *Record; + llvm::SmallVector<CXXRecordDecl*, 4> Records; FunctionDecl *Function; }; } @@ -83,48 +93,133 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { return DeclaringClass; } +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Friend) { + // FIXME: close matches becuse of dependency + if (EC.includesClass(Friend)) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; +} + +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *Friend) { + if (Type *T = Friend->getFriendType()) { + CanQualType CT = T->getCanonicalTypeUnqualified(); + if (const RecordType *RT = CT->getAs<RecordType>()) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); + + // TODO: we can fail early for a lot of type classes. + if (T->isDependentType()) + return Sema::AR_dependent; + + return Sema::AR_inaccessible; + } + + NamedDecl *D + = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + + // FIXME: declarations with dependent or templated scope. + + // For class templates, we want to check whether any of the records + // are possible specializations of the template. + if (isa<ClassTemplateDecl>(D)) { + for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CXXRecordDecl *Record = *I; + ClassTemplateDecl *CTD; + + // A specialization of the template... + if (isa<ClassTemplateSpecializationDecl>(Record)) { + CTD = cast<ClassTemplateSpecializationDecl>(Record) + ->getSpecializedTemplate(); + + // ... or the template pattern itself. + } else { + CTD = Record->getDescribedClassTemplate(); + } + + if (CTD && D == CTD->getCanonicalDecl()) + return Sema::AR_accessible; + } + + return Sema::AR_inaccessible; + } + + // Same thing for function templates. + if (isa<FunctionTemplateDecl>(D)) { + if (!EC.Function) return Sema::AR_inaccessible; + + FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); + if (!FTD) + FTD = EC.Function->getDescribedFunctionTemplate(); + + if (FTD && D == FTD->getCanonicalDecl()) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; + } + + // Friend functions. FIXME: close matches due to dependency. + // + // The decl pointers in EC have been canonicalized, so pointer + // equality is sufficient. + if (D == EC.Function) + return Sema::AR_accessible; + + if (isa<CXXRecordDecl>(D)) + return MatchesFriend(S, EC, cast<CXXRecordDecl>(D)); + + return Sema::AR_inaccessible; +} + static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { // A class always has access to its own members. - if (EC.isClass(Class)) + if (EC.includesClass(Class)) return Sema::AR_accessible; + Sema::AccessResult OnFailure = Sema::AR_inaccessible; + // Okay, check friends. for (CXXRecordDecl::friend_iterator I = Class->friend_begin(), E = Class->friend_end(); I != E; ++I) { FriendDecl *Friend = *I; - if (Type *T = Friend->getFriendType()) { - if (EC.Record && - S.Context.hasSameType(QualType(T, 0), - S.Context.getTypeDeclType(EC.Record))) - return Sema::AR_accessible; - } else { - NamedDecl *D - = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl()); + switch (MatchesFriend(S, EC, Friend)) { + case Sema::AR_accessible: + return Sema::AR_accessible; - // The decl pointers in EC have been canonicalized, so pointer - // equality is sufficient. - if (D == EC.Function || D == EC.Record) - return Sema::AR_accessible; - } + case Sema::AR_inaccessible: + break; + + case Sema::AR_dependent: + OnFailure = Sema::AR_dependent; + break; - // FIXME: templates! templated contexts! dependent delay! + case Sema::AR_delayed: + llvm_unreachable("cannot get delayed answer from MatchesFriend"); + } } // That's it, give up. - return Sema::AR_inaccessible; + return OnFailure; } /// Finds the best path from the naming class to the declaring class, /// taking friend declarations into account. /// +/// \param FinalAccess the access of the "final step", or AS_none if +/// there is no final step. /// \return null if friendship is dependent static CXXBasePath *FindBestPath(Sema &S, const EffectiveContext &EC, CXXRecordDecl *Derived, CXXRecordDecl *Base, + AccessSpecifier FinalAccess, CXXBasePaths &Paths) { // Derive the paths to the desired base. bool isDerived = Derived->isDerivedFrom(Base, Paths); @@ -133,28 +228,43 @@ static CXXBasePath *FindBestPath(Sema &S, CXXBasePath *BestPath = 0; + assert(FinalAccess != AS_none && "forbidden access after declaring class"); + // Derive the friend-modified access along each path. for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); PI != PE; ++PI) { // Walk through the path backwards. - AccessSpecifier PathAccess = AS_public; + AccessSpecifier PathAccess = FinalAccess; CXXBasePath::iterator I = PI->end(), E = PI->begin(); while (I != E) { --I; + assert(PathAccess != AS_none); + + // If the declaration is a private member of a base class, there + // is no level of friendship in derived classes that can make it + // accessible. + if (PathAccess == AS_private) { + PathAccess = AS_none; + break; + } + AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); if (BaseAccess != AS_public) { switch (GetFriendKind(S, EC, I->Class)) { - case Sema::AR_inaccessible: break; - case Sema::AR_accessible: BaseAccess = AS_public; break; - case Sema::AR_dependent: return 0; + case Sema::AR_inaccessible: + PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); + break; + case Sema::AR_accessible: + PathAccess = AS_public; + break; + case Sema::AR_dependent: + return 0; case Sema::AR_delayed: llvm_unreachable("friend resolution is never delayed"); break; } } - - PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess); } // Note that we modify the path's Access field to the @@ -199,7 +309,8 @@ static void DiagnoseAccessPath(Sema &S, } CXXBasePaths Paths; - CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths); + CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, + AS_public, Paths); CXXBasePath::iterator I = Path.end(), E = Path.begin(); while (I != E) { @@ -304,7 +415,7 @@ static void TryElevateAccess(Sema &S, CXXRecordDecl *NamingClass = Entity.getNamingClass(); // Adjust the declaration of the referred entity. - AccessSpecifier DeclAccess = AS_none; + AccessSpecifier DeclAccess = AS_public; if (Entity.isMemberAccess()) { NamedDecl *Target = Entity.getTargetDecl(); @@ -329,17 +440,15 @@ static void TryElevateAccess(Sema &S, // Append the declaration's access if applicable. CXXBasePaths Paths; CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(), - DeclaringClass, Paths); + DeclaringClass, DeclAccess, Paths); if (!Path) { // FIXME: delay dependent friendship return; } - // Grab the access along the best path. + // Grab the access along the best path (note that this includes the + // final-step access). AccessSpecifier NewAccess = Path->Access; - if (Entity.isMemberAccess()) - NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess); - assert(NewAccess <= Access && "access along best path worse than direct?"); Access = NewAccess; } @@ -350,51 +459,38 @@ static Sema::AccessResult CheckEffectiveAccess(Sema &S, SourceLocation Loc, Sema::AccessedEntity const &Entity) { AccessSpecifier Access = Entity.getAccess(); - assert(Access != AS_public); + assert(Access != AS_public && "called for public access!"); + // Find a non-anonymous naming class. For records with access, + // there should always be one of these. CXXRecordDecl *NamingClass = Entity.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->getParent()); - if (!EC.Record) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - - if (!Entity.isQuiet()) - DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); - return Sema::AR_inaccessible; - } - - // White-list accesses from within the declaring class. - if (Access != AS_none && EC.isClass(NamingClass)) + // White-list accesses from classes with privileges equivalent to the + // naming class --- but only if the access path isn't forbidden + // (i.e. an access of a private member from a subclass). + if (Access != AS_none && EC.includesClass(NamingClass)) return Sema::AR_accessible; - - // If the access is worse than 'protected', try to promote to it using - // friend declarations. - bool TriedElevation = false; - if (Access != AS_protected) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - TriedElevation = true; - } + + // Try to elevate access. + // FIXME: delay if elevation was dependent? + // TODO: on some code, it might be better to do the protected check + // without trying to elevate first. + TryElevateAccess(S, EC, Entity, Access); + if (Access == AS_public) return Sema::AR_accessible; // Protected access. if (Access == AS_protected) { // FIXME: implement [class.protected]p1 - if (EC.Record->isDerivedFrom(NamingClass)) - return Sema::AR_accessible; + for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) + if ((*I)->isDerivedFrom(NamingClass)) + return Sema::AR_accessible; - // FIXME: delay dependent classes + // FIXME: delay if we can't decide class derivation yet. } - // We're about to reject; one last chance to promote access. - if (!TriedElevation) { - TryElevateAccess(S, EC, Entity, Access); - if (Access == AS_public) return Sema::AR_accessible; - } - // Okay, that's it, reject it. if (!Entity.isQuiet()) DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity); @@ -431,15 +527,13 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) { } Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, - NamedDecl *D, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || !E->getNamingClass() || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, - E->getNamingClass(), Access, D); + AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getNameLoc(), Entity); @@ -448,14 +542,12 @@ Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, /// Perform access-control checking on a previously-unresolved member /// access which has now been resolved to a member. Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, - NamedDecl *D, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; - AccessedEntity Entity(AccessedEntity::Member, - E->getNamingClass(), Access, D); + AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found); Entity.setDiag(diag::err_access) << E->getSourceRange(); return CheckAccess(*this, E->getMemberLoc(), Entity); @@ -473,7 +565,8 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, return AR_accessible; CXXRecordDecl *NamingClass = Dtor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Dtor, Access)); Entity.setDiag(PDiag); // TODO: avoid copy return CheckAccess(*this, Loc, Entity); @@ -488,8 +581,8 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); - AccessedEntity Entity(AccessedEntity::Member, - NamingClass, Access, Constructor); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Constructor, Access)); Entity.setDiag(diag::err_access_ctor); return CheckAccess(*this, UseLoc, Entity); @@ -506,29 +599,45 @@ Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc, return AR_accessible; CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext()); - AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, + DeclAccessPair::make(Target, Access)); Entity.setDiag(Diag); return CheckAccess(*this, UseLoc, Entity); } +/// Checks access to an overloaded operator new or delete. +Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair Found) { + if (!getLangOptions().AccessControl || + !NamingClass || + Found.getAccess() == AS_public) + return AR_accessible; + + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); + Entity.setDiag(diag::err_access) + << PlacementRange; + + return CheckAccess(*this, OpLoc, Entity); +} + /// Checks access to an overloaded member operator, including /// conversion operators. Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, Expr *ObjectExpr, Expr *ArgExpr, - NamedDecl *MemberOperator, - AccessSpecifier Access) { + DeclAccessPair Found) { if (!getLangOptions().AccessControl || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>(); assert(RT && "found member operator but object expr not of record type"); CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); - AccessedEntity Entity(AccessedEntity::Member, - NamingClass, Access, MemberOperator); + AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); @@ -580,7 +689,8 @@ void Sema::CheckLookupAccess(const LookupResult &R) { for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (I.getAccess() != AS_public) { AccessedEntity Entity(AccessedEntity::Member, - R.getNamingClass(), I.getAccess(), *I); + R.getNamingClass(), + I.getPair()); Entity.setDiag(diag::err_access); CheckAccess(*this, R.getNameLoc(), Entity); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 3fac79d..0a33485 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -13,9 +13,6 @@ //===----------------------------------------------------------------------===// #include "Sema.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/PrintfFormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -30,7 +27,6 @@ #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 @@ -2045,6 +2041,11 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, if (!tmp.isNull()) rt = tmp; } + if (const EnumType *E = lt->getAs<EnumType>()) + lt = E->getDecl()->getPromotionType(); + if (const EnumType *E = rt->getAs<EnumType>()) + rt = E->getDecl()->getPromotionType(); + // The rule is that the signed operand becomes unsigned, so isolate the // signed operand. Expr *signedOperand = lex, *unsignedOperand = rex; @@ -2219,276 +2220,6 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) { return; } - - -namespace { -class UnreachableCodeHandler : public reachable_code::Callback { - Sema &S; -public: - UnreachableCodeHandler(Sema *s) : S(*s) {} - - void HandleUnreachable(SourceLocation L, SourceRange R1, SourceRange R2) { - S.Diag(L, diag::warn_unreachable) << R1 << R2; - } -}; -} - -/// 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() || - Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored) - return; - - UnreachableCodeHandler UC(this); - reachable_code::FindUnreachableCode(AC, UC); -} - -/// 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 = reachable_code::ScanReachableFromBlock(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 += reachable_code::ScanReachableFromBlock(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)) { - // For function templates, class templates and member function templates - // we'll do the analysis at instantiation time. - if (FD->isDependentContext()) - return; - - ReturnsVoid = FD->getResultType()->isVoidType(); - HasNoReturn = FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); - - } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - ReturnsVoid = MD->getResultType()->isVoidType(); - HasNoReturn = MD->hasAttr<NoReturnAttr>(); - } - - // 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 diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 4693fa9..317eef8 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2253,7 +2253,8 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, Results.push_back(ResultCandidate(FDecl)); else // FIXME: access? - AddOverloadCandidate(FDecl, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FDecl, DeclAccessPair::make(FDecl, AS_none), + Args, NumArgs, CandidateSet, false, false, /*PartialOverloading*/ true); } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index dab7d88..e11e161 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/AnalysisContext.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -2403,6 +2403,10 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); } + // Diagnose shadowed variables before filtering for scope. + if (!D.getCXXScopeSpec().isSet()) + DiagnoseShadow(S, D, Previous); + // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). @@ -2454,6 +2458,72 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, return NewVD; } +/// \brief Diagnose variable or built-in function shadowing. +/// +/// This method is called as soon as a NamedDecl materializes to check +/// if it shadows another local or global variable, or a built-in function. +/// +/// For performance reasons, the lookup results are reused from the calling +/// context. +/// +/// \param S the scope in which the shadowing name is being declared +/// \param R the lookup of the name +/// +void Sema::DiagnoseShadow(Scope *S, Declarator &D, + const LookupResult& R) { + // Return if warning is ignored. + if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored) + return; + + // Don't diagnose declarations at file scope. The scope might not + // have a DeclContext if (e.g.) we're parsing a function prototype. + DeclContext *NewDC = static_cast<DeclContext*>(S->getEntity()); + if (NewDC && NewDC->isFileContext()) + return; + + // Only diagnose if we're shadowing an unambiguous field or variable. + if (R.getResultKind() != LookupResult::Found) + return; + + NamedDecl* ShadowedDecl = R.getFoundDecl(); + if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) + return; + + DeclContext *OldDC = ShadowedDecl->getDeclContext(); + + // Only warn about certain kinds of shadowing for class members. + if (NewDC && NewDC->isRecord()) { + // In particular, don't warn about shadowing non-class members. + if (!OldDC->isRecord()) + return; + + // TODO: should we warn about static data members shadowing + // static data members from base classes? + + // TODO: don't diagnose for inaccessible shadowed members. + // This is hard to do perfectly because we might friend the + // shadowing context, but that's just a false negative. + } + + // Determine what kind of declaration we're shadowing. + unsigned Kind; + if (isa<RecordDecl>(OldDC)) { + if (isa<FieldDecl>(ShadowedDecl)) + Kind = 3; // field + else + Kind = 2; // static data member + } else if (OldDC->isFileContext()) + Kind = 1; // global + else + Kind = 0; // local + + DeclarationName Name = R.getLookupName(); + + // Emit warning and note. + Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); +} + /// \brief Perform semantic checking on a newly-created variable /// declaration. /// @@ -3896,7 +3966,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check for redeclaration of parameters, e.g. int foo(int x, int x); IdentifierInfo *II = D.getIdentifier(); if (II) { - if (NamedDecl *PrevDecl = LookupSingleName(S, II, LookupOrdinaryName)) { + LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, + ForRedeclaration); + LookupName(R, S); + if (R.isSingleResult()) { + NamedDecl *PrevDecl = R.getFoundDecl(); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -3910,6 +3984,8 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { II = 0; D.SetIdentifier(0, D.getIdentifierLoc()); D.setInvalidType(true); + } else { + DiagnoseShadow(S, D, R); } } } @@ -4183,9 +4259,6 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - // 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) @@ -4193,14 +4266,16 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, else FD = dyn_cast_or_null<FunctionDecl>(dcl); + sema::AnalysisBasedWarnings W(*this); + if (FD) { FD->setBody(Body); - if (FD->isMain()) + if (FD->isMain()) { // C and C++ allow for main to automagically return 0. // Implements C++ [basic.start.main]p5 and C99 5.1.2.2.3. FD->setHasImplicitReturnZero(true); - else - CheckFallThroughForFunctionDef(FD, Body, AC); + W.disableCheckFallThrough(); + } if (!FD->isInvalidDecl()) DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); @@ -4212,9 +4287,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - CheckFallThroughForFunctionDef(MD, Body, AC); MD->setEndLoc(Body->getLocEnd()); - if (!MD->isInvalidDecl()) DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); } else { @@ -4267,28 +4340,40 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } if (Body) { - CheckUnreachable(AC); - // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) // Verify this. if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); - // Verify that that gotos and switch cases don't jump into scopes illegally. - // Verify that that gotos and switch cases don't jump into scopes illegally. + // Verify that that gotos and switch cases don't jump into scopes illegally. + // Verify that that gotos and switch cases don't jump into scopes illegally. if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(Body); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) - MarkBaseAndMemberDestructorsReferenced(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. if (PP.getDiagnostics().hasErrorOccurred()) ExprTemporaries.clear(); - + else if (!isa<FunctionTemplateDecl>(dcl)) { + // Since the body is valid, issue any analysis-based warnings that are + // enabled. + QualType ResultType; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(dcl)) { + ResultType = FD->getResultType(); + } + else { + ObjCMethodDecl *MD = cast<ObjCMethodDecl>(dcl); + ResultType = MD->getResultType(); + } + W.IssueWarnings(dcl); + } + assert(ExprTemporaries.empty() && "Leftover temporaries in function"); } @@ -5055,6 +5140,18 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, Consumer.HandleTagDeclDefinition(Tag); } +void Sema::ActOnTagDefinitionError(Scope *S, DeclPtrTy TagD) { + AdjustDeclIfTemplate(TagD); + TagDecl *Tag = cast<TagDecl>(TagD.getAs<Decl>()); + Tag->setInvalidDecl(); + + // We're undoing ActOnTagStartDefinition here, not + // ActOnStartCXXMemberDeclarations, so we don't have to mess with + // the FieldCollector. + + PopDeclContext(); +} + // Note that FieldName may be null for anonymous bitfields. bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, const Expr *BitWidth, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c27b0d5..13a7ead 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1643,29 +1643,14 @@ Sema::SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, Constructor->setNumBaseOrMemberInitializers(NumInitializers); CXXBaseOrMemberInitializer **baseOrMemberInitializers = new (Context) CXXBaseOrMemberInitializer*[NumInitializers]; - + memcpy(baseOrMemberInitializers, AllToInit.data(), + NumInitializers * sizeof(CXXBaseOrMemberInitializer*)); Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers); - for (unsigned Idx = 0; Idx < NumInitializers; ++Idx) { - CXXBaseOrMemberInitializer *Member = AllToInit[Idx]; - baseOrMemberInitializers[Idx] = Member; - if (!Member->isBaseInitializer()) - continue; - const Type *BaseType = Member->getBaseClass(); - const RecordType *RT = BaseType->getAs<RecordType>(); - if (!RT) - continue; - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(RT->getDecl()); - - // We don't know if a dependent type will have an implicit destructor. - if (BaseClassDecl->isDependentType()) - continue; - if (BaseClassDecl->hasTrivialDestructor()) - continue; - CXXDestructorDecl *DD = BaseClassDecl->getDestructor(Context); - MarkDeclarationReferenced(Constructor->getLocation(), DD); - } + // Constructors implicitly reference the base and member + // destructors. + MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(), + Constructor->getParent()); } return HadError; @@ -1848,9 +1833,10 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, } void -Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { - // Ignore dependent destructors. - if (Destructor->isDependentContext()) +Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, + CXXRecordDecl *ClassDecl) { + // Ignore dependent contexts. + if (ClassDecl->isDependentContext()) return; // FIXME: all the access-control diagnostics are positioned on the @@ -1858,8 +1844,6 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { // user might reasonably want to know why the destructor is being // emitted, and we currently don't say. - CXXRecordDecl *ClassDecl = Destructor->getParent(); - // Non-static data members. for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { @@ -1881,8 +1865,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { << Field->getDeclName() << FieldType); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; @@ -1910,8 +1893,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { << Base->getType() << Base->getSourceRange()); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } // Virtual bases. @@ -1935,8 +1917,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(CXXDestructorDecl *Destructor) { PartialDiagnostic(diag::err_access_dtor_vbase) << VBase->getType()); - MarkDeclarationReferenced(Destructor->getLocation(), - const_cast<CXXDestructorDecl*>(Dtor)); + MarkDeclarationReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor)); } } @@ -3819,7 +3800,8 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, DeclContext *PreviousContext = CurContext; CurContext = Destructor; - MarkBaseAndMemberDestructorsReferenced(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); // FIXME: If CheckDestructor fails, we should emit a note about where the // implicit destructor was needed. @@ -4222,6 +4204,8 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { + DeclAccessPair FoundDecl = DeclAccessPair::make(*Con, (*Con)->getAccess()); + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con); @@ -4238,12 +4222,11 @@ static void AddConstructorInitializationCandidates(Sema &SemaRef, ((Kind.getKind() == InitializationKind::IK_Default) && Constructor->isDefaultConstructor())) { if (ConstructorTmpl) - SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + SemaRef.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - SemaRef.AddOverloadCandidate(Constructor, Constructor->getAccess(), + SemaRef.AddOverloadCandidate(Constructor, FoundDecl, Args, NumArgs, CandidateSet); } } @@ -4553,10 +4536,10 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, if (Conv->getConversionType()->isLValueReferenceType() && (AllowExplicit || !Conv->isExplicit())) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), ActingDC, + AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet); else - AddConversionCandidate(Conv, I.getAccess(), ActingDC, Init, + AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet); } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a39ba2f..fe6f3b9 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -14,7 +14,7 @@ #include "Sema.h" #include "SemaInit.h" #include "Lookup.h" -#include "clang/Analysis/AnalysisContext.h" +#include "AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -1691,7 +1691,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ExprError(); } - if (VD->getType()->isArrayType() && !VD->hasAttr<BlocksAttr>()) { + if (VD->getType()->isArrayType()) { Diag(Loc, diag::err_ref_array_type); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); @@ -1751,7 +1751,10 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; - llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer); + bool Invalid = false; + llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); + if (Invalid) + return ExprError(); CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(), Tok.getLocation(), PP); @@ -1789,7 +1792,10 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { const char *ThisTokBegin = &IntegerBuffer[0]; // Get the spelling of the token, which eliminates trigraphs, etc. - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin); + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + if (Invalid) + return ExprError(); NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, Tok.getLocation(), PP); @@ -4573,7 +4579,11 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, if (lhptee.getLocalCVRQualifiers() != rhptee.getLocalCVRQualifiers()) ConvTy = CompatiblePointerDiscardsQualifiers; - if (!Context.typesAreCompatible(lhptee, rhptee)) + if (!getLangOptions().CPlusPlus) { + if (!Context.typesAreBlockPointerCompatible(lhsType, rhsType)) + return IncompatibleBlockPointer; + } + else if (!Context.typesAreCompatible(lhptee, rhptee)) return IncompatibleBlockPointer; return ConvTy; } @@ -4582,8 +4592,18 @@ Sema::CheckBlockPointerTypesForAssignment(QualType lhsType, /// for assignment compatibility. Sema::AssignConvertType Sema::CheckObjCPointerTypesForAssignment(QualType lhsType, QualType rhsType) { - if (lhsType->isObjCBuiltinType() || rhsType->isObjCBuiltinType()) + if (lhsType->isObjCBuiltinType()) { + // Class is not compatible with ObjC object pointers. + if (lhsType->isObjCClassType() && !rhsType->isObjCBuiltinType()) + return IncompatiblePointer; + return Compatible; + } + if (rhsType->isObjCBuiltinType()) { + // Class is not compatible with ObjC object pointers. + if (rhsType->isObjCClassType() && !lhsType->isObjCBuiltinType()) + return IncompatiblePointer; return Compatible; + } QualType lhptee = lhsType->getAs<ObjCObjectPointerType>()->getPointeeType(); QualType rhptee = @@ -5780,9 +5800,6 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_SubObjCPropertySetting: Diag = diag::error_no_subobject_property_setting; break; - case Expr::MLV_SubObjCPropertyGetterSetting: - Diag = diag::error_no_subobject_property_getter_setting; - break; } SourceRange Assign; @@ -6986,9 +7003,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, return ExprError(); } - AnalysisContext AC(BSI->TheDecl); - CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC); - CheckUnreachable(AC); + // Issue any analysis-based warnings. + sema::AnalysisBasedWarnings W(*this); + W.IssueWarnings(BSI->TheDecl, BlockTy); + Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, BSI->hasBlockDeclRefExprs); PopFunctionOrBlockScope(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e1e5efa..366089f 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -912,6 +912,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, = cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()); LookupQualifiedName(FoundDelete, RD); } + if (FoundDelete.isAmbiguous()) + return true; // FIXME: clean up expressions? if (FoundDelete.empty()) { DeclareGlobalNewDelete(); @@ -919,8 +921,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, } FoundDelete.suppressDiagnostics(); - llvm::SmallVector<NamedDecl *, 4> Matches; - if (NumPlaceArgs > 1) { + + llvm::SmallVector<std::pair<DeclAccessPair,FunctionDecl*>, 2> Matches; + + if (NumPlaceArgs > 0) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the @@ -962,7 +966,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) - Matches.push_back(Fn); + Matches.push_back(std::make_pair(D.getPair(), Fn)); } } else { // C++ [expr.new]p20: @@ -973,7 +977,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) if (isNonPlacementDeallocationFunction(Fn)) - Matches.push_back(*D); + Matches.push_back(std::make_pair(D.getPair(), Fn)); } } @@ -982,8 +986,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // function, that function will be called; otherwise, no // deallocation function will be called. if (Matches.size() == 1) { - // FIXME: Drops access, using-declaration info! - OperatorDelete = cast<FunctionDecl>(Matches[0]->getUnderlyingDecl()); + OperatorDelete = Matches[0].second; // C++0x [expr.new]p20: // If the lookup finds the two-parameter form of a usual @@ -998,6 +1001,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, PlaceArgs[NumPlaceArgs - 1]->getLocEnd()); Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; + } else { + CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), + Matches[0].first); } } @@ -1019,25 +1025,28 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, << Name << Range; } - // FIXME: handle ambiguity + if (R.isAmbiguous()) + return true; + + R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. + NamedDecl *D = (*Alloc)->getUnderlyingDecl(); - if (FunctionTemplateDecl *FnTemplate = - dyn_cast<FunctionTemplateDecl>((*Alloc)->getUnderlyingDecl())) { - AddTemplateOverloadCandidate(FnTemplate, Alloc.getAccess(), + if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { + AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/0, Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); continue; } - FunctionDecl *Fn = cast<FunctionDecl>((*Alloc)->getUnderlyingDecl()); - AddOverloadCandidate(Fn, Alloc.getAccess(), Args, NumArgs, Candidates, + FunctionDecl *Fn = cast<FunctionDecl>(D); + AddOverloadCandidate(Fn, Alloc.getPair(), Args, NumArgs, Candidates, /*SuppressUserConversions=*/false); } @@ -1050,7 +1059,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // The first argument is size_t, and the first parameter must be size_t, // too. This is checked on declaration and can be assumed. (It can't be // asserted on, though, since invalid decls are left in there.) - // Whatch out for variadic allocator function. + // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { if (PerformCopyInitialization(Args[i], @@ -1059,6 +1068,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, return true; } Operator = FnDecl; + CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl); return false; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 98a7eec..f86ae51 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2007,7 +2007,8 @@ void InitializationSequence::AddAddressOverloadResolutionStep( S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); // Access is currently ignored for these. - S.Function = DeclAccessPair::make(Function, AccessSpecifier(0)); + S.Function.Function = Function; + S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none); Steps.push_back(S); } @@ -2028,12 +2029,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, } void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, QualType T) { Step S; S.Kind = SK_UserConversion; S.Type = T; - S.Function = DeclAccessPair::make(Function, Access); + S.Function.Function = Function; + S.Function.FoundDecl = FoundDecl; Steps.push_back(S); } @@ -2071,7 +2073,8 @@ InitializationSequence::AddConstructorInitializationStep( Step S; S.Kind = SK_ConstructorInitialization; S.Type = T; - S.Function = DeclAccessPair::make(Constructor, Access); + S.Function.Function = Constructor; + S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access); Steps.push_back(S); } @@ -2198,25 +2201,26 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = T1RecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(*Con); + FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, &Initializer, 1, CandidateSet); } } @@ -2257,11 +2261,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, if ((AllowExplicit || !Conv->isExplicit()) && (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){ if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Initializer, ToType, CandidateSet); else - S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, ToType, CandidateSet); } } @@ -2284,7 +2288,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, T2 = cv1T1; // Add the user-defined conversion step. - Sequence.AddUserConversionStep(Function, Best->getAccess(), + Sequence.AddUserConversionStep(Function, Best->FoundDecl, T2.getNonReferenceType()); // Determine whether we need to perform derived-to-base or @@ -2574,25 +2578,26 @@ static void TryConstructorInitialization(Sema &S, DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(*Con); + FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && (AllowExplicit || !Constructor->isExplicit())) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, Args, NumArgs, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, Args, NumArgs, CandidateSet); } } @@ -2623,11 +2628,11 @@ static void TryConstructorInitialization(Sema &S, // Add the constructor initialization step. Any cv-qualification conversion is // subsumed by the initialization. if (Kind.getKind() == InitializationKind::IK_Copy) { - Sequence.AddUserConversionStep(Best->Function, Best->getAccess(), DestType); + Sequence.AddUserConversionStep(Best->Function, Best->FoundDecl, DestType); } else { Sequence.AddConstructorInitializationStep( cast<CXXConstructorDecl>(Best->Function), - Best->getAccess(), + Best->FoundDecl.getAccess(), DestType); } } @@ -2744,25 +2749,27 @@ static void TryUserDefinedConversion(Sema &S, DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(*Con); + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>( ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &Initializer, 1, CandidateSet); else - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + S.AddOverloadCandidate(Constructor, FoundDecl, &Initializer, 1, CandidateSet); } } @@ -2799,11 +2806,11 @@ static void TryUserDefinedConversion(Sema &S, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, CandidateSet); else - S.AddConversionCandidate(Conv, I.getAccess(), ActingDC, + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet); } } @@ -2825,13 +2832,13 @@ static void TryUserDefinedConversion(Sema &S, if (isa<CXXConstructorDecl>(Function)) { // Add the user-defined conversion step. Any cv-qualification conversion is // subsumed by the initialization. - Sequence.AddUserConversionStep(Function, Best->getAccess(), DestType); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType); return; } // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getResultType().getNonReferenceType(); - Sequence.AddUserConversionStep(Function, Best->getAccess(), ConvType); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType); // If the conversion following the call to the conversion function is // interesting, add it as a separate step. @@ -3135,8 +3142,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, if (!Constructor || Constructor->isInvalidDecl() || !Constructor->isCopyConstructor()) continue; - - S.AddOverloadCandidate(Constructor, Constructor->getAccess(), + + DeclAccessPair FoundDecl + = DeclAccessPair::make(Constructor, Constructor->getAccess()); + S.AddOverloadCandidate(Constructor, FoundDecl, &CurInitExpr, 1, CandidateSet); } @@ -3170,6 +3179,10 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S, return S.ExprError(); } + S.CheckConstructorAccess(Loc, + cast<CXXConstructorDecl>(Best->Function), + Best->FoundDecl.getAccess()); + CurInit.release(); return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(), cast<CXXConstructorDecl>(Best->Function), @@ -3303,7 +3316,7 @@ InitializationSequence::Perform(Sema &S, // initializer to reflect that choice. // Access control was done in overload resolution. CurInit = S.FixOverloadedFunctionReference(move(CurInit), - cast<FunctionDecl>(Step->Function.getDecl())); + Step->Function.Function); break; case SK_CastDerivedToBaseRValue: @@ -3367,8 +3380,8 @@ InitializationSequence::Perform(Sema &S, // or a conversion function. CastExpr::CastKind CastKind = CastExpr::CK_Unknown; bool IsCopy = false; - FunctionDecl *Fn = cast<FunctionDecl>(Step->Function.getDecl()); - AccessSpecifier FnAccess = Step->Function.getAccess(); + FunctionDecl *Fn = Step->Function.Function; + DeclAccessPair FoundFn = Step->Function.FoundDecl; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3390,7 +3403,8 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return S.ExprError(); - S.CheckConstructorAccess(Kind.getLocation(), Constructor, FnAccess); + S.CheckConstructorAccess(Kind.getLocation(), Constructor, + FoundFn.getAccess()); CastKind = CastExpr::CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); @@ -3402,7 +3416,7 @@ InitializationSequence::Perform(Sema &S, CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, - Conversion, FnAccess); + FoundFn); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because @@ -3469,7 +3483,7 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: { CXXConstructorDecl *Constructor - = cast<CXXConstructorDecl>(Step->Function.getDecl()); + = cast<CXXConstructorDecl>(Step->Function.Function); // Build a call to the selected constructor. ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); @@ -3506,7 +3520,8 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, Step->Function.getAccess()); + S.CheckConstructorAccess(Loc, Constructor, + Step->Function.FoundDecl.getAccess()); bool Elidable = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable(); @@ -3972,7 +3987,8 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { break; case SK_UserConversion: - OS << "user-defined conversion via " << S->Function->getNameAsString(); + OS << "user-defined conversion via " + << S->Function.Function->getNameAsString(); break; case SK_QualificationConversionRValue: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index 2b49df2..18a0938 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -454,7 +454,10 @@ public: /// Always a FunctionDecl. /// For conversion decls, the naming class is the source type. /// For construct decls, the naming class is the target type. - DeclAccessPair Function; + struct { + FunctionDecl *Function; + DeclAccessPair FoundDecl; + } Function; /// \brief When Kind = SK_ConversionSequence, the implicit conversion /// sequence @@ -622,7 +625,7 @@ public: /// \brief Add a new step invoking a conversion function, which is either /// a constructor or a conversion function. void AddUserConversionStep(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, QualType T); /// \brief Add a new step that performs a qualification conversion to the diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 6caeec6..9ae520d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1176,7 +1176,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; - AccessSpecifier SubobjectAccess = AS_private; + AccessSpecifier SubobjectAccess = AS_none; for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 3a0fe0a..41ed6c6 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -137,17 +137,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } - DeclContext *DC = dyn_cast<DeclContext>(CCPrimary); - assert(DC && "ClassDecl is not a DeclContext"); - DeclContext::lookup_result Found = - DC->lookup(PIDecl->getDeclName()); - bool PropertyInPrimaryClass = false; - for (; Found.first != Found.second; ++Found.first) - if (isa<ObjCPropertyDecl>(*Found.first)) { - PropertyInPrimaryClass = true; - break; - } - if (!PropertyInPrimaryClass) { + DeclContext *DC = cast<DeclContext>(CCPrimary); + if (!ObjCPropertyDecl::findPropertyDecl(DC, + PIDecl->getDeclName().getAsIdentifierInfo())) { // Protocol is not in the primary class. Must build one for it. ObjCDeclSpec ProtocolPropertyODS; // FIXME. Assuming that ObjCDeclSpec::ObjCPropertyAttributeKind diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index f73ec9c..410bf9a 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1525,28 +1525,30 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, for (llvm::tie(Con, ConEnd) = ToRecordDecl->lookup(ConstructorName); Con != ConEnd; ++Con) { + NamedDecl *D = *Con; + DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); + // Find the constructor (which may be a template). CXXConstructorDecl *Constructor = 0; FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(*Con); + = dyn_cast<FunctionTemplateDecl>(D); if (ConstructorTmpl) Constructor = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); else - Constructor = cast<CXXConstructorDecl>(*Con); + Constructor = cast<CXXConstructorDecl>(D); if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, - ConstructorTmpl->getAccess(), + AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, /*ExplicitArgs*/ 0, &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). - AddOverloadCandidate(Constructor, Constructor->getAccess(), + AddOverloadCandidate(Constructor, FoundDecl, &From, 1, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -1569,7 +1571,8 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, = FromRecordDecl->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - NamedDecl *D = *I; + DeclAccessPair FoundDecl = I.getPair(); + NamedDecl *D = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); @@ -1583,11 +1586,11 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, I.getAccess(), + AddTemplateConversionCandidate(ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet); else - AddConversionCandidate(Conv, I.getAccess(), ActingContext, + AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType, CandidateSet); } } @@ -2383,7 +2386,7 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// code completion. void Sema::AddOverloadCandidate(FunctionDecl *Function, - AccessSpecifier Access, + DeclAccessPair FoundDecl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, @@ -2404,7 +2407,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // function, e.g., X::f(). We use an empty type for the implied // object argument (C++ [over.call.func]p3), and the acting context // is irrelevant. - AddMethodCandidate(Method, Access, Method->getParent(), + AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(), Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); return; @@ -2434,8 +2437,8 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Function; - Candidate.Access = Access; Candidate.Viable = true; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2500,28 +2503,28 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { - // FIXME: using declarations - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*F)) { + NamedDecl *D = F.getDecl()->getUnderlyingDecl(); + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic()) - AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getAccess(), + AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), cast<CXXMethodDecl>(FD)->getParent(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, F.getPair(), Args, NumArgs, CandidateSet, SuppressUserConversions); } else { - FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*F); + FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(D); if (isa<CXXMethodDecl>(FunTmpl->getTemplatedDecl()) && !cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())->isStatic()) - AddMethodTemplateCandidate(FunTmpl, F.getAccess(), + AddMethodTemplateCandidate(FunTmpl, F.getPair(), cast<CXXRecordDecl>(FunTmpl->getDeclContext()), /*FIXME: explicit args */ 0, Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, SuppressUserConversions); else - AddTemplateOverloadCandidate(FunTmpl, AS_none, + AddTemplateOverloadCandidate(FunTmpl, F.getPair(), /*FIXME: explicit args */ 0, Args, NumArgs, CandidateSet, SuppressUserConversions); @@ -2531,12 +2534,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, /// AddMethodCandidate - Adds a named decl (which is some kind of /// method) as a method candidate to the given overload set. -void Sema::AddMethodCandidate(NamedDecl *Decl, - AccessSpecifier Access, +void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions, bool ForceRValue) { + NamedDecl *Decl = FoundDecl.getDecl(); CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext()); if (isa<UsingShadowDecl>(Decl)) @@ -2545,13 +2548,14 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, if (FunctionTemplateDecl *TD = dyn_cast<FunctionTemplateDecl>(Decl)) { assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && "Expected a member function template"); - AddMethodTemplateCandidate(TD, Access, ActingContext, /*ExplicitArgs*/ 0, + AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, + /*ExplicitArgs*/ 0, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } else { - AddMethodCandidate(cast<CXXMethodDecl>(Decl), Access, ActingContext, + AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2567,7 +2571,7 @@ void Sema::AddMethodCandidate(NamedDecl *Decl, /// a slightly hacky way to implement the overloading rules for elidable copy /// initialization in C++0x (C++0x 12.8p15). void -Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, +Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2587,8 +2591,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Method; - Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; @@ -2666,7 +2670,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, AccessSpecifier Access, /// function template specialization. void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, @@ -2702,7 +2706,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, assert(Specialization && "Missing member function template specialization?"); assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast<CXXMethodDecl>(Specialization), Access, + AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2712,7 +2716,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, /// an appropriate function template specialization. void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, @@ -2737,8 +2741,8 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, Args, NumArgs, Specialization, Info)) { CandidateSet.push_back(OverloadCandidate()); OverloadCandidate &Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = FunctionTemplate->getTemplatedDecl(); - Candidate.Access = Access; Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.IsSurrogate = false; @@ -2753,7 +2757,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate(Specialization, Access, Args, NumArgs, CandidateSet, + AddOverloadCandidate(Specialization, FoundDecl, Args, NumArgs, CandidateSet, SuppressUserConversions, ForceRValue); } @@ -2765,7 +2769,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, /// conversion function produces). void Sema::AddConversionCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet) { @@ -2781,8 +2785,8 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = Conversion; - Candidate.Access = Access; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.FinalConversion.setAsIdentityConversion(); @@ -2869,7 +2873,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, /// [temp.deduct.conv]). void Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingDC, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet) { @@ -2893,7 +2897,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, Access, ActingDC, From, ToType, + AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, CandidateSet); } @@ -2903,7 +2907,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, /// with the given arguments (C++ [over.call.object]p2-4). Proto is /// the type of function that we'll eventually be calling. void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, - AccessSpecifier Access, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, QualType ObjectType, @@ -2917,8 +2921,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = FoundDecl; Candidate.Function = 0; - Candidate.Access = Access; Candidate.Surrogate = Conversion; Candidate.Viable = true; Candidate.IsSurrogate = true; @@ -3066,7 +3070,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, OperEnd = Operators.end(); Oper != OperEnd; ++Oper) - AddMethodCandidate(*Oper, Oper.getAccess(), Args[0]->getType(), + AddMethodCandidate(Oper.getPair(), Args[0]->getType(), Args + 1, NumArgs - 1, CandidateSet, /* SuppressUserConversions = */ false); } @@ -3091,8 +3095,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); + Candidate.FoundDecl = DeclAccessPair::make(0, AS_none); Candidate.Function = 0; - Candidate.Access = AS_none; Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = false; Candidate.BuiltinTypes.ResultTy = ResultTy; @@ -4179,15 +4183,16 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // For each of the ADL candidates we found, add it to the overload // set. for (ADLResult::iterator I = Fns.begin(), E = Fns.end(); I != E; ++I) { + DeclAccessPair FoundDecl = DeclAccessPair::make(*I, AS_none); if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { if (ExplicitTemplateArgs) continue; - AddOverloadCandidate(FD, AS_none, Args, NumArgs, CandidateSet, + AddOverloadCandidate(FD, FoundDecl, Args, NumArgs, CandidateSet, false, false, PartialOverloading); } else AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), - AS_none, ExplicitTemplateArgs, + FoundDecl, ExplicitTemplateArgs, Args, NumArgs, CandidateSet); } } @@ -4951,12 +4956,11 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } } -static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, NamedDecl *D, - AccessSpecifier AS) { +static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { if (isa<UnresolvedLookupExpr>(E)) - return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D, AS); + return S.CheckUnresolvedLookupAccess(cast<UnresolvedLookupExpr>(E), D); - return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D, AS); + return S.CheckUnresolvedMemberAccess(cast<UnresolvedMemberExpr>(E), D); } /// ResolveAddressOfOverloadedFunction - Try to resolve the address of @@ -5013,7 +5017,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. - UnresolvedSet<4> Matches; // contains only FunctionDecls + llvm::SmallVector<std::pair<DeclAccessPair, FunctionDecl*>, 4> Matches; bool FoundNonTemplateFunction = false; for (UnresolvedSetIterator I = OvlExpr->decls_begin(), E = OvlExpr->decls_end(); I != E; ++I) { @@ -5057,8 +5061,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // a candidate? Find a testcase before changing the code. assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - Matches.addDecl(cast<FunctionDecl>(Specialization->getCanonicalDecl()), - I.getAccess()); + Matches.push_back(std::make_pair(I.getPair(), + cast<FunctionDecl>(Specialization->getCanonicalDecl()))); } continue; @@ -5081,8 +5085,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, ResultTy)) { - Matches.addDecl(cast<FunctionDecl>(FunDecl->getCanonicalDecl()), - I.getAccess()); + Matches.push_back(std::make_pair(I.getPair(), + cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; } } @@ -5092,10 +5096,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (Matches.empty()) return 0; else if (Matches.size() == 1) { - FunctionDecl *Result = cast<FunctionDecl>(*Matches.begin()); + FunctionDecl *Result = Matches[0].second; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Result, Matches.begin().getAccess()); + CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); return Result; } @@ -5112,50 +5116,54 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // two-pass algorithm (similar to the one used to identify the // best viable function in an overload set) that identifies the // best function template (if it exists). + + UnresolvedSet<4> MatchesCopy; // TODO: avoid! + for (unsigned I = 0, E = Matches.size(); I != E; ++I) + MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); UnresolvedSetIterator Result = - getMostSpecialized(Matches.begin(), Matches.end(), + getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), TPOC_Other, From->getLocStart(), PDiag(), PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0]->getDeclName(), + << Matches[0].second->getDeclName(), PDiag(diag::note_ovl_candidate) << (unsigned) oc_function_template); - assert(Result != Matches.end() && "no most-specialized template"); + assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); - if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, *Result, Result.getAccess()); + if (Complain) { + DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first; + CheckUnresolvedAccess(*this, OvlExpr, FoundDecl); + } return cast<FunctionDecl>(*Result); } // [...] any function template specializations in the set are // eliminated if the set also contains a non-template function, [...] for (unsigned I = 0, N = Matches.size(); I != N; ) { - if (cast<FunctionDecl>(Matches[I].getDecl())->getPrimaryTemplate() == 0) + if (Matches[I].second->getPrimaryTemplate() == 0) ++I; else { - Matches.erase(I); - --N; + Matches[I] = Matches[--N]; + Matches.set_size(N); } } // [...] After such eliminations, if any, there shall remain exactly one // selected function. if (Matches.size() == 1) { - UnresolvedSetIterator Match = Matches.begin(); - MarkDeclarationReferenced(From->getLocStart(), *Match); + MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, *Match, Match.getAccess()); - return cast<FunctionDecl>(*Match); + CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + return cast<FunctionDecl>(Matches[0].second); } // FIXME: We should probably return the same thing that BestViableFunction // returns (even if we issue the diagnostics here). Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) - << Matches[0]->getDeclName(); - for (UnresolvedSetIterator I = Matches.begin(), - E = Matches.end(); I != E; ++I) - NoteOverloadCandidate(cast<FunctionDecl>(*I)); + << Matches[0].second->getDeclName(); + for (unsigned I = 0, E = Matches.size(); I != E; ++I) + NoteOverloadCandidate(Matches[I].second); return 0; } @@ -5227,25 +5235,26 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, - NamedDecl *Callee, - AccessSpecifier Access, + DeclAccessPair FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { + NamedDecl *Callee = FoundDecl.getDecl(); if (isa<UsingShadowDecl>(Callee)) Callee = cast<UsingShadowDecl>(Callee)->getTargetDecl(); if (FunctionDecl *Func = dyn_cast<FunctionDecl>(Callee)) { assert(!ExplicitTemplateArgs && "Explicit template arguments?"); - S.AddOverloadCandidate(Func, Access, Args, NumArgs, CandidateSet, + S.AddOverloadCandidate(Func, FoundDecl, Args, NumArgs, CandidateSet, false, false, PartialOverloading); return; } if (FunctionTemplateDecl *FuncTemplate = dyn_cast<FunctionTemplateDecl>(Callee)) { - S.AddTemplateOverloadCandidate(FuncTemplate, Access, ExplicitTemplateArgs, + S.AddTemplateOverloadCandidate(FuncTemplate, FoundDecl, + ExplicitTemplateArgs, Args, NumArgs, CandidateSet); return; } @@ -5301,7 +5310,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, for (UnresolvedLookupExpr::decls_iterator I = ULE->decls_begin(), E = ULE->decls_end(); I != E; ++I) - AddOverloadedCallCandidate(*this, *I, I.getAccess(), ExplicitTemplateArgs, + AddOverloadedCallCandidate(*this, I.getPair(), ExplicitTemplateArgs, Args, NumArgs, CandidateSet, PartialOverloading); @@ -5423,7 +5432,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; - CheckUnresolvedLookupAccess(ULE, FDecl, Best->getAccess()); + CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); Fn = FixOverloadedFunctionReference(Fn, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5549,7 +5558,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { - CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl); if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) return ExprError(); @@ -5733,8 +5742,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { // Best->Access is only meaningful for class members. - CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method, - Best->getAccess()); + CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl); OwningExprResult Arg1 = PerformCopyInitialization( @@ -5908,8 +5916,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched an overloaded operator. Build a call to that // operator. - CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl, - Best->getAccess()); + CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl); // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); @@ -6054,12 +6061,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, if (TemplateArgs) continue; - AddMethodCandidate(Method, I.getAccess(), ActingDC, ObjectType, + AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); } else { AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func), - I.getAccess(), ActingDC, TemplateArgs, + I.getPair(), ActingDC, TemplateArgs, ObjectType, Args, NumArgs, CandidateSet, /*SuppressUsedConversions=*/false); @@ -6072,7 +6079,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast<CXXMethodDecl>(Best->Function); - CheckUnresolvedMemberAccess(UnresExpr, Method, Best->getAccess()); + CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); break; case OR_No_Viable_Function: @@ -6176,7 +6183,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(*Oper, Oper.getAccess(), Object->getType(), + AddMethodCandidate(Oper.getPair(), Object->getType(), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -6221,7 +6228,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ConvType = ConvPtrType->getPointeeType(); if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) - AddSurrogateCandidate(Conv, I.getAccess(), ActingContext, Proto, + AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, Object->getType(), Args, NumArgs, CandidateSet); } @@ -6278,7 +6285,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); - CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); // We selected one of the surrogate functions that converts the // object parameter to a function pointer. Perform the conversion @@ -6293,8 +6300,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CommaLocs, RParenLoc).release(); } - CheckMemberOperatorAccess(LParenLoc, Object, 0, - Best->Function, Best->getAccess()); + CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); // We found an overloaded operator(). Build a CXXOperatorCallExpr // that calls this method, using Object for the implicit object @@ -6429,13 +6435,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - NamedDecl *D = *Oper; - CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext()); - if (isa<UsingShadowDecl>(D)) - D = cast<UsingShadowDecl>(D)->getTargetDecl(); - - AddMethodCandidate(cast<CXXMethodDecl>(D), Oper.getAccess(), ActingContext, - Base->getType(), 0, 0, CandidateSet, + AddMethodCandidate(Oper.getPair(), Base->getType(), 0, 0, CandidateSet, /*SuppressUserConversions=*/false); } @@ -6470,6 +6470,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { return ExprError(); } + CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl); + // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method)) diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h index 58e416c..cff4774 100644 --- a/lib/Sema/SemaOverload.h +++ b/lib/Sema/SemaOverload.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -450,6 +451,11 @@ namespace clang { /// function pointer or reference (C++ [over.call.object]). FunctionDecl *Function; + /// FoundDecl - The original declaration that was looked up / + /// invented / otherwise found, together with its access. + /// Might be a UsingShadowDecl or a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + // BuiltinTypes - Provides the return and parameter types of a // built-in overload candidate. Only valid when Function is NULL. struct { @@ -486,14 +492,6 @@ namespace clang { /// Actually an OverloadFailureKind. unsigned char FailureKind; - /// PathAccess - The 'path access' to the given function/conversion. - /// Actually an AccessSpecifier. - unsigned Access; - - AccessSpecifier getAccess() const { - return AccessSpecifier(Access); - } - /// A structure used to record information about a failed /// template argument deduction. struct DeductionFailureInfo { |