summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-03-21 10:50:08 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-03-21 10:50:08 +0000
commit1e255aab650a7fa2047fd953cae65b12215280af (patch)
tree508d4388db78f87d35bf26a0400b4b03bc4c1f13 /lib
parent1033b7c1e32962948b01a25145829f17bc70a8de (diff)
downloadFreeBSD-src-1e255aab650a7fa2047fd953cae65b12215280af.zip
FreeBSD-src-1e255aab650a7fa2047fd953cae65b12215280af.tar.gz
Update clang to r99115.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp264
-rw-r--r--lib/AST/Decl.cpp5
-rw-r--r--lib/AST/DeclObjC.cpp5
-rw-r--r--lib/AST/Expr.cpp15
-rw-r--r--lib/AST/ExprConstant.cpp27
-rw-r--r--lib/AST/TypePrinter.cpp31
-rw-r--r--lib/Basic/SourceLocation.cpp28
-rw-r--r--lib/Basic/SourceManager.cpp76
-rw-r--r--lib/Checker/BasicStore.cpp5
-rw-r--r--lib/Checker/BugReporter.cpp19
-rw-r--r--lib/Checker/BugReporterVisitors.cpp67
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp195
-rw-r--r--lib/Checker/CheckDeadStores.cpp25
-rw-r--r--lib/Checker/FlatStore.cpp4
-rw-r--r--lib/Checker/GRExprEngine.cpp4
-rw-r--r--lib/Checker/GRState.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp22
-rw-r--r--lib/CodeGen/CGBuiltin.cpp76
-rw-r--r--lib/CodeGen/CGCXX.cpp55
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp20
-rw-r--r--lib/CodeGen/CGDecl.cpp15
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp48
-rw-r--r--lib/CodeGen/CGException.cpp34
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp2
-rw-r--r--lib/CodeGen/CGVtable.cpp108
-rw-r--r--lib/CodeGen/CodeGenFunction.h6
-rw-r--r--lib/CodeGen/CodeGenModule.cpp159
-rw-r--r--lib/CodeGen/CodeGenModule.h72
-rw-r--r--lib/CodeGen/Mangle.cpp45
-rw-r--r--lib/CodeGen/Mangle.h33
-rw-r--r--lib/Driver/Arg.cpp9
-rw-r--r--lib/Driver/Compilation.cpp49
-rw-r--r--lib/Driver/Driver.cpp8
-rw-r--r--lib/Driver/OptTable.cpp6
-rw-r--r--lib/Driver/ToolChains.cpp4
-rw-r--r--lib/Driver/ToolChains.h2
-rw-r--r--lib/Driver/Tools.cpp38
-rw-r--r--lib/Frontend/ASTUnit.cpp4
-rw-r--r--lib/Frontend/CacheTokens.cpp16
-rw-r--r--lib/Frontend/CompilerInstance.cpp33
-rw-r--r--lib/Frontend/CompilerInvocation.cpp19
-rw-r--r--lib/Frontend/FrontendActions.cpp24
-rw-r--r--lib/Frontend/PCHReader.cpp286
-rw-r--r--lib/Frontend/PCHWriter.cpp139
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp6
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/Warnings.cpp4
-rw-r--r--lib/Headers/emmintrin.h1
-rw-r--r--lib/Headers/nmmintrin.h35
-rw-r--r--lib/Headers/smmintrin.h112
-rw-r--r--lib/Headers/varargs.h26
-rw-r--r--lib/Headers/xmmintrin.h5
-rw-r--r--lib/Lex/CMakeLists.txt1
-rw-r--r--lib/Lex/Lexer.cpp6
-rw-r--r--lib/Lex/MacroArgs.cpp31
-rw-r--r--lib/Lex/PPDirectives.cpp28
-rw-r--r--lib/Lex/PPLexerChange.cpp6
-rw-r--r--lib/Lex/PPMacroExpansion.cpp8
-rw-r--r--lib/Lex/Pragma.cpp5
-rw-r--r--lib/Lex/PreprocessingRecord.cpp128
-rw-r--r--lib/Lex/Preprocessor.cpp30
-rw-r--r--lib/Lex/TokenLexer.cpp11
-rw-r--r--lib/Parse/AttributeList.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp2
-rw-r--r--lib/Parse/ParseDeclCXX.cpp12
-rw-r--r--lib/Parse/Parser.cpp18
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp369
-rw-r--r--lib/Sema/AnalysisBasedWarnings.h35
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/CXXFieldCollector.h5
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/Sema.h66
-rw-r--r--lib/Sema/SemaAccess.cpp290
-rw-r--r--lib/Sema/SemaChecking.cpp279
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp129
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--lib/Sema/SemaExpr.cpp42
-rw-r--r--lib/Sema/SemaExprCXX.cpp36
-rw-r--r--lib/Sema/SemaInit.cpp96
-rw-r--r--lib/Sema/SemaInit.h7
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaObjCProperty.cpp14
-rw-r--r--lib/Sema/SemaOverload.cpp186
-rw-r--r--lib/Sema/SemaOverload.h14
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 {
OpenPOWER on IntegriCloud